Merge "Get slices libraries closer to a lower minSdk." into pi-preview1-androidx-dev
am: 2f5a0d87a5

Change-Id: I6218413f43a8ebcf5a46c4ce581abe29ff32fb9f
diff --git a/annotations/build.gradle b/annotations/build.gradle
index 03d2e6c..15274fe 100644
--- a/annotations/build.gradle
+++ b/annotations/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/app-toolkit/common/build.gradle b/app-toolkit/common/build.gradle
index db61b3f..81a34ad 100644
--- a/app-toolkit/common/build.gradle
+++ b/app-toolkit/common/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/app-toolkit/core-testing/build.gradle b/app-toolkit/core-testing/build.gradle
index 8e7ccfb..e4c2e17 100644
--- a/app-toolkit/core-testing/build.gradle
+++ b/app-toolkit/core-testing/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/app-toolkit/init.gradle b/app-toolkit/init.gradle
index d3d7754..3c58368 100644
--- a/app-toolkit/init.gradle
+++ b/app-toolkit/init.gradle
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-import android.support.DacOptions
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.DacOptions
+import androidx.build.license.CheckExternalDependencyLicensesTask
+
 apply from: "${ext.supportRootFolder}/buildSrc/init.gradle"
 init.setSdkInLocalPropertiesFile()
 
diff --git a/app-toolkit/runtime/build.gradle b/app-toolkit/runtime/build.gradle
index cd74aae..5c8f2d9 100644
--- a/app-toolkit/runtime/build.gradle
+++ b/app-toolkit/runtime/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.SupportLibraryExtension
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.SupportLibraryExtension
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/asynclayoutinflater/api/0.0.0.txt b/asynclayoutinflater/api/0.0.0.txt
new file mode 100644
index 0000000..83a85be
--- /dev/null
+++ b/asynclayoutinflater/api/0.0.0.txt
@@ -0,0 +1,13 @@
+package android.support.v4.view {
+
+  public final class AsyncLayoutInflater {
+    ctor public AsyncLayoutInflater(android.content.Context);
+    method public void inflate(int, android.view.ViewGroup, android.support.v4.view.AsyncLayoutInflater.OnInflateFinishedListener);
+  }
+
+  public static abstract interface AsyncLayoutInflater.OnInflateFinishedListener {
+    method public abstract void onInflateFinished(android.view.View, int, android.view.ViewGroup);
+  }
+
+}
+
diff --git a/asynclayoutinflater/build.gradle b/asynclayoutinflater/build.gradle
index 597b01d..a83d876 100644
--- a/asynclayoutinflater/build.gradle
+++ b/asynclayoutinflater/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/build.gradle b/build.gradle
index 0307507..c8683d4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import android.support.DacOptions
+
+import androidx.build.DacOptions
 
 def currentJvmVersion = org.gradle.api.JavaVersion.current()
 if (currentJvmVersion.getMajorVersion() != "8") {
diff --git a/buildSrc/init.gradle b/buildSrc/init.gradle
index 38b41e8..4faeac5 100644
--- a/buildSrc/init.gradle
+++ b/buildSrc/init.gradle
@@ -15,9 +15,9 @@
  */
 
 
-import android.support.DiffAndDocs
-import android.support.gmaven.GMavenVersionChecker
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.DiffAndDocs
+import androidx.build.gmaven.GMavenVersionChecker
+import androidx.build.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.internal.coverage.JacocoReportTask
 import com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask
 import org.gradle.api.logging.configuration.ShowStacktrace
diff --git a/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
rename to buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index 72564cc..213a8a8 100644
--- a/buildSrc/src/main/kotlin/android/support/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.checkapi.ApiXmlConversionTask
-import android.support.checkapi.CheckApiTask
-import android.support.checkapi.UpdateApiTask
-import android.support.doclava.DoclavaTask
-import android.support.docs.GenerateDocsTask
-import android.support.jdiff.JDiffTask
+import androidx.build.checkapi.ApiXmlConversionTask
+import androidx.build.checkapi.CheckApiTask
+import androidx.build.checkapi.UpdateApiTask
+import androidx.build.doclava.DoclavaTask
+import androidx.build.docs.GenerateDocsTask
+import androidx.build.jdiff.JDiffTask
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.api.LibraryVariant
 import org.gradle.api.GradleException
@@ -228,7 +228,9 @@
  */
 private fun createOldApiXml(project: Project, doclavaConfig: Configuration) =
         project.tasks.createWithConfig("oldApiXml", ApiXmlConversionTask::class.java) {
-            val toApi = project.processProperty("toApi")?.let { Version.parseOrNull(it) }
+            val toApi = project.processProperty("toApi")?.let {
+                Version.parseOrNull(it)
+            }
             val fromApi = project.processProperty("fromApi")
             classpath = project.files(doclavaConfig.resolve())
             val rootFolder = project.projectDir
diff --git a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
similarity index 96%
rename from buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
rename to buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
index 74f0505..53e6154 100644
--- a/buildSrc/src/main/kotlin/android/support/ErrorProneConfiguration.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/ErrorProneConfiguration.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
 import org.gradle.api.tasks.compile.JavaCompile
@@ -40,6 +40,7 @@
             "-Xep:OperatorPrecedence:ERROR",
             "-Xep:IntLongMath:ERROR",
             "-Xep:MissingFail:ERROR",
+            "-Xep:JavaLangClash:ERROR",
 
             // Nullaway
             "-XepIgnoreUnknownCheckNames", // https://github.com/uber/NullAway/issues/25
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
rename to buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
index 2f64e5d..385c04c 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryGroups.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryGroups.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 /**
  * The list of maven group names of all the libraries in this project.
diff --git a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
rename to buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index 7daa0b7..7d00959 100644
--- a/buildSrc/src/main/kotlin/android/support/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 /**
  * The list of versions codes of all the libraries in this project.
@@ -33,7 +33,7 @@
     /**
      * Version code for Lifecycle extensions (ProcessLifecycleOwner, Fragment support)
      */
-    val LIFECYCLES_EXT = Version("1.1.0")
+    val LIFECYCLES_EXT = Version("1.2.0-alpha1")
 
     /**
      * Version code for Lifecycle LiveData
diff --git a/buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt b/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt
rename to buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
index c8be47a..dc86936 100644
--- a/buildSrc/src/main/kotlin/android/support/MavenUploadHelper.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/MavenUploadHelper.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import com.android.build.gradle.LibraryPlugin
 import org.gradle.api.Project
diff --git a/buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt
rename to buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
index 992171e..5a11175 100644
--- a/buildSrc/src/main/kotlin/android/support/SourceJarTaskHelper.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SourceJarTaskHelper.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import com.android.build.gradle.LibraryExtension
 import com.android.builder.core.BuilderConstants
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
similarity index 96%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
index 85b556a..da8dc88 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.SupportConfig.INSTRUMENTATION_RUNNER
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
+import androidx.build.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.LibraryExtension
 import com.android.build.gradle.internal.dsl.LintOptions
 import com.android.build.gradle.tasks.GenerateBuildConfig
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
similarity index 89%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
index 66dd873..3d3e0aa 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppExtension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.SupportConfig.DEFAULT_MIN_SDK_VERSION
+import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
 import org.gradle.api.Project
 
 /**
diff --git a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
index 1604bbe..1142ea0 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportAndroidTestAppPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidTestAppPlugin.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.SupportConfig.INSTRUMENTATION_RUNNER
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.SupportConfig.INSTRUMENTATION_RUNNER
+import androidx.build.license.CheckExternalDependencyLicensesTask
 import com.android.build.gradle.AppExtension
 import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
diff --git a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt b/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/SupportConfig.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
index 42b298c..1f216f7 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportConfig.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportConfig.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import org.gradle.api.Project
 import org.gradle.api.plugins.ExtraPropertiesExtension
diff --git a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
similarity index 93%
rename from buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
index f3651ab..24546f1 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.license.CheckExternalDependencyLicensesTask
 import net.ltgt.gradle.errorprone.ErrorProneBasePlugin
 import net.ltgt.gradle.errorprone.ErrorProneToolChain
 import org.gradle.api.JavaVersion
diff --git a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
similarity index 90%
rename from buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
index 8651ef8..4103aad 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportKotlinLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportKotlinLibraryPlugin.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -13,9 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support
+package androidx.build
 
-import android.support.license.CheckExternalDependencyLicensesTask
+import androidx.build.license.CheckExternalDependencyLicensesTask
 import org.gradle.api.JavaVersion
 import org.gradle.api.Plugin
 import org.gradle.api.Project
diff --git a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
similarity index 93%
rename from buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
rename to buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
index fb2f3b5..4f69460 100644
--- a/buildSrc/src/main/kotlin/android/support/SupportLibraryExtension.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportLibraryExtension.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2017 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
-import android.support.SupportConfig.DEFAULT_MIN_SDK_VERSION
+import androidx.build.SupportConfig.DEFAULT_MIN_SDK_VERSION
 import groovy.lang.Closure
 import org.gradle.api.Project
 import java.util.ArrayList
diff --git a/buildSrc/src/main/kotlin/android/support/Version.kt b/buildSrc/src/main/kotlin/androidx/build/Version.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/Version.kt
rename to buildSrc/src/main/kotlin/androidx/build/Version.kt
index 6348b0c..75855d5 100644
--- a/buildSrc/src/main/kotlin/android/support/Version.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/Version.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import java.io.File
 import java.util.regex.Matcher
diff --git a/buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt b/buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
index cde11e6..9fbe3ba 100644
--- a/buildSrc/src/main/kotlin/android/support/VersionFileWriterTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/VersionFileWriterTask.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import com.android.build.gradle.LibraryExtension
 import org.gradle.api.DefaultTask
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
index a4733b2..419d66f 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/ApiXmlConversionTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/ApiXmlConversionTask.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.checkapi
+package androidx.build.checkapi
 
 import org.gradle.api.tasks.InputFile
 import org.gradle.api.tasks.JavaExec
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
similarity index 99%
rename from buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
index be9f877..44f7d39 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/CheckApiTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/CheckApiTask.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.checkapi
+package androidx.build.checkapi
 
 import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt b/buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
similarity index 97%
rename from buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
index 16c625a..810d50b 100644
--- a/buildSrc/src/main/kotlin/android/support/checkapi/UpdateApiTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/checkapi/UpdateApiTask.kt
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.support.checkapi
+package androidx.build.checkapi
 
-import android.support.Version
+import androidx.build.Version
 import com.google.common.io.Files
 import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
rename to buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 0844832..4199fae 100644
--- a/buildSrc/src/main/kotlin/android/support/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.dependencies
+package androidx.build.dependencies
 
 const val AUTO_COMMON = "com.google.auto:auto-common:0.6"
 const val ANTLR = "org.antlr:antlr4:4.5.3"
diff --git a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt b/buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
similarity index 99%
rename from buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
index b30611d..3f0a6f5 100644
--- a/buildSrc/src/main/kotlin/android/support/doclava/DoclavaTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/doclava/DoclavaTask.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.doclava
+package androidx.build.doclava
 
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFiles
diff --git a/buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt b/buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
similarity index 94%
rename from buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
index e889a54..4bbb830 100644
--- a/buildSrc/src/main/kotlin/android/support/docs/GenerateDocsTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/docs/GenerateDocsTask.kt
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.support.docs
+package androidx.build.docs
 
-import android.support.Version
-import android.support.doclava.DoclavaTask
+import androidx.build.Version
+import androidx.build.doclava.DoclavaTask
 import java.io.File
 
 open class GenerateDocsTask : DoclavaTask() {
diff --git a/buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt b/buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt
rename to buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
index 7fc4836..3c1b8d0 100644
--- a/buildSrc/src/main/kotlin/android/support/gmaven/GMavenVersionChecker.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/gmaven/GMavenVersionChecker.kt
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.support.gmaven
+package androidx.build.gmaven
 
-import android.support.Version
+import androidx.build.Version
 import groovy.util.XmlSlurper
 import groovy.util.slurpersupport.Node
 import groovy.util.slurpersupport.NodeChild
diff --git a/buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
index a6abc57..dfeb322 100644
--- a/buildSrc/src/main/kotlin/android/support/jdiff/JDiffTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/jdiff/JDiffTask.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.jdiff
+package androidx.build.jdiff
 
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFile
diff --git a/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt b/buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
similarity index 98%
rename from buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
rename to buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
index 771f222..2dc4e01 100644
--- a/buildSrc/src/main/kotlin/android/support/license/CheckExternalDependencyLicensesTask.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/license/CheckExternalDependencyLicensesTask.kt
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.license
+package androidx.build.license
 
 import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
index 222602b..25c8e4e 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportAndroidLibraryPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportAndroidLibraryPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
index 4c794f1..8bb9716 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportAndroidTestAppPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportAndroidTestAppPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportAndroidTestAppPlugin
\ 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
index 89755b7..acc6819 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportJavaLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportJavaLibraryPlugin
\ No newline at end of file
+implementation-class=androidx.build.SupportJavaLibraryPlugin
\ No newline at end of file
diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
index d93c20a..f50d743 100644
--- a/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
+++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/SupportKotlinLibraryPlugin.properties
@@ -1 +1 @@
-implementation-class=android.support.SupportKotlinLibraryPlugin
+implementation-class=androidx.build.SupportKotlinLibraryPlugin
diff --git a/buildSrc/src/test/kotlin/android/support/VersionTest.kt b/buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
similarity index 95%
rename from buildSrc/src/test/kotlin/android/support/VersionTest.kt
rename to buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
index 339acab..fc803d9 100644
--- a/buildSrc/src/test/kotlin/android/support/VersionTest.kt
+++ b/buildSrc/src/test/kotlin/androidx/build/VersionTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright 2018 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support
+package androidx.build
 
 import org.junit.Assert.assertEquals
 import org.junit.Test
diff --git a/car/build.gradle b/car/build.gradle
index 0e96019..8660f6f 100644
--- a/car/build.gradle
+++ b/car/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/collections/build.gradle b/collections/build.gradle
index 3145c4a..a5ebc43 100644
--- a/collections/build.gradle
+++ b/collections/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/compat/build.gradle b/compat/build.gradle
index f52c5ff..3cb9b06 100644
--- a/compat/build.gradle
+++ b/compat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -15,7 +15,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'support-compat'
     }
 }
diff --git a/compat/res/values-port/bools.xml b/compat/res/values-port/bools.xml
deleted file mode 100644
index 25053be..0000000
--- a/compat/res/values-port/bools.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 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.
--->
-
-<resources>
-
-    <bool name="abc_action_bar_embed_tabs">false</bool>
-
-</resources>
diff --git a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
index c8bc229..9375aad 100644
--- a/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
+++ b/compat/src/androidTest/java/android/support/v4/widget/ContentLoadingProgressBarTest.java
@@ -22,7 +22,6 @@
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.view.View;
 
 import org.junit.Before;
@@ -30,6 +29,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.PollingCheck;
+
 /**
  * Tests for {@link ContentLoadingProgressBar}
  */
diff --git a/content/build.gradle b/content/build.gradle
index 990f308..ea39651 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/coordinatorlayout/api/0.0.0.txt b/coordinatorlayout/api/0.0.0.txt
new file mode 100644
index 0000000..a5a44a2
--- /dev/null
+++ b/coordinatorlayout/api/0.0.0.txt
@@ -0,0 +1,97 @@
+package android.support.design.widget {
+
+  public class CoordinatorLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingParent2 {
+    ctor public CoordinatorLayout(android.content.Context);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet);
+    ctor public CoordinatorLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void dispatchDependentViewsChanged(android.view.View);
+    method public boolean doViewsOverlap(android.view.View, android.view.View);
+    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateDefaultLayoutParams();
+    method public android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.util.AttributeSet);
+    method protected android.support.design.widget.CoordinatorLayout.LayoutParams generateLayoutParams(android.view.ViewGroup.LayoutParams);
+    method public java.util.List<android.view.View> getDependencies(android.view.View);
+    method public java.util.List<android.view.View> getDependents(android.view.View);
+    method public android.graphics.drawable.Drawable getStatusBarBackground();
+    method public boolean isPointInChildBounds(android.view.View, int, int);
+    method public void onAttachedToWindow();
+    method public void onDetachedFromWindow();
+    method public void onDraw(android.graphics.Canvas);
+    method public void onLayoutChild(android.view.View, int);
+    method public void onMeasureChild(android.view.View, int, int, int, int);
+    method public void onNestedPreScroll(android.view.View, int, int, int[], int);
+    method public void onNestedScroll(android.view.View, int, int, int, int, int);
+    method public void onNestedScrollAccepted(android.view.View, android.view.View, int, int);
+    method public boolean onStartNestedScroll(android.view.View, android.view.View, int, int);
+    method public void onStopNestedScroll(android.view.View, int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackgroundColor(int);
+    method public void setStatusBarBackgroundResource(int);
+  }
+
+  public static abstract interface CoordinatorLayout.AttachedBehavior {
+    method public abstract android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+  }
+
+  public static abstract class CoordinatorLayout.Behavior<V extends android.view.View> {
+    ctor public CoordinatorLayout.Behavior();
+    ctor public CoordinatorLayout.Behavior(android.content.Context, android.util.AttributeSet);
+    method public boolean blocksInteractionBelow(android.support.design.widget.CoordinatorLayout, V);
+    method public boolean getInsetDodgeRect(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect);
+    method public int getScrimColor(android.support.design.widget.CoordinatorLayout, V);
+    method public float getScrimOpacity(android.support.design.widget.CoordinatorLayout, V);
+    method public static java.lang.Object getTag(android.view.View);
+    method public boolean layoutDependsOn(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public android.support.v4.view.WindowInsetsCompat onApplyWindowInsets(android.support.design.widget.CoordinatorLayout, V, android.support.v4.view.WindowInsetsCompat);
+    method public void onAttachedToLayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    method public boolean onDependentViewChanged(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDependentViewRemoved(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onDetachedFromLayoutParams();
+    method public boolean onInterceptTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public boolean onLayoutChild(android.support.design.widget.CoordinatorLayout, V, int);
+    method public boolean onMeasureChild(android.support.design.widget.CoordinatorLayout, V, int, int, int, int);
+    method public boolean onNestedFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float, boolean);
+    method public boolean onNestedPreFling(android.support.design.widget.CoordinatorLayout, V, android.view.View, float, float);
+    method public deprecated void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[]);
+    method public void onNestedPreScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int[], int);
+    method public deprecated void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int);
+    method public void onNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int, int, int, int, int);
+    method public deprecated void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public void onNestedScrollAccepted(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+    method public boolean onRequestChildRectangleOnScreen(android.support.design.widget.CoordinatorLayout, V, android.graphics.Rect, boolean);
+    method public void onRestoreInstanceState(android.support.design.widget.CoordinatorLayout, V, android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState(android.support.design.widget.CoordinatorLayout, V);
+    method public deprecated boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int);
+    method public boolean onStartNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, android.view.View, int, int);
+    method public deprecated void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View);
+    method public void onStopNestedScroll(android.support.design.widget.CoordinatorLayout, V, android.view.View, int);
+    method public boolean onTouchEvent(android.support.design.widget.CoordinatorLayout, V, android.view.MotionEvent);
+    method public static void setTag(android.view.View, java.lang.Object);
+  }
+
+  public static abstract deprecated class CoordinatorLayout.DefaultBehavior implements java.lang.annotation.Annotation {
+  }
+
+  public static class CoordinatorLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public CoordinatorLayout.LayoutParams(int, int);
+    ctor public CoordinatorLayout.LayoutParams(android.support.design.widget.CoordinatorLayout.LayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public CoordinatorLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    method public int getAnchorId();
+    method public android.support.design.widget.CoordinatorLayout.Behavior getBehavior();
+    method public void setAnchorId(int);
+    method public void setBehavior(android.support.design.widget.CoordinatorLayout.Behavior);
+    field public int anchorGravity;
+    field public int dodgeInsetEdges;
+    field public int gravity;
+    field public int insetEdge;
+    field public int keyline;
+  }
+
+  protected static class CoordinatorLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public CoordinatorLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public CoordinatorLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.design.widget.CoordinatorLayout.SavedState> CREATOR;
+  }
+
+}
+
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
index c6ce55b..0f9e7ab 100644
--- a/coordinatorlayout/build.gradle
+++ b/coordinatorlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -15,7 +15,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'support-core-ui'
     }
 }
diff --git a/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
index 0dd56e4..4272f56 100755
--- a/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
+++ b/coordinatorlayout/src/androidTest/java/android/support/design/widget/BaseTestActivity.java
@@ -18,9 +18,10 @@
 
 import android.os.Bundle;
 import android.support.annotation.LayoutRes;
-import android.support.testutils.RecreatedActivity;
 import android.view.WindowManager;
 
+import androidx.testutils.RecreatedActivity;
+
 abstract class BaseTestActivity extends RecreatedActivity {
 
     private boolean mDestroyed;
diff --git a/core-ui/build.gradle b/core-ui/build.gradle
index 12f5525..9fd62d1 100644
--- a/core-ui/build.gradle
+++ b/core-ui/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -24,7 +24,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'support-core-ui'
     }
 
diff --git a/core-utils/build.gradle b/core-utils/build.gradle
index ffc0ab8..9f66444 100644
--- a/core-utils/build.gradle
+++ b/core-utils/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/cursoradapter/api/0.0.0.txt b/cursoradapter/api/0.0.0.txt
new file mode 100644
index 0000000..07f7287
--- /dev/null
+++ b/cursoradapter/api/0.0.0.txt
@@ -0,0 +1,61 @@
+package android.support.v4.widget {
+
+  public abstract class CursorAdapter extends android.widget.BaseAdapter implements android.widget.Filterable {
+    ctor public deprecated CursorAdapter(android.content.Context, android.database.Cursor);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, boolean);
+    ctor public CursorAdapter(android.content.Context, android.database.Cursor, int);
+    method public abstract void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursor(android.database.Cursor);
+    method public java.lang.CharSequence convertToString(android.database.Cursor);
+    method public int getCount();
+    method public android.database.Cursor getCursor();
+    method public android.widget.Filter getFilter();
+    method public android.widget.FilterQueryProvider getFilterQueryProvider();
+    method public java.lang.Object getItem(int);
+    method public long getItemId(int);
+    method public android.view.View getView(int, android.view.View, android.view.ViewGroup);
+    method protected deprecated void init(android.content.Context, android.database.Cursor, boolean);
+    method public android.view.View newDropDownView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public abstract android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method protected void onContentChanged();
+    method public android.database.Cursor runQueryOnBackgroundThread(java.lang.CharSequence);
+    method public void setFilterQueryProvider(android.widget.FilterQueryProvider);
+    method public android.database.Cursor swapCursor(android.database.Cursor);
+    field public static final deprecated int FLAG_AUTO_REQUERY = 1; // 0x1
+    field public static final int FLAG_REGISTER_CONTENT_OBSERVER = 2; // 0x2
+  }
+
+  public abstract class ResourceCursorAdapter extends android.support.v4.widget.CursorAdapter {
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor);
+    ctor public deprecated ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, boolean);
+    ctor public ResourceCursorAdapter(android.content.Context, int, android.database.Cursor, int);
+    method public android.view.View newView(android.content.Context, android.database.Cursor, android.view.ViewGroup);
+    method public void setDropDownViewResource(int);
+    method public void setViewResource(int);
+  }
+
+  public class SimpleCursorAdapter extends android.support.v4.widget.ResourceCursorAdapter {
+    ctor public deprecated SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[]);
+    ctor public SimpleCursorAdapter(android.content.Context, int, android.database.Cursor, java.lang.String[], int[], int);
+    method public void bindView(android.view.View, android.content.Context, android.database.Cursor);
+    method public void changeCursorAndColumns(android.database.Cursor, java.lang.String[], int[]);
+    method public android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter getCursorToStringConverter();
+    method public int getStringConversionColumn();
+    method public android.support.v4.widget.SimpleCursorAdapter.ViewBinder getViewBinder();
+    method public void setCursorToStringConverter(android.support.v4.widget.SimpleCursorAdapter.CursorToStringConverter);
+    method public void setStringConversionColumn(int);
+    method public void setViewBinder(android.support.v4.widget.SimpleCursorAdapter.ViewBinder);
+    method public void setViewImage(android.widget.ImageView, java.lang.String);
+    method public void setViewText(android.widget.TextView, java.lang.String);
+  }
+
+  public static abstract interface SimpleCursorAdapter.CursorToStringConverter {
+    method public abstract java.lang.CharSequence convertToString(android.database.Cursor);
+  }
+
+  public static abstract interface SimpleCursorAdapter.ViewBinder {
+    method public abstract boolean setViewValue(android.view.View, android.database.Cursor, int);
+  }
+
+}
+
diff --git a/cursoradapter/build.gradle b/cursoradapter/build.gradle
index d08a8bc..2e379a1 100644
--- a/cursoradapter/build.gradle
+++ b/cursoradapter/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/customtabs/build.gradle b/customtabs/build.gradle
index ced95b8..8df42d0 100644
--- a/customtabs/build.gradle
+++ b/customtabs/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -14,7 +14,7 @@
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
-    androidTestImplementation(project(":support-testutils"))
+    androidTestImplementation(project(":internal-testutils"))
 }
 
 supportLibrary {
diff --git a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
index 07d21a8..381afae 100644
--- a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
+++ b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageServiceConnectionTest.java
@@ -26,7 +26,6 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.rule.ServiceTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -35,6 +34,8 @@
 
 import java.util.concurrent.TimeoutException;
 
+import androidx.testutils.PollingCheck;
+
 /**
  * Tests for {@link PostMessageServiceConnection} with no {@link CustomTabsService} component.
  */
diff --git a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
index 7e342b4..6e96b45 100644
--- a/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
+++ b/customtabs/src/androidTest/java/android/support/customtabs/PostMessageTest.java
@@ -29,7 +29,6 @@
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.rule.ServiceTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -38,6 +37,8 @@
 
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import androidx.testutils.PollingCheck;
+
 
 /**
  * Tests for a complete loop between a browser side {@link CustomTabsService}
diff --git a/customview/api/0.0.0.txt b/customview/api/0.0.0.txt
new file mode 100644
index 0000000..1e8a9c1
--- /dev/null
+++ b/customview/api/0.0.0.txt
@@ -0,0 +1,105 @@
+package android.support.v4.view {
+
+  public abstract class AbsSavedState implements android.os.Parcelable {
+    ctor protected AbsSavedState(android.os.Parcelable);
+    ctor protected AbsSavedState(android.os.Parcel);
+    ctor protected AbsSavedState(android.os.Parcel, java.lang.ClassLoader);
+    method public int describeContents();
+    method public final android.os.Parcelable getSuperState();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.AbsSavedState> CREATOR;
+    field public static final android.support.v4.view.AbsSavedState EMPTY_STATE;
+  }
+
+}
+
+package android.support.v4.widget {
+
+  public abstract class ExploreByTouchHelper extends android.support.v4.view.AccessibilityDelegateCompat {
+    ctor public ExploreByTouchHelper(android.view.View);
+    method public final boolean clearKeyboardFocusForVirtualView(int);
+    method public final boolean dispatchHoverEvent(android.view.MotionEvent);
+    method public final boolean dispatchKeyEvent(android.view.KeyEvent);
+    method public final int getAccessibilityFocusedVirtualViewId();
+    method public deprecated int getFocusedVirtualView();
+    method public final int getKeyboardFocusedVirtualViewId();
+    method protected abstract int getVirtualViewAt(float, float);
+    method protected abstract void getVisibleVirtualViews(java.util.List<java.lang.Integer>);
+    method public final void invalidateRoot();
+    method public final void invalidateVirtualView(int);
+    method public final void invalidateVirtualView(int, int);
+    method public final void onFocusChanged(boolean, int, android.graphics.Rect);
+    method protected abstract boolean onPerformActionForVirtualView(int, int, android.os.Bundle);
+    method protected void onPopulateEventForHost(android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateEventForVirtualView(int, android.view.accessibility.AccessibilityEvent);
+    method protected void onPopulateNodeForHost(android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected abstract void onPopulateNodeForVirtualView(int, android.support.v4.view.accessibility.AccessibilityNodeInfoCompat);
+    method protected void onVirtualViewKeyboardFocusChanged(int, boolean);
+    method public final boolean requestKeyboardFocusForVirtualView(int);
+    method public final boolean sendEventForVirtualView(int, int);
+    field public static final int HOST_ID = -1; // 0xffffffff
+    field public static final int INVALID_ID = -2147483648; // 0x80000000
+  }
+
+  public class ViewDragHelper {
+    method public void abort();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int, int);
+    method public void cancel();
+    method public void captureChildView(android.view.View, int);
+    method public boolean checkTouchSlop(int);
+    method public boolean checkTouchSlop(int, int);
+    method public boolean continueSettling(boolean);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, android.support.v4.widget.ViewDragHelper.Callback);
+    method public static android.support.v4.widget.ViewDragHelper create(android.view.ViewGroup, float, android.support.v4.widget.ViewDragHelper.Callback);
+    method public android.view.View findTopChildUnder(int, int);
+    method public void flingCapturedView(int, int, int, int);
+    method public int getActivePointerId();
+    method public android.view.View getCapturedView();
+    method public int getEdgeSize();
+    method public float getMinVelocity();
+    method public int getTouchSlop();
+    method public int getViewDragState();
+    method public boolean isCapturedViewUnder(int, int);
+    method public boolean isEdgeTouched(int);
+    method public boolean isEdgeTouched(int, int);
+    method public boolean isPointerDown(int);
+    method public boolean isViewUnder(android.view.View, int, int);
+    method public void processTouchEvent(android.view.MotionEvent);
+    method public void setEdgeTrackingEnabled(int);
+    method public void setMinVelocity(float);
+    method public boolean settleCapturedViewAt(int, int);
+    method public boolean shouldInterceptTouchEvent(android.view.MotionEvent);
+    method public boolean smoothSlideViewTo(android.view.View, int, int);
+    field public static final int DIRECTION_ALL = 3; // 0x3
+    field public static final int DIRECTION_HORIZONTAL = 1; // 0x1
+    field public static final int DIRECTION_VERTICAL = 2; // 0x2
+    field public static final int EDGE_ALL = 15; // 0xf
+    field public static final int EDGE_BOTTOM = 8; // 0x8
+    field public static final int EDGE_LEFT = 1; // 0x1
+    field public static final int EDGE_RIGHT = 2; // 0x2
+    field public static final int EDGE_TOP = 4; // 0x4
+    field public static final int INVALID_POINTER = -1; // 0xffffffff
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewDragHelper.Callback {
+    ctor public ViewDragHelper.Callback();
+    method public int clampViewPositionHorizontal(android.view.View, int, int);
+    method public int clampViewPositionVertical(android.view.View, int, int);
+    method public int getOrderedChildIndex(int);
+    method public int getViewHorizontalDragRange(android.view.View);
+    method public int getViewVerticalDragRange(android.view.View);
+    method public void onEdgeDragStarted(int, int);
+    method public boolean onEdgeLock(int);
+    method public void onEdgeTouched(int, int);
+    method public void onViewCaptured(android.view.View, int);
+    method public void onViewDragStateChanged(int);
+    method public void onViewPositionChanged(android.view.View, int, int, int, int);
+    method public void onViewReleased(android.view.View, float, float);
+    method public abstract boolean tryCaptureView(android.view.View, int);
+  }
+
+}
+
diff --git a/customview/build.gradle b/customview/build.gradle
index 108ec71..421a2e0 100644
--- a/customview/build.gradle
+++ b/customview/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/documentfile/api/0.0.0.txt b/documentfile/api/0.0.0.txt
new file mode 100644
index 0000000..6d7790b
--- /dev/null
+++ b/documentfile/api/0.0.0.txt
@@ -0,0 +1,29 @@
+package android.support.v4.provider {
+
+  public abstract class DocumentFile {
+    method public abstract boolean canRead();
+    method public abstract boolean canWrite();
+    method public abstract android.support.v4.provider.DocumentFile createDirectory(java.lang.String);
+    method public abstract android.support.v4.provider.DocumentFile createFile(java.lang.String, java.lang.String);
+    method public abstract boolean delete();
+    method public abstract boolean exists();
+    method public android.support.v4.provider.DocumentFile findFile(java.lang.String);
+    method public static android.support.v4.provider.DocumentFile fromFile(java.io.File);
+    method public static android.support.v4.provider.DocumentFile fromSingleUri(android.content.Context, android.net.Uri);
+    method public static android.support.v4.provider.DocumentFile fromTreeUri(android.content.Context, android.net.Uri);
+    method public abstract java.lang.String getName();
+    method public android.support.v4.provider.DocumentFile getParentFile();
+    method public abstract java.lang.String getType();
+    method public abstract android.net.Uri getUri();
+    method public abstract boolean isDirectory();
+    method public static boolean isDocumentUri(android.content.Context, android.net.Uri);
+    method public abstract boolean isFile();
+    method public abstract boolean isVirtual();
+    method public abstract long lastModified();
+    method public abstract long length();
+    method public abstract android.support.v4.provider.DocumentFile[] listFiles();
+    method public abstract boolean renameTo(java.lang.String);
+  }
+
+}
+
diff --git a/documentfile/build.gradle b/documentfile/build.gradle
index 2f59518..460332f 100644
--- a/documentfile/build.gradle
+++ b/documentfile/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/drawerlayout/api/0.0.0.txt b/drawerlayout/api/0.0.0.txt
new file mode 100644
index 0000000..c1a0b4c
--- /dev/null
+++ b/drawerlayout/api/0.0.0.txt
@@ -0,0 +1,81 @@
+package android.support.v4.widget {
+
+  public class DrawerLayout extends android.view.ViewGroup {
+    ctor public DrawerLayout(android.content.Context);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout(android.content.Context, android.util.AttributeSet, int);
+    method public void addDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void closeDrawer(android.view.View);
+    method public void closeDrawer(android.view.View, boolean);
+    method public void closeDrawer(int);
+    method public void closeDrawer(int, boolean);
+    method public void closeDrawers();
+    method public float getDrawerElevation();
+    method public int getDrawerLockMode(int);
+    method public int getDrawerLockMode(android.view.View);
+    method public java.lang.CharSequence getDrawerTitle(int);
+    method public android.graphics.drawable.Drawable getStatusBarBackgroundDrawable();
+    method public boolean isDrawerOpen(android.view.View);
+    method public boolean isDrawerOpen(int);
+    method public boolean isDrawerVisible(android.view.View);
+    method public boolean isDrawerVisible(int);
+    method public void onDraw(android.graphics.Canvas);
+    method public void openDrawer(android.view.View);
+    method public void openDrawer(android.view.View, boolean);
+    method public void openDrawer(int);
+    method public void openDrawer(int, boolean);
+    method public void removeDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerElevation(float);
+    method public deprecated void setDrawerListener(android.support.v4.widget.DrawerLayout.DrawerListener);
+    method public void setDrawerLockMode(int);
+    method public void setDrawerLockMode(int, int);
+    method public void setDrawerLockMode(int, android.view.View);
+    method public void setDrawerShadow(android.graphics.drawable.Drawable, int);
+    method public void setDrawerShadow(int, int);
+    method public void setDrawerTitle(int, java.lang.CharSequence);
+    method public void setScrimColor(int);
+    method public void setStatusBarBackground(android.graphics.drawable.Drawable);
+    method public void setStatusBarBackground(int);
+    method public void setStatusBarBackgroundColor(int);
+    field public static final int LOCK_MODE_LOCKED_CLOSED = 1; // 0x1
+    field public static final int LOCK_MODE_LOCKED_OPEN = 2; // 0x2
+    field public static final int LOCK_MODE_UNDEFINED = 3; // 0x3
+    field public static final int LOCK_MODE_UNLOCKED = 0; // 0x0
+    field public static final int STATE_DRAGGING = 1; // 0x1
+    field public static final int STATE_IDLE = 0; // 0x0
+    field public static final int STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract interface DrawerLayout.DrawerListener {
+    method public abstract void onDrawerClosed(android.view.View);
+    method public abstract void onDrawerOpened(android.view.View);
+    method public abstract void onDrawerSlide(android.view.View, float);
+    method public abstract void onDrawerStateChanged(int);
+  }
+
+  public static class DrawerLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public DrawerLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public DrawerLayout.LayoutParams(int, int);
+    ctor public DrawerLayout.LayoutParams(int, int, int);
+    ctor public DrawerLayout.LayoutParams(android.support.v4.widget.DrawerLayout.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public DrawerLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    field public int gravity;
+  }
+
+  protected static class DrawerLayout.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public DrawerLayout.SavedState(android.os.Parcel, java.lang.ClassLoader);
+    ctor public DrawerLayout.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.widget.DrawerLayout.SavedState> CREATOR;
+  }
+
+  public static abstract class DrawerLayout.SimpleDrawerListener implements android.support.v4.widget.DrawerLayout.DrawerListener {
+    ctor public DrawerLayout.SimpleDrawerListener();
+    method public void onDrawerClosed(android.view.View);
+    method public void onDrawerOpened(android.view.View);
+    method public void onDrawerSlide(android.view.View, float);
+    method public void onDrawerStateChanged(int);
+  }
+
+}
+
diff --git a/drawerlayout/build.gradle b/drawerlayout/build.gradle
index 1d1476b..b4cc482 100644
--- a/drawerlayout/build.gradle
+++ b/drawerlayout/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 451e874..04d3c33 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/emoji/appcompat/build.gradle b/emoji/appcompat/build.gradle
index 8a75f66..5c00c8e 100644
--- a/emoji/appcompat/build.gradle
+++ b/emoji/appcompat/build.gradle
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/emoji/bundled/build.gradle b/emoji/bundled/build.gradle
index 7c3a76a..181f893 100644
--- a/emoji/bundled/build.gradle
+++ b/emoji/bundled/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 449ebb1..4936635 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 import java.util.zip.ZipException
 import java.util.zip.ZipFile
 
@@ -28,7 +28,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils')
+    androidTestImplementation project(':internal-testutils')
 }
 
 android {
diff --git a/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
index 1c647ce..aafa0d1 100644
--- a/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
+++ b/emoji/core/src/androidTest/java/android/support/text/emoji/EmojiKeyboardTest.java
@@ -30,7 +30,6 @@
 import android.support.test.filters.Suppress;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.support.text.emoji.test.R;
 import android.support.text.emoji.util.KeyboardUtil;
 import android.support.text.emoji.util.TestString;
@@ -44,6 +43,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.PollingCheck;
+
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 @Suppress
diff --git a/exifinterface/build.gradle b/exifinterface/build.gradle
index e81d422..1914d9c 100644
--- a/exifinterface/build.gradle
+++ b/exifinterface/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/fragment/build.gradle b/fragment/build.gradle
index 4a3c1d1..9e7f478 100644
--- a/fragment/build.gradle
+++ b/fragment/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'support-fragment'
     }
 }
diff --git a/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java b/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
index dc62c01..c3bea05 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/FragmentManagerNonConfigTest.java
@@ -21,13 +21,14 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
 import android.support.v4.app.test.NonConfigOnStopActivity;
 
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.FragmentActivityUtils;
+
 @MediumTest
 @RunWith(AndroidJUnit4.class)
 public class FragmentManagerNonConfigTest {
diff --git a/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java b/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
index bf8726f..bb8d1db 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/HangingFragmentTest.java
@@ -19,7 +19,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
 import android.support.v4.app.test.HangingFragmentActivity;
 
 import org.junit.Assert;
@@ -27,6 +26,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.FragmentActivityUtils;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
diff --git a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
index 1d89e27..4a1837f 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/LoaderTest.java
@@ -32,8 +32,6 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.FragmentActivityUtils;
-import android.support.testutils.RecreatedActivity;
 import android.support.v4.app.test.LoaderActivity;
 import android.support.v4.content.AsyncTaskLoader;
 import android.support.v4.content.Loader;
@@ -46,6 +44,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.testutils.FragmentActivityUtils;
+import androidx.testutils.RecreatedActivity;
+
 @RunWith(AndroidJUnit4.class)
 @MediumTest
 public class LoaderTest {
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
index 80b9aa5..bdf29cb 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/HangingFragmentActivity.java
@@ -19,7 +19,8 @@
 import android.os.Bundle;
 import android.support.annotation.Nullable;
 import android.support.fragment.test.R;
-import android.support.testutils.RecreatedActivity;
+
+import androidx.testutils.RecreatedActivity;
 
 public class HangingFragmentActivity extends RecreatedActivity {
 
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
index f6ddf9c..1c88dbe 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/LoaderActivity.java
@@ -21,7 +21,6 @@
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.fragment.test.R;
-import android.support.testutils.RecreatedActivity;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.AsyncTaskLoader;
@@ -31,6 +30,8 @@
 import android.view.ViewGroup;
 import android.widget.TextView;
 
+import androidx.testutils.RecreatedActivity;
+
 public class LoaderActivity extends RecreatedActivity
         implements LoaderManager.LoaderCallbacks<String> {
     private static final int TEXT_LOADER_ID = 14;
diff --git a/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java b/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
index 9d71388..f52ddbd 100644
--- a/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
+++ b/fragment/src/androidTest/java/android/support/v4/app/test/NonConfigOnStopActivity.java
@@ -16,9 +16,10 @@
 
 package android.support.v4.app.test;
 
-import android.support.testutils.RecreatedActivity;
 import android.support.v4.app.Fragment;
 
+import androidx.testutils.RecreatedActivity;
+
 public class NonConfigOnStopActivity extends RecreatedActivity {
     @Override
     protected void onStop() {
diff --git a/fragment/src/main/java/android/support/v4/app/DialogFragment.java b/fragment/src/main/java/android/support/v4/app/DialogFragment.java
index b6bbb48..b585863 100644
--- a/fragment/src/main/java/android/support/v4/app/DialogFragment.java
+++ b/fragment/src/main/java/android/support/v4/app/DialogFragment.java
@@ -320,7 +320,8 @@
     }
 
     @Override
-    public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) {
+    @NonNull
+    public LayoutInflater onGetLayoutInflater(@Nullable Bundle savedInstanceState) {
         if (!mShowsDialog) {
             return super.onGetLayoutInflater(savedInstanceState);
         }
@@ -375,7 +376,7 @@
      * @return Return a new Dialog instance to be displayed by the Fragment.
      */
     @NonNull
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
+    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
         return new Dialog(getActivity(), getTheme());
     }
 
@@ -395,7 +396,7 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         if (!mShowsDialog) {
@@ -436,7 +437,7 @@
     }
 
     @Override
-    public void onSaveInstanceState(Bundle outState) {
+    public void onSaveInstanceState(@NonNull Bundle outState) {
         super.onSaveInstanceState(outState);
         if (mDialog != null) {
             Bundle dialogState = mDialog.onSaveInstanceState();
diff --git a/fragment/src/main/java/android/support/v4/app/Fragment.java b/fragment/src/main/java/android/support/v4/app/Fragment.java
index e93acfe..cab47a8 100644
--- a/fragment/src/main/java/android/support/v4/app/Fragment.java
+++ b/fragment/src/main/java/android/support/v4/app/Fragment.java
@@ -302,7 +302,8 @@
      * Thrown by {@link Fragment#instantiate(Context, String, Bundle)} when
      * there is an instantiation failure.
      */
-    static public class InstantiationException extends RuntimeException {
+    @SuppressWarnings("JavaLangClash")
+    public static class InstantiationException extends RuntimeException {
         public InstantiationException(String msg, Exception cause) {
             super(msg, cause);
         }
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 70c7ad6..f05ac0d 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.5-bin.zip
+distributionUrl=../../../../tools/external/gradle/gradle-4.6-bin.zip
diff --git a/graphics/drawable/animated/build.gradle b/graphics/drawable/animated/build.gradle
index 2f18053..ffaceff 100644
--- a/graphics/drawable/animated/build.gradle
+++ b/graphics/drawable/animated/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/graphics/drawable/animated/lint-baseline.xml b/graphics/drawable/animated/lint-baseline.xml
deleted file mode 100644
index 9fbd83c..0000000
--- a/graphics/drawable/animated/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="4" by="lint 3.0.0-beta6">
-
-    <issue
-        id="ResourceType"
-        message="Expected resource of type anim"
-        errorLine1="            parser = resources.getAnimation(id);"
-        errorLine2="                                            ~~">
-        <location
-            file="src/main/java/android/support/graphics/drawable/AnimatorInflaterCompat.java"
-            line="130"
-            column="45"/>
-    </issue>
-
-</issues>
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index 9388480..63282c0 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/heifwriter/build.gradle b/heifwriter/build.gradle
index 278521c..c1e1aff 100644
--- a/heifwriter/build.gradle
+++ b/heifwriter/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/interpolator/api/0.0.0.txt b/interpolator/api/0.0.0.txt
new file mode 100644
index 0000000..7de1883
--- /dev/null
+++ b/interpolator/api/0.0.0.txt
@@ -0,0 +1,16 @@
+package android.support.v4.view.animation {
+
+  public class FastOutLinearInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutLinearInInterpolator();
+  }
+
+  public class FastOutSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public FastOutSlowInInterpolator();
+  }
+
+  public class LinearOutSlowInInterpolator implements android.view.animation.Interpolator {
+    ctor public LinearOutSlowInInterpolator();
+  }
+
+}
+
diff --git a/interpolator/build.gradle b/interpolator/build.gradle
index 6bc6e04..49c31e2 100644
--- a/interpolator/build.gradle
+++ b/interpolator/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/jetifier/jetifier/core/build.gradle b/jetifier/jetifier/core/build.gradle
index 683a020..5e4f5c0 100644
--- a/jetifier/jetifier/core/build.gradle
+++ b/jetifier/jetifier/core/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License
  */
 
-import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
+import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
 
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportKotlinLibraryPlugin")
diff --git a/jetifier/jetifier/gradle-plugin/build.gradle b/jetifier/jetifier/gradle-plugin/build.gradle
index 4a8d0fb..a2b1cfc 100644
--- a/jetifier/jetifier/gradle-plugin/build.gradle
+++ b/jetifier/jetifier/gradle-plugin/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License
  */
 
-import static android.support.dependencies.DependenciesKt.KOTLIN_STDLIB
+import static androidx.build.dependencies.DependenciesKt.KOTLIN_STDLIB
 
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
   id("SupportKotlinLibraryPlugin")
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 36ba9e2..da4b168 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/common-java8/build.gradle b/lifecycle/common-java8/build.gradle
index bee8b9c..0f4ffd8 100644
--- a/lifecycle/common-java8/build.gradle
+++ b/lifecycle/common-java8/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions;
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions;
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/lifecycle/common/build.gradle b/lifecycle/common/build.gradle
index 866a656..89f46a7 100644
--- a/lifecycle/common/build.gradle
+++ b/lifecycle/common/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions;
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions;
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/lifecycle/compiler/build.gradle b/lifecycle/compiler/build.gradle
index 534d1ec..fec3d99 100644
--- a/lifecycle/compiler/build.gradle
+++ b/lifecycle/compiler/build.gradle
@@ -1,8 +1,11 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
-apply plugin: android.support.SupportKotlinLibraryPlugin
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+    id("SupportKotlinLibraryPlugin")
+}
 
 sourceSets {
     test.java.srcDirs += 'src/tests/kotlin'
diff --git a/lifecycle/extensions/build.gradle b/lifecycle/extensions/build.gradle
index e8ab2f6..2875ab4 100644
--- a/lifecycle/extensions/build.gradle
+++ b/lifecycle/extensions/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/integration-tests/testapp/build.gradle b/lifecycle/integration-tests/testapp/build.gradle
index 25b5b75..c8fba58 100644
--- a/lifecycle/integration-tests/testapp/build.gradle
+++ b/lifecycle/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidTestAppPlugin")
diff --git a/lifecycle/livedata-core/api/current.txt b/lifecycle/livedata-core/api/current.txt
index 0c855c4..7e1d451 100644
--- a/lifecycle/livedata-core/api/current.txt
+++ b/lifecycle/livedata-core/api/current.txt
@@ -5,12 +5,12 @@
     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 public void observe(android.arch.lifecycle.LifecycleOwner, android.arch.lifecycle.Observer<? super T>);
+    method public void observeForever(android.arch.lifecycle.Observer<? super 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 removeObserver(android.arch.lifecycle.Observer<? super T>);
     method public void removeObservers(android.arch.lifecycle.LifecycleOwner);
     method protected void setValue(T);
   }
diff --git a/lifecycle/livedata-core/build.gradle b/lifecycle/livedata-core/build.gradle
index 58765a0..becb17e 100644
--- a/lifecycle/livedata-core/build.gradle
+++ b/lifecycle/livedata-core/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java b/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
index fc8fb31..b49185a 100644
--- a/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
+++ b/lifecycle/livedata-core/src/main/java/android/arch/lifecycle/LiveData.java
@@ -61,7 +61,7 @@
     static final int START_VERSION = -1;
     private static final Object NOT_SET = new Object();
 
-    private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers =
+    private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers =
             new SafeIterableMap<>();
 
     // how many observers are in active state
@@ -121,7 +121,7 @@
                 considerNotify(initiator);
                 initiator = null;
             } else {
-                for (Iterator<Map.Entry<Observer<T>, ObserverWrapper>> iterator =
+                for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                         mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                     considerNotify(iterator.next().getValue());
                     if (mDispatchInvalidated) {
@@ -162,7 +162,7 @@
      * @param observer The observer that will receive the events
      */
     @MainThread
-    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
+    public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
         assertMainThread("observe");
         if (owner.getLifecycle().getCurrentState() == DESTROYED) {
             // ignore
@@ -195,7 +195,7 @@
      * @param observer The observer that will receive the events
      */
     @MainThread
-    public void observeForever(@NonNull Observer<T> observer) {
+    public void observeForever(@NonNull Observer<? super T> observer) {
         assertMainThread("observeForever");
         AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
         ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
@@ -215,7 +215,7 @@
      * @param observer The Observer to receive events.
      */
     @MainThread
-    public void removeObserver(@NonNull final Observer<T> observer) {
+    public void removeObserver(@NonNull final Observer<? super T> observer) {
         assertMainThread("removeObserver");
         ObserverWrapper removed = mObservers.remove(observer);
         if (removed == null) {
@@ -234,7 +234,7 @@
     @MainThread
     public void removeObservers(@NonNull final LifecycleOwner owner) {
         assertMainThread("removeObservers");
-        for (Map.Entry<Observer<T>, ObserverWrapper> entry : mObservers) {
+        for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
             if (entry.getValue().isAttachedTo(owner)) {
                 removeObserver(entry.getKey());
             }
@@ -351,7 +351,7 @@
     class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
         @NonNull final LifecycleOwner mOwner;
 
-        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<T> observer) {
+        LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
             super(observer);
             mOwner = owner;
         }
@@ -382,11 +382,11 @@
     }
 
     private abstract class ObserverWrapper {
-        final Observer<T> mObserver;
+        final Observer<? super T> mObserver;
         boolean mActive;
         int mLastVersion = START_VERSION;
 
-        ObserverWrapper(Observer<T> observer) {
+        ObserverWrapper(Observer<? super T> observer) {
             mObserver = observer;
         }
 
@@ -422,7 +422,7 @@
 
     private class AlwaysActiveObserver extends ObserverWrapper {
 
-        AlwaysActiveObserver(Observer<T> observer) {
+        AlwaysActiveObserver(Observer<? super T> observer) {
             super(observer);
         }
 
diff --git a/lifecycle/livedata/api/current.txt b/lifecycle/livedata/api/current.txt
index f9783ec..13f8154 100644
--- a/lifecycle/livedata/api/current.txt
+++ b/lifecycle/livedata/api/current.txt
@@ -2,7 +2,7 @@
 
   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 addSource(android.arch.lifecycle.LiveData<S>, android.arch.lifecycle.Observer<? super S>);
     method public <S> void removeSource(android.arch.lifecycle.LiveData<S>);
   }
 
diff --git a/lifecycle/livedata/build.gradle b/lifecycle/livedata/build.gradle
index 7047886..cf3b50c 100644
--- a/lifecycle/livedata/build.gradle
+++ b/lifecycle/livedata/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java b/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
index 5864739..3960163 100644
--- a/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
+++ b/lifecycle/livedata/src/main/java/android/arch/lifecycle/MediatorLiveData.java
@@ -82,7 +82,7 @@
      * @param <S>       The type of data hold by {@code source} LiveData
      */
     @MainThread
-    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<S> onChanged) {
+    public <S> void addSource(@NonNull LiveData<S> source, @NonNull Observer<? super S> onChanged) {
         Source<S> e = new Source<>(source, onChanged);
         Source<?> existing = mSources.putIfAbsent(source, e);
         if (existing != null && existing.mObserver != onChanged) {
@@ -129,10 +129,10 @@
 
     private static class Source<V> implements Observer<V> {
         final LiveData<V> mLiveData;
-        final Observer<V> mObserver;
+        final Observer<? super V> mObserver;
         int mVersion = START_VERSION;
 
-        Source(LiveData<V> liveData, final Observer<V> observer) {
+        Source(LiveData<V> liveData, final Observer<? super V> observer) {
             mLiveData = liveData;
             mObserver = observer;
         }
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 5c22e4a..12f12b1 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/runtime/build.gradle b/lifecycle/runtime/build.gradle
index aee73c0..f7f6ff8 100644
--- a/lifecycle/runtime/build.gradle
+++ b/lifecycle/runtime/build.gradle
@@ -1,7 +1,7 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/lifecycle/viewmodel/build.gradle b/lifecycle/viewmodel/build.gradle
index 914d9ce..1494733 100644
--- a/lifecycle/viewmodel/build.gradle
+++ b/lifecycle/viewmodel/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/loader/api/0.0.0.txt b/loader/api/0.0.0.txt
new file mode 100644
index 0000000..d0027ea
--- /dev/null
+++ b/loader/api/0.0.0.txt
@@ -0,0 +1,98 @@
+package android.support.v4.app {
+
+  public abstract class LoaderManager {
+    ctor public LoaderManager();
+    method public abstract void destroyLoader(int);
+    method public abstract void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public static void enableDebugLogging(boolean);
+    method public abstract <D> android.support.v4.content.Loader<D> getLoader(int);
+    method public boolean hasRunningLoaders();
+    method public abstract <D> android.support.v4.content.Loader<D> initLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+    method public abstract <D> android.support.v4.content.Loader<D> restartLoader(int, android.os.Bundle, android.support.v4.app.LoaderManager.LoaderCallbacks<D>);
+  }
+
+  public static abstract interface LoaderManager.LoaderCallbacks<D> {
+    method public abstract android.support.v4.content.Loader<D> onCreateLoader(int, android.os.Bundle);
+    method public abstract void onLoadFinished(android.support.v4.content.Loader<D>, D);
+    method public abstract void onLoaderReset(android.support.v4.content.Loader<D>);
+  }
+
+}
+
+package android.support.v4.content {
+
+  public abstract class AsyncTaskLoader<D> extends android.support.v4.content.Loader {
+    ctor public AsyncTaskLoader(android.content.Context);
+    method public void cancelLoadInBackground();
+    method public boolean isLoadInBackgroundCanceled();
+    method public abstract D loadInBackground();
+    method public void onCanceled(D);
+    method protected D onLoadInBackground();
+    method public void setUpdateThrottle(long);
+  }
+
+  public class CursorLoader extends android.support.v4.content.AsyncTaskLoader {
+    ctor public CursorLoader(android.content.Context);
+    ctor public CursorLoader(android.content.Context, android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String);
+    method public void deliverResult(android.database.Cursor);
+    method public java.lang.String[] getProjection();
+    method public java.lang.String getSelection();
+    method public java.lang.String[] getSelectionArgs();
+    method public java.lang.String getSortOrder();
+    method public android.net.Uri getUri();
+    method public android.database.Cursor loadInBackground();
+    method public void onCanceled(android.database.Cursor);
+    method public void setProjection(java.lang.String[]);
+    method public void setSelection(java.lang.String);
+    method public void setSelectionArgs(java.lang.String[]);
+    method public void setSortOrder(java.lang.String);
+    method public void setUri(android.net.Uri);
+  }
+
+  public class Loader<D> {
+    ctor public Loader(android.content.Context);
+    method public void abandon();
+    method public boolean cancelLoad();
+    method public void commitContentChanged();
+    method public java.lang.String dataToString(D);
+    method public void deliverCancellation();
+    method public void deliverResult(D);
+    method public void dump(java.lang.String, java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
+    method public void forceLoad();
+    method public android.content.Context getContext();
+    method public int getId();
+    method public boolean isAbandoned();
+    method public boolean isReset();
+    method public boolean isStarted();
+    method protected void onAbandon();
+    method protected boolean onCancelLoad();
+    method public void onContentChanged();
+    method protected void onForceLoad();
+    method protected void onReset();
+    method protected void onStartLoading();
+    method protected void onStopLoading();
+    method public void registerListener(int, android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void registerOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+    method public void reset();
+    method public void rollbackContentChanged();
+    method public final void startLoading();
+    method public void stopLoading();
+    method public boolean takeContentChanged();
+    method public void unregisterListener(android.support.v4.content.Loader.OnLoadCompleteListener<D>);
+    method public void unregisterOnLoadCanceledListener(android.support.v4.content.Loader.OnLoadCanceledListener<D>);
+  }
+
+  public final class Loader.ForceLoadContentObserver extends android.database.ContentObserver {
+    ctor public Loader.ForceLoadContentObserver();
+  }
+
+  public static abstract interface Loader.OnLoadCanceledListener<D> {
+    method public abstract void onLoadCanceled(android.support.v4.content.Loader<D>);
+  }
+
+  public static abstract interface Loader.OnLoadCompleteListener<D> {
+    method public abstract void onLoadComplete(android.support.v4.content.Loader<D>, D);
+  }
+
+}
+
diff --git a/loader/build.gradle b/loader/build.gradle
index 45cad2a..b89ac0c 100644
--- a/loader/build.gradle
+++ b/loader/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/localbroadcastmanager/api/0.0.0.txt b/localbroadcastmanager/api/0.0.0.txt
new file mode 100644
index 0000000..5c02abe
--- /dev/null
+++ b/localbroadcastmanager/api/0.0.0.txt
@@ -0,0 +1,12 @@
+package android.support.v4.content {
+
+  public final class LocalBroadcastManager {
+    method public static android.support.v4.content.LocalBroadcastManager getInstance(android.content.Context);
+    method public void registerReceiver(android.content.BroadcastReceiver, android.content.IntentFilter);
+    method public boolean sendBroadcast(android.content.Intent);
+    method public void sendBroadcastSync(android.content.Intent);
+    method public void unregisterReceiver(android.content.BroadcastReceiver);
+  }
+
+}
+
diff --git a/localbroadcastmanager/build.gradle b/localbroadcastmanager/build.gradle
index a3d35bf..2709f7d 100644
--- a/localbroadcastmanager/build.gradle
+++ b/localbroadcastmanager/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/build.gradle b/media-compat/build.gradle
index 29c91b7..f952731 100644
--- a/media-compat/build.gradle
+++ b/media-compat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -14,7 +14,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils')
+    androidTestImplementation project(':internal-testutils')
 }
 
 android {
diff --git a/media-compat/version-compat-tests/current/client/build.gradle b/media-compat/version-compat-tests/current/client/build.gradle
index 2a247df..385462f 100644
--- a/media-compat/version-compat-tests/current/client/build.gradle
+++ b/media-compat/version-compat-tests/current/client/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/current/service/build.gradle b/media-compat/version-compat-tests/current/service/build.gradle
index 2a247df..385462f 100644
--- a/media-compat/version-compat-tests/current/service/build.gradle
+++ b/media-compat/version-compat-tests/current/service/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/lib/build.gradle b/media-compat/version-compat-tests/lib/build.gradle
index caa6c7e..df9e75c 100644
--- a/media-compat/version-compat-tests/lib/build.gradle
+++ b/media-compat/version-compat-tests/lib/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/previous/client/build.gradle b/media-compat/version-compat-tests/previous/client/build.gradle
index 31f33fe..4319f69 100644
--- a/media-compat/version-compat-tests/previous/client/build.gradle
+++ b/media-compat/version-compat-tests/previous/client/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/media-compat/version-compat-tests/previous/service/build.gradle b/media-compat/version-compat-tests/previous/service/build.gradle
index 765e406..28c88c3 100644
--- a/media-compat/version-compat-tests/previous/service/build.gradle
+++ b/media-compat/version-compat-tests/previous/service/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/paging/common/build.gradle b/paging/common/build.gradle
index dbe6b06..bc1d3a8 100644
--- a/paging/common/build.gradle
+++ b/paging/common/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/paging/integration-tests/testapp/build.gradle b/paging/integration-tests/testapp/build.gradle
index d1b0aec..9aab333 100644
--- a/paging/integration-tests/testapp/build.gradle
+++ b/paging/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 
 plugins {
diff --git a/paging/runtime/build.gradle b/paging/runtime/build.gradle
index 4c42b30..20a39d4 100644
--- a/paging/runtime/build.gradle
+++ b/paging/runtime/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/percent/build.gradle b/percent/build.gradle
index 9585323..7209ac2 100644
--- a/percent/build.gradle
+++ b/percent/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/persistence/db-framework/build.gradle b/persistence/db-framework/build.gradle
index bae3d02..15f638b 100644
--- a/persistence/db-framework/build.gradle
+++ b/persistence/db-framework/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/persistence/db/build.gradle b/persistence/db/build.gradle
index 657ef1e..5c9cb2d 100644
--- a/persistence/db/build.gradle
+++ b/persistence/db/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/preference-leanback/build.gradle b/preference-leanback/build.gradle
index fc88f28..e5c19da 100644
--- a/preference-leanback/build.gradle
+++ b/preference-leanback/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/print/api/0.0.0.txt b/print/api/0.0.0.txt
new file mode 100644
index 0000000..5277150
--- /dev/null
+++ b/print/api/0.0.0.txt
@@ -0,0 +1,29 @@
+package android.support.v4.print {
+
+  public final class PrintHelper {
+    ctor public PrintHelper(android.content.Context);
+    method public int getColorMode();
+    method public int getOrientation();
+    method public int getScaleMode();
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap);
+    method public void printBitmap(java.lang.String, android.graphics.Bitmap, android.support.v4.print.PrintHelper.OnPrintFinishCallback);
+    method public void printBitmap(java.lang.String, android.net.Uri) throws java.io.FileNotFoundException;
+    method public void printBitmap(java.lang.String, android.net.Uri, android.support.v4.print.PrintHelper.OnPrintFinishCallback) throws java.io.FileNotFoundException;
+    method public void setColorMode(int);
+    method public void setOrientation(int);
+    method public void setScaleMode(int);
+    method public static boolean systemSupportsPrint();
+    field public static final int COLOR_MODE_COLOR = 2; // 0x2
+    field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1
+    field public static final int ORIENTATION_LANDSCAPE = 1; // 0x1
+    field public static final int ORIENTATION_PORTRAIT = 2; // 0x2
+    field public static final int SCALE_MODE_FILL = 2; // 0x2
+    field public static final int SCALE_MODE_FIT = 1; // 0x1
+  }
+
+  public static abstract interface PrintHelper.OnPrintFinishCallback {
+    method public abstract void onFinish();
+  }
+
+}
+
diff --git a/print/build.gradle b/print/build.gradle
index 78fc9db..d3af888 100644
--- a/print/build.gradle
+++ b/print/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/print/src/main/java/android/support/v4/print/PrintHelper.java b/print/src/main/java/android/support/v4/print/PrintHelper.java
index ce342e3..5f445b7 100644
--- a/print/src/main/java/android/support/v4/print/PrintHelper.java
+++ b/print/src/main/java/android/support/v4/print/PrintHelper.java
@@ -39,6 +39,8 @@
 import android.print.PrintManager;
 import android.print.pdf.PrintedPdfDocument;
 import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.annotation.RequiresApi;
 import android.util.Log;
 
@@ -136,9 +138,11 @@
 
         int getOrientation();
 
-        void printBitmap(String jobName, Bitmap bitmap, OnPrintFinishCallback callback);
+        void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
+                @Nullable OnPrintFinishCallback callback);
 
-        void printBitmap(String jobName, Uri imageFile, OnPrintFinishCallback callback)
+        void printBitmap(@NonNull String jobName, @NonNull Uri imageFile,
+                @Nullable OnPrintFinishCallback callback)
                 throws FileNotFoundException;
     }
 
@@ -885,7 +889,7 @@
      *
      * @param context A context for accessing system resources.
      */
-    public PrintHelper(Context context) {
+    public PrintHelper(@NonNull Context context) {
         if (Build.VERSION.SDK_INT >= 24) {
             mImpl = new PrintHelperApi24(context);
         } else if (Build.VERSION.SDK_INT >= 23) {
@@ -975,7 +979,7 @@
      * @param jobName The print job name.
      * @param bitmap  The bitmap to print.
      */
-    public void printBitmap(String jobName, Bitmap bitmap) {
+    public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap) {
         mImpl.printBitmap(jobName, bitmap, null);
     }
 
@@ -986,7 +990,8 @@
      * @param bitmap  The bitmap to print.
      * @param callback Optional callback to observe when printing is finished.
      */
-    public void printBitmap(String jobName, Bitmap bitmap, OnPrintFinishCallback callback) {
+    public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
+            @Nullable OnPrintFinishCallback callback) {
         mImpl.printBitmap(jobName, bitmap, callback);
     }
 
@@ -999,7 +1004,8 @@
      * @param imageFile The <code>Uri</code> pointing to an image to print.
      * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
      */
-    public void printBitmap(String jobName, Uri imageFile) throws FileNotFoundException {
+    public void printBitmap(@NonNull String jobName, @NonNull Uri imageFile)
+            throws FileNotFoundException {
         mImpl.printBitmap(jobName, imageFile, null);
     }
 
@@ -1013,7 +1019,8 @@
      * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
      * @param callback Optional callback to observe when printing is finished.
      */
-    public void printBitmap(String jobName, Uri imageFile, OnPrintFinishCallback callback)
+    public void printBitmap(@NonNull String jobName, @NonNull Uri imageFile,
+            @Nullable OnPrintFinishCallback callback)
             throws FileNotFoundException {
         mImpl.printBitmap(jobName, imageFile, callback);
     }
diff --git a/recommendation/build.gradle b/recommendation/build.gradle
index b401eb8..4f4a737 100644
--- a/recommendation/build.gradle
+++ b/recommendation/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/recyclerview-selection/build.gradle b/recyclerview-selection/build.gradle
index 85745d6..94f8a05 100644
--- a/recyclerview-selection/build.gradle
+++ b/recyclerview-selection/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/room/common/build.gradle b/room/common/build.gradle
index 9457308..1bf6652 100644
--- a/room/common/build.gradle
+++ b/room/common/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/room/compiler/build.gradle b/room/compiler/build.gradle
index c3319ac..3599893 100644
--- a/room/compiler/build.gradle
+++ b/room/compiler/build.gradle
@@ -15,14 +15,16 @@
  */
 
 
-import android.support.SupportConfig
+import androidx.build.SupportConfig
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
-apply plugin: android.support.SupportKotlinLibraryPlugin
+plugins {
+    id("SupportKotlinLibraryPlugin")
+}
 
 def antlrOut = "$buildDir/generated/antlr/grammar-gen/"
 sourceSets {
diff --git a/room/guava/build.gradle b/room/guava/build.gradle
index 8660aae..3837406 100644
--- a/room/guava/build.gradle
+++ b/room/guava/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/room/integration-tests/kotlintestapp/build.gradle b/room/integration-tests/kotlintestapp/build.gradle
index 1dc0a79..162f325 100644
--- a/room/integration-tests/kotlintestapp/build.gradle
+++ b/room/integration-tests/kotlintestapp/build.gradle
@@ -17,7 +17,7 @@
 //./gradlew :r:in:k:clean :r:in:k:cC --no-daemon
 // -Dorg.gradle.debug=true
 // -Dkotlin.compiler.execution.strategy="in-process"
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidTestAppPlugin")
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 45ec9c6..401cc07 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidTestAppPlugin")
diff --git a/room/migration/build.gradle b/room/migration/build.gradle
index acadb71..2b683e8 100644
--- a/room/migration/build.gradle
+++ b/room/migration/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension;
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension;
 
 plugins {
     id("SupportJavaLibraryPlugin")
diff --git a/room/runtime/build.gradle b/room/runtime/build.gradle
index 1022616..739725c 100644
--- a/room/runtime/build.gradle
+++ b/room/runtime/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/room/rxjava2/build.gradle b/room/rxjava2/build.gradle
index d3d7bc9..8dcaa6b 100644
--- a/room/rxjava2/build.gradle
+++ b/room/rxjava2/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/room/testing/build.gradle b/room/testing/build.gradle
index d584b54..48ac8a7 100644
--- a/room/testing/build.gradle
+++ b/room/testing/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
-import android.support.SupportLibraryExtension
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/samples/SupportContentDemos/lint-baseline.xml b/samples/SupportContentDemos/lint-baseline.xml
index d25b380..1dfd06e 100644
--- a/samples/SupportContentDemos/lint-baseline.xml
+++ b/samples/SupportContentDemos/lint-baseline.xml
@@ -35,17 +35,6 @@
     </issue>
 
     <issue
-        id="WrongConstant"
-        message="Must be one of: BaseTransientBottomBar.LENGTH_INDEFINITE, BaseTransientBottomBar.LENGTH_SHORT, BaseTransientBottomBar.LENGTH_LONG or value must be ≥ 1 (was 0)"
-        errorLine1="                msg, Snackbar.LENGTH_LONG)"
-        errorLine2="                     ~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/com/example/android/support/content/demos/ContentPagerDemoActivity.java"
-            line="143"
-            column="22"/>
-    </issue>
-
-    <issue
         id="AllowBackup"
         message="On SDK version 23 and up, your app data will be automatically backed up and restored on app install. Consider adding the attribute `android:fullBackupContent` to specify an `@xml` resource which configures which files to backup. More info: https://developer.android.com/training/backup/autosyncapi.html"
         errorLine1="    &lt;application"
diff --git a/samples/SupportSliceDemos/build.gradle b/samples/SupportSliceDemos/build.gradle
index a0b236d..4eb590e 100644
--- a/samples/SupportSliceDemos/build.gradle
+++ b/samples/SupportSliceDemos/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidTestAppPlugin")
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
index 1df92f9..6230dd0 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SampleSliceProvider.java
@@ -46,6 +46,8 @@
  */
 public class SampleSliceProvider extends SliceProvider {
 
+    private static final boolean TEST_CUSTOM_SEE_MORE = false;
+
     public static final String ACTION_WIFI_CHANGED =
             "com.example.androidx.slice.action.WIFI_CHANGED";
     public static final String ACTION_TOAST =
@@ -414,18 +416,50 @@
                 state = ""; // just don't show anything?
                 break;
         }
+
+        // Set the first row as a toggle
         boolean finalWifiEnabled = wifiEnabled;
         SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
                 Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
-        return new ListBuilder(getContext(), sliceUri)
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri)
                 .setColor(0xff4285f4)
                 .addRow(b -> b
                     .setTitle("Wi-fi")
                     .setSubtitle(state)
                     .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
                             "Toggle wifi", finalWifiEnabled))
-                    .setPrimaryAction(primaryAction))
-                .build();
+                    .setPrimaryAction(primaryAction));
+
+        // Add fake wifi networks
+        int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+                R.drawable.ic_wifi_fair};
+        for (int i = 0; i < 10; i++) {
+            final int iconId = wifiIcons[i % wifiIcons.length];
+            Icon icon = Icon.createWithResource(getContext(), iconId);
+            final String networkName = "Network" + i;
+            ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb);
+            rb.setTitleItem(icon)
+                .setTitle("Network" + networkName);
+            boolean locked = i % 3 == 0;
+            if (locked) {
+                rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock));
+            }
+            String message = locked ? "Open wifi password dialog" : "Connect to " + networkName;
+            rb.setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, message), icon,
+                    message));
+            lb.addRow(rb);
+        }
+
+        // Add see more intent
+        if (TEST_CUSTOM_SEE_MORE) {
+            lb.addSeeMoreRow(rb -> rb
+                    .setTitle("See all available networks")
+                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret))
+                    .setPrimaryAction(primaryAction));
+        } else {
+            lb.addSeeMoreAction(primaryAction.getAction());
+        }
+        return lb.build();
     }
 
     private Slice createStarRatingInputRange(Uri sliceUri) {
diff --git a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
index c7751c4..f55bf4b 100644
--- a/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
+++ b/samples/SupportSliceDemos/src/main/java/com/example/androidx/slice/demos/SliceBrowser.java
@@ -67,6 +67,7 @@
     private static final String SLICE_METADATA_KEY = "android.metadata.SLICE_URI";
     private static final boolean TEST_INTENT = false;
     private static final boolean TEST_THEMES = false;
+    private static final boolean SCROLLING_ENABLED = true;
 
     private ArrayList<Uri> mSliceUris = new ArrayList<Uri>();
     private int mSelectedMode;
@@ -289,6 +290,7 @@
         if (mSliceLiveData != null) {
             mSliceLiveData.removeObservers(this);
         }
+        v.setScrollable(SCROLLING_ENABLED);
         return v;
     }
 }
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..7a79428
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_lock.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector android:height="16dp" android:viewportHeight="24.0"
+    android:viewportWidth="24.0" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2L8.9,8L8.9,6zM18,20L6,20L6,10h12v10z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml
new file mode 100644
index 0000000..a4f9d06
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_more.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml
new file mode 100644
index 0000000..3310e62
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_right_caret.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml
new file mode 100644
index 0000000..4e92a64
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_fair.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml
new file mode 100644
index 0000000..0b37310
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_full.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/>
+</vector>
diff --git a/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml
new file mode 100644
index 0000000..87c84ce
--- /dev/null
+++ b/samples/SupportSliceDemos/src/main/res/drawable/ic_wifi_low.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.67,14.86L12,21.49v0.01l0.01,-0.01 5.33,-6.63C17.06,14.65 15.03,13 12,13s-5.06,1.65 -5.33,1.86z"/>
+</vector>
diff --git a/samples/ViewPager2Demos/OWNERS b/samples/ViewPager2Demos/OWNERS
new file mode 100644
index 0000000..e24ee8b
--- /dev/null
+++ b/samples/ViewPager2Demos/OWNERS
@@ -0,0 +1 @@
+jgielzak@google.com
\ No newline at end of file
diff --git a/samples/ViewPager2Demos/src/main/AndroidManifest.xml b/samples/ViewPager2Demos/src/main/AndroidManifest.xml
index 57e52d3..71d115e 100644
--- a/samples/ViewPager2Demos/src/main/AndroidManifest.xml
+++ b/samples/ViewPager2Demos/src/main/AndroidManifest.xml
@@ -16,7 +16,7 @@
 
 <manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.androidx.widget.viewpager2">
+    package="com.example.androidx.viewpager2">
 
     <application
         android:icon="@drawable/app_sample_code"
@@ -31,6 +31,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".CardFragmentActivity" android:label="CardsFragmentDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.SAMPLE_CODE"/>
+            </intent-filter>
+        </activity>
+
         <activity android:name=".BrowseActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
similarity index 97%
rename from samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java
rename to samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
index 6c36994..41e4f99 100644
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/BrowseActivity.java
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/BrowseActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.example.androidx.widget.viewpager2;
+package com.example.androidx.viewpager2;
 
 import android.app.ListActivity;
 import android.content.Intent;
@@ -45,7 +45,7 @@
         super.onCreate(savedInstanceState);
 
         Intent intent = getIntent();
-        String path = intent.getStringExtra("com.example.androidx.widget.viewpager2");
+        String path = intent.getStringExtra("com.example.androidx.viewpager2");
 
         if (path == null) {
             path = "";
@@ -131,7 +131,7 @@
     protected Intent browseIntent(String path) {
         Intent result = new Intent();
         result.setClass(this, BrowseActivity.class);
-        result.putExtra("com.example.androidx.widget.viewpager2", path);
+        result.putExtra("com.example.androidx.viewpager2", path);
         return result;
     }
 
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java
new file mode 100644
index 0000000..7c43127
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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 com.example.androidx.viewpager2;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.view.ViewGroup;
+
+import com.example.androidx.viewpager2.cards.Card;
+import com.example.androidx.viewpager2.cards.CardView;
+
+import java.util.List;
+
+import androidx.viewpager2.widget.ViewPager2;
+
+/**
+ * Shows how to use {@link ViewPager2#setAdapter(RecyclerView.Adapter)}
+ *
+ * @see CardFragmentActivity
+ */
+public class CardActivity extends Activity {
+    private static final List<Card> sCards = unmodifiableList(Card.createDeck52());
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setContentView(R.layout.activity_card_layout);
+
+        this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(
+                new RecyclerView.Adapter<CardViewHolder>() {
+                    @NonNull
+                    public CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                            int viewType) {
+                        return new CardViewHolder(new CardView(getLayoutInflater(), parent));
+                    }
+
+                    @Override
+                    public void onBindViewHolder(@NonNull CardViewHolder holder, int position) {
+                        holder.bind(sCards.get(position));
+                    }
+
+                    @Override
+                    public int getItemCount() {
+                        return sCards.size();
+                    }
+                });
+    }
+
+    /** @inheritDoc */
+    public static class CardViewHolder extends RecyclerView.ViewHolder {
+        private final CardView mCardView;
+
+        /** {@inheritDoc} */
+        public CardViewHolder(CardView cardView) {
+            super(cardView.getView());
+            mCardView = cardView;
+        }
+
+        /** @see CardView#bind(Card) */
+        public void bind(Card card) {
+            mCardView.bind(card);
+        }
+    }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
new file mode 100644
index 0000000..fe4e538
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2018 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 com.example.androidx.viewpager2;
+
+import static java.util.Collections.unmodifiableList;
+
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.example.androidx.viewpager2.cards.Card;
+import com.example.androidx.viewpager2.cards.CardView;
+
+import java.util.List;
+
+import androidx.viewpager2.widget.ViewPager2;
+import androidx.viewpager2.widget.ViewPager2.FragmentProvider;
+
+/**
+ * Shows how to use {@link ViewPager2#setAdapter(FragmentManager, FragmentProvider, int)}
+ *
+ * @see CardActivity
+ */
+public class CardFragmentActivity extends FragmentActivity {
+    private static final List<Card> sCards = unmodifiableList(Card.createDeck52());
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setContentView(R.layout.activity_card_layout);
+
+        this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(getSupportFragmentManager(),
+                new FragmentProvider() {
+                    @Override
+                    public Fragment getItem(int position) {
+                        return CardFragment.create(sCards.get(position));
+                    }
+
+                    @Override
+                    public int getCount() {
+                        return sCards.size();
+                    }
+                },
+                ViewPager2.FragmentRetentionPolicy.SAVE_STATE);
+    }
+
+        /** {@inheritDoc} */
+    public static class CardFragment extends Fragment {
+        @Nullable
+        @Override
+        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            CardView cardView = new CardView(getLayoutInflater(), container);
+            cardView.bind(Card.fromBundle(getArguments()));
+            return cardView.getView();
+        }
+
+        /** Creates a Fragment for a given {@link Card} */
+        public static CardFragment create(Card card) {
+            CardFragment fragment = new CardFragment();
+            fragment.setArguments(card.toBundle());
+            return fragment;
+        }
+    }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java
new file mode 100644
index 0000000..28b8fd1
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/Card.java
@@ -0,0 +1,91 @@
+/*
+ * 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 com.example.androidx.viewpager2.cards;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.unmodifiableSet;
+
+import android.os.Bundle;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Playing card
+ */
+public class Card {
+    private static final String ARGS_BUNDLE = Card.class.getName() + ":Bundle";
+
+    private static final Set<Character> SUITS = unmodifiableSet(new LinkedHashSet<>(
+            asList('♣' /* clubs*/, '♦' /* diamonds*/, '♥' /* hearts*/, '♠' /*spades*/)));
+    private static final Set<Character> VALUES = unmodifiableSet(new LinkedHashSet<>(
+            asList('2', '3', '4', '5', '6', '7', '8', '9', '⒑', 'J', 'Q', 'K', 'A')));
+
+    private final char mSuit;
+    private final char mValue;
+
+    public Card(char suit, char value) {
+        this.mSuit = checkValidValue(suit, SUITS);
+        this.mValue = checkValidValue(value, VALUES);
+    }
+
+    char getSuit() {
+        return mSuit;
+    }
+
+    String getCornerLabel() {
+        return mValue + "\n" + mSuit;
+    }
+
+    /** Use in conjunction with {@link Card#fromBundle(Bundle)} */
+    public Bundle toBundle() {
+        Bundle args = new Bundle(1);
+        args.putCharArray(ARGS_BUNDLE, new char[]{mSuit, mValue});
+        return args;
+    }
+
+    /** Use in conjunction with {@link Card#toBundle()} */
+    public static Card fromBundle(Bundle bundle) {
+        char[] spec = bundle.getCharArray(ARGS_BUNDLE);
+        return new Card(spec[0], spec[1]);
+    }
+
+    private static char checkValidValue(char value, Set<Character> allowed) {
+        if (allowed.contains(value)) {
+            return value;
+        }
+        throw new IllegalArgumentException("Illegal argument: " + value);
+    }
+
+    /**
+     * Creates a deck of all allowed cards
+     */
+    public static List<Card> createDeck52() {
+        List<Card> result = new ArrayList<>(52);
+        for (Character suit : SUITS) {
+            for (Character value : VALUES) {
+                result.add(new Card(suit, value));
+            }
+        }
+        if (result.size() != 52) {
+            throw new IllegalStateException();
+        }
+        return result;
+    }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java
new file mode 100644
index 0000000..02b52f8
--- /dev/null
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/cards/CardView.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 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 com.example.androidx.viewpager2.cards;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.example.androidx.viewpager2.R;
+
+/** Inflates and populates a {@link View} representing a {@link Card} */
+public class CardView {
+    private final View mView;
+    private final TextView mTextSuite;
+    private final TextView mTextCorner1;
+    private final TextView mTextCorner2;
+
+    public CardView(LayoutInflater layoutInflater, ViewGroup container) {
+        mView = layoutInflater.inflate(R.layout.item_card_layout, container, false);
+        mTextSuite = mView.findViewById(R.id.label_center);
+        mTextCorner1 = mView.findViewById(R.id.label_top);
+        mTextCorner2 = mView.findViewById(R.id.label_bottom);
+    }
+
+    /**
+     * Updates the view to represent the passed in card
+     */
+    public void bind(Card card) {
+        mTextSuite.setText(Character.toString(card.getSuit()));
+
+        String cornerLabel = card.getCornerLabel();
+        mTextCorner1.setText(cornerLabel);
+        mTextCorner2.setText(cornerLabel);
+        mTextCorner2.setRotation(180);
+    }
+
+    public View getView() {
+        return mView;
+    }
+}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java
deleted file mode 100644
index 7484389..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/CardActivity.java
+++ /dev/null
@@ -1,49 +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 com.example.androidx.widget.viewpager2;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableList;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-import com.example.androidx.widget.viewpager2.cards.Card;
-import com.example.androidx.widget.viewpager2.cards.CardDataAdapter;
-
-import java.util.List;
-
-import androidx.widget.ViewPager2;
-
-/** @inheritDoc */
-public class CardActivity extends Activity {
-    private static final List<Card> sCards = unmodifiableList(asList(
-            new Card('♦', 'A'),
-            new Card('♣', 'K'),
-            new Card('♥', 'J'),
-            new Card('♠', '9'),
-            new Card('♦', '2')));
-
-    @Override
-    public void onCreate(Bundle bundle) {
-        super.onCreate(bundle);
-        setContentView(R.layout.activity_card_layout);
-
-        this.<ViewPager2>findViewById(R.id.view_pager).setAdapter(
-                new CardDataAdapter(getLayoutInflater(), sCards));
-    }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java
deleted file mode 100644
index 02f3271..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/Card.java
+++ /dev/null
@@ -1,56 +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 com.example.androidx.widget.viewpager2.cards;
-
-import static java.util.Arrays.asList;
-import static java.util.Collections.unmodifiableSet;
-
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-/**
- * Playing card
- */
-public class Card {
-    private static final Set<Character> SUITS = unmodifiableSet(new LinkedHashSet<>(
-            asList('♦', /* diamonds*/ '♣', /*, clubs*/ '♥', /* hearts*/ '♠' /*spades*/)));
-    private static final Set<Character> VALUES = unmodifiableSet(new LinkedHashSet<>(
-            asList('2', '3', '4', '5', '6', '7', '8', '9', '⒑', 'J', 'Q', 'K', 'A')));
-
-    private final char mSuit;
-    private final char mValue;
-
-    public Card(char suit, char value) {
-        this.mSuit = checkValidValue(suit, SUITS);
-        this.mValue = checkValidValue(value, VALUES);
-    }
-
-    public char getSuit() {
-        return mSuit;
-    }
-
-    public String getCornerLabel() {
-        return mValue + "\n" + mSuit;
-    }
-
-    private static char checkValidValue(char value, Set<Character> allowed) {
-        if (allowed.contains(value)) {
-            return value;
-        }
-        throw new IllegalArgumentException("Illegal argument: " + value);
-    }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java
deleted file mode 100644
index 7f69e1b..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardDataAdapter.java
+++ /dev/null
@@ -1,56 +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 com.example.androidx.widget.viewpager2.cards;
-
-import android.support.annotation.NonNull;
-import android.support.v7.widget.RecyclerView;
-import android.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.example.androidx.widget.viewpager2.R;
-
-import java.util.List;
-
-/** @inheritDoc */
-public class CardDataAdapter extends RecyclerView.Adapter<CardViewHolder> {
-    private final List<Card> mCards;
-    private final LayoutInflater mLayoutInflater;
-
-    public CardDataAdapter(LayoutInflater layoutInflater, List<Card> cards) {
-        mLayoutInflater = layoutInflater;
-        mCards = cards;
-    }
-
-    /**
-     * @inheritDoc
-     */
-    @NonNull
-    public CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-        return new CardViewHolder(
-                mLayoutInflater.inflate(R.layout.item_card_layout, parent, false));
-    }
-
-    @Override
-    public void onBindViewHolder(@NonNull CardViewHolder holder, int position) {
-        holder.apply(mCards.get(position));
-    }
-
-    @Override
-    public int getItemCount() {
-        return mCards.size();
-    }
-}
diff --git a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java b/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java
deleted file mode 100644
index 8fd0477..0000000
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/widget/viewpager2/cards/CardViewHolder.java
+++ /dev/null
@@ -1,49 +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 com.example.androidx.widget.viewpager2.cards;
-
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.widget.TextView;
-
-import com.example.androidx.widget.viewpager2.R;
-
-/** @inheritDoc */
-public class CardViewHolder extends RecyclerView.ViewHolder {
-    private final TextView mTextSuite;
-    private final TextView mTextCorner1;
-    private final TextView mTextCorner2;
-
-    public CardViewHolder(View itemView) {
-        super(itemView);
-        mTextSuite = itemView.findViewById(R.id.label_center);
-        mTextCorner1 = itemView.findViewById(R.id.label_top);
-        mTextCorner2 = itemView.findViewById(R.id.label_bottom);
-    }
-
-    /**
-     * Updates the view to represent the passed in card
-     */
-    public void apply(Card card) {
-        mTextSuite.setText(Character.toString(card.getSuit()));
-
-        String cornerLabel = card.getCornerLabel();
-        mTextCorner1.setText(cornerLabel);
-        mTextCorner2.setText(cornerLabel);
-        mTextCorner2.setRotation(180);
-    }
-}
diff --git a/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml b/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
index 3037029..9d996ab 100644
--- a/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
+++ b/samples/ViewPager2Demos/src/main/res/layout/activity_card_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<androidx.widget.ViewPager2
+<androidx.viewpager2.widget.ViewPager2
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/view_pager"
     android:layout_width="match_parent"
diff --git a/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml b/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
index 90a0404..1ae9295 100644
--- a/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
+++ b/samples/ViewPager2Demos/src/main/res/layout/item_card_layout.xml
@@ -26,6 +26,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="top|start"
+        android:gravity="center"
         android:textAppearance="@android:style/TextAppearance.Medium"/>
 
     <TextView
@@ -40,5 +41,6 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="bottom|end"
+        android:gravity="center"
         android:textAppearance="@android:style/TextAppearance.Medium"/>
 </FrameLayout>
diff --git a/settings.gradle b/settings.gradle
index 06b1c32..5e1b188 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -127,7 +127,7 @@
 //
 /////////////////////////////
 
-includeProject(":support-testutils", "testutils")
+includeProject(":internal-testutils", "testutils")
 
 /////////////////////////////
 //
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 491617a..4b9a250 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryVersions
-import android.support.LibraryGroups
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryVersions
+import androidx.build.LibraryGroups
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
index 4147dc4..84c7325 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderV1Impl.java
@@ -140,7 +140,8 @@
         getBuilder().addSubSlice(
                 new Slice.Builder(getBuilder())
                         .addHints(HINT_SEE_MORE)
-                        .addAction(intent, new Slice.Builder(getBuilder()).build(), null)
+                        .addAction(intent, new Slice.Builder(getBuilder())
+                                .addHints(HINT_SEE_MORE).build(), null)
                         .build());
     }
 
diff --git a/slices/core/build.gradle b/slices/core/build.gradle
index 8087ab4..f1eed8d 100644
--- a/slices/core/build.gradle
+++ b/slices/core/build.gradle
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index af2a1be..43e17d3 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -44,6 +44,7 @@
     method public void setPosition(int, int, int);
     field public static final int ACTION_TYPE_BUTTON = 1; // 0x1
     field public static final int ACTION_TYPE_CONTENT = 3; // 0x3
+    field public static final int ACTION_TYPE_SEE_MORE = 4; // 0x4
     field public static final int ACTION_TYPE_SLIDER = 2; // 0x2
     field public static final int ACTION_TYPE_TOGGLE = 0; // 0x0
     field public static final int POSITION_CELL = 2; // 0x2
diff --git a/slices/view/build.gradle b/slices/view/build.gradle
index 0d9d277..acea2c6 100644
--- a/slices/view/build.gradle
+++ b/slices/view/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryVersions
-import android.support.LibraryGroups
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryVersions
+import androidx.build.LibraryGroups
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -26,7 +26,7 @@
     implementation(project(":slices-core"))
     implementation(project(":slices-builders"))
     implementation(project(":recyclerview-v7"))
-    api(ARCH_LIFECYCLE_EXTENSIONS, libs.exclude_annotations_transitive)
+    api(ARCH_LIFECYCLE_LIVEDATA_CORE, libs.exclude_annotations_transitive)
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(ESPRESSO_CORE)
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
index cec5ef4..3c5aa5b 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
@@ -48,7 +48,7 @@
             "com.example.androidx.slice.action.TOAST";
     public static final String EXTRA_TOAST_MESSAGE = "com.example.androidx.extra.TOAST_MESSAGE";
 
-    public static final String[] URI_PATHS = {"message", "wifi", "note", "ride", "toggle",
+    public static final String[] URI_PATHS = {"message", "wifi", "wifi2", "note", "ride", "toggle",
             "toggle2", "contact", "gallery", "weather"};
 
     private final Context mContext;
@@ -78,7 +78,9 @@
             case "/message":
                 return createMessagingSlice(sliceUri);
             case "/wifi":
-                return createWifiSlice(sliceUri);
+                return createWifiSlice(sliceUri, false /* customSeeMore */);
+            case "/wifi2":
+                return createWifiSlice(sliceUri, true /* customSeeMore */);
             case "/note":
                 return createNoteSlice(sliceUri);
             case "/ride":
@@ -283,7 +285,7 @@
                 .build();
     }
 
-    private Slice createWifiSlice(Uri sliceUri) {
+    private Slice createWifiSlice(Uri sliceUri, boolean customSeeMore) {
         // Get wifi state
         WifiManager wifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
         int wifiState = wifiManager.getWifiState();
@@ -305,18 +307,46 @@
                 break;
         }
         boolean finalWifiEnabled = wifiEnabled;
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
         SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
                 Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
-        return b.setColor(0xff4285f4)
-                .addRow(new ListBuilder.RowBuilder(b)
-                    .setTitle("Wi-fi")
-                    .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
-                    .setSubtitle(state)
-                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
-                                "Toggle wifi", finalWifiEnabled))
-                    .setPrimaryAction(primaryAction))
-            .build();
+        lb.setColor(0xff4285f4);
+        lb.addRow(new ListBuilder.RowBuilder(lb)
+                .setTitle("Wi-fi")
+                .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi))
+                .setSubtitle(state)
+                .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
+                        "Toggle wifi", finalWifiEnabled))
+                .setPrimaryAction(primaryAction));
+
+        // Add fake wifi networks
+        int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+                R.drawable.ic_wifi_fair};
+        for (int i = 0; i < 10; i++) {
+            final int iconId = wifiIcons[i % wifiIcons.length];
+            Icon icon = Icon.createWithResource(getContext(), iconId);
+            final String networkName = "Network" + i;
+            ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb);
+            rb.setTitleItem(icon)
+                    .setTitle("Network" + networkName);
+            boolean locked = i % 3 == 0;
+            if (locked) {
+                rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock));
+            }
+            String message = locked ? "Open wifi password dialog" : "Connect to " + networkName;
+            rb.setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, message), icon,
+                    message));
+            lb.addRow(rb);
+        }
+        if (customSeeMore) {
+            lb.addSeeMoreRow(new ListBuilder.RowBuilder(lb)
+                    .setTitle("See all available networks")
+                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret))
+                    .setPrimaryAction(primaryAction));
+        } else {
+            lb.addSeeMoreAction(primaryAction.getAction());
+        }
+        return lb.build();
     }
 
     private PendingIntent getIntent(String action) {
diff --git a/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java b/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
index ca968db..1c33115 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceRenderer.java
@@ -127,7 +127,13 @@
         }
         mDoneLatch = new CountDownLatch(SliceCreator.URI_PATHS.length);
         for (String slice : SliceCreator.URI_PATHS) {
-            doRender(slice, new File(output, String.format("%s.png", slice)));
+            doRender(slice, new File(output, String.format("%s.png", slice)),
+                    true /* scrollable */);
+            if (slice.equals("wifi") || slice.equals("wifi2")) {
+                // Test scrolling
+                doRender(slice, new File(output, String.format("%s-no-scroll.png", slice)),
+                        false /* scrollable */);
+            }
         }
         Log.d(TAG, "Wrote render to " + output.getAbsolutePath());
         mContext.runOnUiThread(new Runnable() {
@@ -142,7 +148,7 @@
         }
     }
 
-    private void doRender(final String slice, final File file) {
+    private void doRender(final String slice, final File file, final boolean scrollable) {
         Log.d(TAG, "Rendering " + slice + " to " + file.getAbsolutePath());
 
         final Slice s = mSliceCreator.onBindSlice(SliceCreator.getUri(slice, mContext));
@@ -154,6 +160,7 @@
                 mSV1.setSlice(s);
                 mSV2.setSlice(s);
                 mSV3.setSlice(s);
+                mSV3.setScrollable(scrollable);
                 mSV1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                     @Override
                     public void onLayoutChange(View v, int left, int top, int right, int bottom,
diff --git a/slices/view/src/androidTest/res/drawable/ic_lock.xml b/slices/view/src/androidTest/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..7a79428
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_lock.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector android:height="16dp" android:viewportHeight="24.0"
+    android:viewportWidth="24.0" android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#FF000000" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1s3.1,1.39 3.1,3.1v2L8.9,8L8.9,6zM18,20L6,20L6,10h12v10z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_right_caret.xml b/slices/view/src/androidTest/res/drawable/ic_right_caret.xml
new file mode 100644
index 0000000..3310e62
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_right_caret.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml
new file mode 100644
index 0000000..4e92a64
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_fair.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml
new file mode 100644
index 0000000..0b37310
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_full.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"/>
+</vector>
diff --git a/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml b/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml
new file mode 100644
index 0000000..87c84ce
--- /dev/null
+++ b/slices/view/src/androidTest/res/drawable/ic_wifi_low.xml
@@ -0,0 +1,29 @@
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
+        android:fillAlpha=".3"/>
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.67,14.86L12,21.49v0.01l0.01,-0.01 5.33,-6.63C17.06,14.65 15.03,13 12,13s-5.06,1.65 -5.33,1.86z"/>
+</vector>
diff --git a/slices/view/src/main/java/androidx/slice/widget/EventInfo.java b/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
index 35786c0..6cdee12 100644
--- a/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
+++ b/slices/view/src/main/java/androidx/slice/widget/EventInfo.java
@@ -55,7 +55,8 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @IntDef({
-            ACTION_TYPE_TOGGLE, ACTION_TYPE_BUTTON, ACTION_TYPE_SLIDER, ACTION_TYPE_CONTENT
+            ACTION_TYPE_TOGGLE, ACTION_TYPE_BUTTON, ACTION_TYPE_SLIDER, ACTION_TYPE_CONTENT,
+            ACTION_TYPE_SEE_MORE
     })
     public @interface SliceActionType{}
 
@@ -78,6 +79,10 @@
      * Indicates the event was a tap on the entire row.
      */
     public static final int ACTION_TYPE_CONTENT = 3;
+    /**
+     * Indicates the event was a tap on a see more button.
+     */
+    public static final int ACTION_TYPE_SEE_MORE = 4;
 
     /**
      * @hide
@@ -243,6 +248,8 @@
                 return "SLIDER";
             case ACTION_TYPE_CONTENT:
                 return "CONTENT";
+            case ACTION_TYPE_SEE_MORE:
+                return "SEE MORE";
             default:
                 return "unknown action: " + action;
         }
diff --git a/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java b/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
index 5c21a14..ada7b4b 100644
--- a/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
@@ -22,6 +22,7 @@
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import androidx.slice.Slice;
@@ -38,6 +39,8 @@
     private Slice mSlice;
     private boolean mIsScrollable;
     private ListContent mListContent;
+    private List<SliceItem> mDisplayedItems = new ArrayList<>();
+    private int mDisplayedItemsHeight = 0;
 
     public LargeTemplateView(Context context) {
         super(context);
@@ -49,8 +52,18 @@
     }
 
     @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int height = MeasureSpec.getSize(heightMeasureSpec);
+        if (mDisplayedItems.size() > 0 && mDisplayedItemsHeight > height) {
+            // Need to resize
+            updateDisplayedItems(height);
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    @Override
     public int getActualHeight() {
-        return mListContent != null ? mListContent.getListHeight() : 0;
+        return mDisplayedItemsHeight;
     }
 
     @Override
@@ -91,23 +104,46 @@
 
     private void populate() {
         if (mSlice == null) {
+            resetView();
             return;
         }
         mListContent = new ListContent(getContext(), mSlice);
-        mAdapter.setSliceItems(mListContent.getRowItems(), mTintColor);
+        updateDisplayedItems(getMeasuredHeight());
     }
 
     /**
      * Whether or not the content in this template should be scrollable.
      */
     public void setScrollable(boolean isScrollable) {
-        // TODO -- restrict / enable how much this view can show
         mIsScrollable = isScrollable;
+        updateDisplayedItems(getMeasuredHeight());
+    }
+
+    private void updateDisplayedItems(int height) {
+        if (mListContent == null) {
+            return;
+        }
+        if (!mIsScrollable) {
+            // If we're not scrollable we must cap the number of items we're displaying such
+            // that they fit in the available space
+            if (height == 0) {
+                // Not measured, use default
+                mDisplayedItems = mListContent.getItemsForNonScrollingList(-1);
+            } else {
+                mDisplayedItems = mListContent.getItemsForNonScrollingList(height);
+            }
+        } else {
+            mDisplayedItems = mListContent.getRowItems();
+        }
+        mDisplayedItemsHeight = ListContent.getListHeight(getContext(), mDisplayedItems);
+        mAdapter.setSliceItems(mDisplayedItems, mTintColor);
     }
 
     @Override
     public void resetView() {
         mSlice = null;
+        mDisplayedItemsHeight = 0;
+        mDisplayedItems.clear();
         mAdapter.setSliceItems(null, -1);
         mListContent = null;
     }
diff --git a/slices/view/src/main/java/androidx/slice/widget/ListContent.java b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
index d2915cd..2dd6375 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
@@ -19,6 +19,7 @@
 import static android.app.slice.Slice.HINT_ACTIONS;
 import static android.app.slice.Slice.HINT_HORIZONTAL;
 import static android.app.slice.Slice.HINT_LIST_ITEM;
+import static android.app.slice.Slice.HINT_SEE_MORE;
 import static android.app.slice.Slice.HINT_SHORTCUT;
 import static android.app.slice.Slice.SUBTYPE_COLOR;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
@@ -48,6 +49,7 @@
 
     private SliceItem mHeaderItem;
     private SliceItem mColorItem;
+    private SliceItem mSeeMoreItem;
     private ArrayList<SliceItem> mRowItems = new ArrayList<>();
     private List<SliceItem> mSliceActions;
     private Context mContext;
@@ -79,12 +81,13 @@
         if (mHeaderItem != null) {
             mRowItems.add(mHeaderItem);
         }
+        mSeeMoreItem = getSeeMoreItem(slice);
         // Filter + create row items
         List<SliceItem> children = slice.getItems();
         for (int i = 0; i < children.size(); i++) {
             final SliceItem child = children.get(i);
             final String format = child.getFormat();
-            if (!child.hasAnyHints(HINT_ACTIONS)
+            if (!child.hasAnyHints(HINT_ACTIONS, HINT_SEE_MORE)
                     && (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
                 if (mHeaderItem == null && !child.hasHint(HINT_LIST_ITEM)) {
                     mHeaderItem = child;
@@ -102,24 +105,70 @@
     }
 
     /**
-     * @return the total height of all the rows contained in this list.
+     * @return the total height of all the rows contained in the provided list.
      */
-    public int getListHeight() {
+    public static int getListHeight(Context context, List<SliceItem> listItems) {
         int height = 0;
-        for (int i = 0; i < mRowItems.size(); i++) {
-            SliceItem item = mRowItems.get(i);
-            if (item.hasHint(HINT_HORIZONTAL)) {
-                GridContent gc = new GridContent(mContext, item);
-                height += gc.getActualHeight();
-            } else {
-                RowContent rc = new RowContent(mContext, item, i == 0 /* isHeader */);
-                height += rc.getActualHeight();
-            }
+        for (int i = 0; i < listItems.size(); i++) {
+            height += getHeight(context, listItems.get(i), i == 0 /* isHeader */);
         }
         return height;
     }
 
     /**
+     * Returns a list of items that can be displayed in the provided height. If this list
+     * has a {@link #getSeeMoreItem()} this will be returned in the list if appropriate.
+     *
+     * @param height the height to restrict the items, -1 to use default sizings for non-scrolling
+     *               templates.
+     * @return the list of items that can be displayed in the provided  height.
+     */
+    @NonNull
+    public List<SliceItem> getItemsForNonScrollingList(int height) {
+        ArrayList<SliceItem> visibleItems = new ArrayList<>();
+        if (mRowItems == null || mRowItems.size() == 0) {
+            return visibleItems;
+        }
+        final int idealItemCount = hasHeader() ? 4 : 3;
+        final int minItemCount = hasHeader() ? 2 : 1;
+        int visibleHeight = 0;
+        // Need to show see more
+        if (mSeeMoreItem != null) {
+            RowContent rc = new RowContent(mContext, mSeeMoreItem, false /* isHeader */);
+            visibleHeight += rc.getActualHeight();
+        }
+        for (int i = 0; i < mRowItems.size(); i++) {
+            int itemHeight = getHeight(mContext, mRowItems.get(i), i == 0 /* isHeader */);
+            if ((height == -1 && i > idealItemCount)
+                    || (height > 0 && visibleHeight + itemHeight > height)) {
+                break;
+            } else {
+                visibleHeight += itemHeight;
+                visibleItems.add(mRowItems.get(i));
+            }
+        }
+        if (mSeeMoreItem != null && visibleItems.size() >= minItemCount) {
+            // Only add see more if we're at least showing one item and it's not the header
+            visibleItems.add(mSeeMoreItem);
+        }
+        if (visibleItems.size() == 0) {
+            // Didn't have enough space to show anything; should still show something
+            visibleItems.add(mRowItems.get(0));
+        }
+        return visibleItems;
+    }
+
+    private static int getHeight(Context context, SliceItem item, boolean isHeader) {
+        if (item.hasHint(HINT_HORIZONTAL)) {
+            GridContent gc = new GridContent(context, item);
+            return gc.getActualHeight();
+        } else {
+            RowContent rc = new RowContent(context, item, isHeader);
+            return rc.getActualHeight();
+        }
+    }
+
+    /**
      * @return whether this list has content that is valid to display.
      */
     public boolean isValid() {
@@ -141,6 +190,11 @@
         return mSliceActions;
     }
 
+    @Nullable
+    public SliceItem getSeeMoreItem() {
+        return mSeeMoreItem;
+    }
+
     public ArrayList<SliceItem> getRowItems() {
         return mRowItems;
     }
@@ -163,6 +217,21 @@
         return null;
     }
 
+    @Nullable
+    private static SliceItem getSeeMoreItem(@NonNull Slice slice) {
+        SliceItem item = SliceQuery.find(slice, null, HINT_SEE_MORE, null);
+        if (item != null && item.hasHint(HINT_SEE_MORE)) {
+            if (FORMAT_SLICE.equals(item.getFormat())) {
+                List<SliceItem> items = item.getSlice().getItems();
+                if (items.size() == 1 && FORMAT_ACTION.equals(items.get(0).getFormat())) {
+                    return items.get(0);
+                }
+                return item;
+            }
+        }
+        return null;
+    }
+
     private static boolean isValidHeader(SliceItem sliceItem) {
         if (FORMAT_SLICE.equals(sliceItem.getFormat()) && !sliceItem.hasHint(HINT_LIST_ITEM)
                 && !sliceItem.hasHint(HINT_ACTIONS)) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowContent.java b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
index cec8ddb..083101c 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowContent.java
@@ -17,6 +17,7 @@
 package androidx.slice.widget;
 
 import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_SEE_MORE;
 import static android.app.slice.Slice.HINT_SHORTCUT;
 import static android.app.slice.Slice.HINT_SUMMARY;
 import static android.app.slice.Slice.HINT_TITLE;
@@ -31,6 +32,7 @@
 import static androidx.slice.core.SliceHints.SUBTYPE_RANGE;
 
 import android.content.Context;
+import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
 import android.support.annotation.RestrictTo;
 import android.text.TextUtils;
@@ -52,6 +54,7 @@
     private static final String TAG = "RowContent";
 
     private SliceItem mPrimaryAction;
+    private SliceItem mRowSlice;
     private SliceItem mStartItem;
     private SliceItem mTitleItem;
     private SliceItem mSubtitleItem;
@@ -75,6 +78,7 @@
      */
     public void reset() {
         mPrimaryAction = null;
+        mRowSlice = null;
         mStartItem = null;
         mTitleItem = null;
         mSubtitleItem = null;
@@ -89,6 +93,7 @@
     private boolean populate(SliceItem rowSlice, boolean isHeader) {
         reset();
         mIsHeader = isHeader;
+        mRowSlice = rowSlice;
         if (!isValidRow(rowSlice)) {
             Log.w(TAG, "Provided SliceItem is invalid for RowContent");
             return false;
@@ -173,6 +178,14 @@
     }
 
     /**
+     * @return the {@link SliceItem} used to populate this row.
+     */
+    @NonNull
+    public SliceItem getSlice() {
+        return mRowSlice;
+    }
+
+    /**
      * @return the {@link SliceItem} representing the range in the row; can be null.
      */
     @Nullable
@@ -181,30 +194,32 @@
     }
 
     /**
-     * @return whether this row has content that is valid to display.
+     * @return the {@link SliceItem} used for the main intent for this row; can be null.
      */
-    public boolean isValid() {
-        return mStartItem != null
-                || mTitleItem != null
-                || mSubtitleItem != null
-                || mEndItems.size() > 0;
-    }
-
     @Nullable
     public SliceItem getPrimaryAction() {
         return mPrimaryAction;
     }
 
+    /**
+     * @return the {@link SliceItem} to display at the start of this row; can be null.
+     */
     @Nullable
     public SliceItem getStartItem() {
         return mIsHeader ? null : mStartItem;
     }
 
+    /**
+     * @return the {@link SliceItem} representing the title text for this row; can be null.
+     */
     @Nullable
     public SliceItem getTitleItem() {
         return mTitleItem;
     }
 
+    /**
+     * @return the {@link SliceItem} representing the subtitle text for this row; can be null.
+     */
     @Nullable
     public SliceItem getSubtitleItem() {
         return mSubtitleItem;
@@ -215,6 +230,9 @@
         return mSummaryItem == null ? mSubtitleItem : mSummaryItem;
     }
 
+    /**
+     * @return the list of {@link SliceItem} that can be shown as items at the end of the row.
+     */
     public ArrayList<SliceItem> getEndItems() {
         return mEndItems;
     }
@@ -254,6 +272,26 @@
     }
 
     /**
+     * @return whether this row content represents a default see more item.
+     */
+    public boolean isDefaultSeeMore() {
+        return FORMAT_ACTION.equals(mRowSlice.getFormat())
+                && mRowSlice.getSlice().hasHint(HINT_SEE_MORE)
+                && mRowSlice.getSlice().getItems().isEmpty();
+    }
+
+    /**
+     * @return whether this row has content that is valid to display.
+     */
+    public boolean isValid() {
+        return mStartItem != null
+                || mTitleItem != null
+                || mSubtitleItem != null
+                || mEndItems.size() > 0
+                || isDefaultSeeMore();
+    }
+
+    /**
      * @return whether this is a valid item to use to populate a row of content.
      */
     private static boolean isValidRow(SliceItem rowSlice) {
@@ -270,10 +308,18 @@
                     return true;
                 }
             }
+            // Special case: default see more just has an action but no other items
+            if (rowSlice.hasHint(HINT_SEE_MORE) && rowItems.isEmpty()) {
+                return true;
+            }
         }
         return false;
     }
 
+    /**
+     * @return list of {@link SliceItem}s that are valid to display in a row according
+     * to {@link #isValidRowContent(SliceItem, SliceItem)}.
+     */
     private static ArrayList<SliceItem> filterInvalidItems(SliceItem rowSlice) {
         ArrayList<SliceItem> filteredList = new ArrayList<>();
         for (SliceItem i : rowSlice.getSlice().getItems()) {
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 9668584..7f522d3 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -40,8 +40,10 @@
 import android.support.annotation.RestrictTo;
 import android.util.Log;
 import android.util.TypedValue;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
 import android.widget.CompoundButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -82,6 +84,7 @@
     private LinearLayout mEndContainer;
     private SeekBar mSeekBar;
     private ProgressBar mProgressBar;
+    private View mSeeMoreView;
 
     private int mRowIndex;
     private RowContent mRowContent;
@@ -173,6 +176,11 @@
 
     private void populateViews() {
         resetView();
+        if (mRowContent.isDefaultSeeMore()) {
+            showSeeMore();
+            return;
+        }
+
         boolean showStart = false;
         final SliceItem startItem = mRowContent.getStartItem();
         if (startItem != null) {
@@ -454,6 +462,31 @@
         return addedView != null;
     }
 
+    private void showSeeMore() {
+        Button b = (Button) LayoutInflater.from(getContext()).inflate(
+                R.layout.abc_slice_row_show_more, this, false);
+        b.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    if (mObserver != null) {
+                        EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_SEE_MORE,
+                                EventInfo.ROW_TYPE_LIST, mRowIndex);
+                        mObserver.onSliceAction(info, mRowContent.getSlice());
+                    }
+                    mRowContent.getSlice().getAction().send();
+                } catch (CanceledException e) {
+                    Log.w(TAG, "PendingIntent for slice cannot be sent", e);
+                }
+            }
+        });
+        if (mTintColor != -1) {
+            b.setTextColor(mTintColor);
+        }
+        mSeeMoreView = b;
+        addView(mSeeMoreView);
+    }
+
     @Override
     public void onClick(View view) {
         if (mRowAction != null && mRowAction.getActionItem() != null && !mRowAction.isToggle()) {
@@ -494,5 +527,8 @@
         mDivider.setVisibility(View.GONE);
         mSeekBar.setVisibility(View.GONE);
         mProgressBar.setVisibility(View.GONE);
+        if (mSeeMoreView != null) {
+            removeView(mSeeMoreView);
+        }
     }
 }
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceView.java b/slices/view/src/main/java/androidx/slice/widget/SliceView.java
index 4a53b9d..df786b3 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceView.java
@@ -192,16 +192,17 @@
         final int heightAvailable = MeasureSpec.getSize(heightMeasureSpec);
         final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         int height = heightAvailable;
-        if (heightAvailable >= sliceHeight) {
-            // Available space is larger than the slice
-            if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
-                height = sliceHeight;
+        if (heightAvailable >= sliceHeight || heightMode == MeasureSpec.UNSPECIFIED) {
+            // Available space is larger than the slice or we be what we want
+            if (heightMode != MeasureSpec.EXACTLY) {
+                int maxHeight = mIsScrollable ? mMinLargeHeight + actionHeight : sliceHeight;
+                height = Math.min(maxHeight, sliceHeight);
             }
         } else {
             // Not enough space available for slice in current mode
             if (getMode() == MODE_LARGE && heightAvailable >= mMinLargeHeight + actionHeight) {
                 // It's just a slice with scrolling content; cap it to height available.
-                height = heightAvailable;
+                height = Math.min(mMinLargeHeight + actionHeight, heightAvailable);
             } else if (getMode() == MODE_SHORTCUT) {
                 // TODO: consider scaling the shortcut to fit if too small
                 height = mShortcutSize;
diff --git a/slices/view/src/main/res/layout/abc_slice_row_show_more.xml b/slices/view/src/main/res/layout/abc_slice_row_show_more.xml
new file mode 100644
index 0000000..ef65f85
--- /dev/null
+++ b/slices/view/src/main/res/layout/abc_slice_row_show_more.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright 2018 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.
+  -->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="end"
+        style="?android:attr/borderlessButtonStyle"
+        android:text="@string/abc_slice_show_more"/>
\ No newline at end of file
diff --git a/slices/view/src/main/res/values/strings.xml b/slices/view/src/main/res/values/strings.xml
index b72c986..f73c6cc 100644
--- a/slices/view/src/main/res/values/strings.xml
+++ b/slices/view/src/main/res/values/strings.xml
@@ -18,4 +18,6 @@
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <!-- Format string for indicating there is more content in a slice view -->
     <string name="abc_slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
+    <!-- String to indicate there is more content to display in a list [CHAR LIMIT=none] -->
+    <string name="abc_slice_show_more">Show more</string>
 </resources>
\ No newline at end of file
diff --git a/slidingpanelayout/api/0.0.0.txt b/slidingpanelayout/api/0.0.0.txt
new file mode 100644
index 0000000..07e71d9
--- /dev/null
+++ b/slidingpanelayout/api/0.0.0.txt
@@ -0,0 +1,54 @@
+package android.support.v4.widget {
+
+  public class SlidingPaneLayout extends android.view.ViewGroup {
+    ctor public SlidingPaneLayout(android.content.Context);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet);
+    ctor public SlidingPaneLayout(android.content.Context, android.util.AttributeSet, int);
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public deprecated boolean canSlide();
+    method public boolean closePane();
+    method public int getCoveredFadeColor();
+    method public int getParallaxDistance();
+    method public int getSliderFadeColor();
+    method public boolean isOpen();
+    method public boolean isSlideable();
+    method public boolean openPane();
+    method public void setCoveredFadeColor(int);
+    method public void setPanelSlideListener(android.support.v4.widget.SlidingPaneLayout.PanelSlideListener);
+    method public void setParallaxDistance(int);
+    method public deprecated void setShadowDrawable(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableLeft(android.graphics.drawable.Drawable);
+    method public void setShadowDrawableRight(android.graphics.drawable.Drawable);
+    method public deprecated void setShadowResource(int);
+    method public void setShadowResourceLeft(int);
+    method public void setShadowResourceRight(int);
+    method public void setSliderFadeColor(int);
+    method public deprecated void smoothSlideClosed();
+    method public deprecated void smoothSlideOpen();
+  }
+
+  public static class SlidingPaneLayout.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public SlidingPaneLayout.LayoutParams();
+    ctor public SlidingPaneLayout.LayoutParams(int, int);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.support.v4.widget.SlidingPaneLayout.LayoutParams);
+    ctor public SlidingPaneLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public float weight;
+  }
+
+  public static abstract interface SlidingPaneLayout.PanelSlideListener {
+    method public abstract void onPanelClosed(android.view.View);
+    method public abstract void onPanelOpened(android.view.View);
+    method public abstract void onPanelSlide(android.view.View, float);
+  }
+
+  public static class SlidingPaneLayout.SimplePanelSlideListener implements android.support.v4.widget.SlidingPaneLayout.PanelSlideListener {
+    ctor public SlidingPaneLayout.SimplePanelSlideListener();
+    method public void onPanelClosed(android.view.View);
+    method public void onPanelOpened(android.view.View);
+    method public void onPanelSlide(android.view.View, float);
+  }
+
+}
+
diff --git a/slidingpanelayout/build.gradle b/slidingpanelayout/build.gradle
index d084e63..4e24b3f 100644
--- a/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/swiperefreshlayout/api/0.0.0.txt b/swiperefreshlayout/api/0.0.0.txt
new file mode 100644
index 0000000..ce68f0b
--- /dev/null
+++ b/swiperefreshlayout/api/0.0.0.txt
@@ -0,0 +1,76 @@
+package android.support.v4.widget {
+
+  public class CircularProgressDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable {
+    ctor public CircularProgressDrawable(android.content.Context);
+    method public void draw(android.graphics.Canvas);
+    method public boolean getArrowEnabled();
+    method public float getArrowHeight();
+    method public float getArrowScale();
+    method public float getArrowWidth();
+    method public int getBackgroundColor();
+    method public float getCenterRadius();
+    method public int[] getColorSchemeColors();
+    method public float getEndTrim();
+    method public int getOpacity();
+    method public float getProgressRotation();
+    method public float getStartTrim();
+    method public android.graphics.Paint.Cap getStrokeCap();
+    method public float getStrokeWidth();
+    method public boolean isRunning();
+    method public void setAlpha(int);
+    method public void setArrowDimensions(float, float);
+    method public void setArrowEnabled(boolean);
+    method public void setArrowScale(float);
+    method public void setBackgroundColor(int);
+    method public void setCenterRadius(float);
+    method public void setColorFilter(android.graphics.ColorFilter);
+    method public void setColorSchemeColors(int...);
+    method public void setProgressRotation(float);
+    method public void setStartEndTrim(float, float);
+    method public void setStrokeCap(android.graphics.Paint.Cap);
+    method public void setStrokeWidth(float);
+    method public void setStyle(int);
+    method public void start();
+    method public void stop();
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+  }
+
+  public class SwipeRefreshLayout extends android.view.ViewGroup implements android.support.v4.view.NestedScrollingChild android.support.v4.view.NestedScrollingParent {
+    ctor public SwipeRefreshLayout(android.content.Context);
+    ctor public SwipeRefreshLayout(android.content.Context, android.util.AttributeSet);
+    method public boolean canChildScrollUp();
+    method public int getProgressCircleDiameter();
+    method public int getProgressViewEndOffset();
+    method public int getProgressViewStartOffset();
+    method public boolean isRefreshing();
+    method public void onMeasure(int, int);
+    method public deprecated void setColorScheme(int...);
+    method public void setColorSchemeColors(int...);
+    method public void setColorSchemeResources(int...);
+    method public void setDistanceToTriggerSync(int);
+    method public void setOnChildScrollUpCallback(android.support.v4.widget.SwipeRefreshLayout.OnChildScrollUpCallback);
+    method public void setOnRefreshListener(android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener);
+    method public deprecated void setProgressBackgroundColor(int);
+    method public void setProgressBackgroundColorSchemeColor(int);
+    method public void setProgressBackgroundColorSchemeResource(int);
+    method public void setProgressViewEndTarget(boolean, int);
+    method public void setProgressViewOffset(boolean, int, int);
+    method public void setRefreshing(boolean);
+    method public void setSize(int);
+    field public static final int DEFAULT = 1; // 0x1
+    field public static final int LARGE = 0; // 0x0
+    field protected int mFrom;
+    field protected int mOriginalOffsetTop;
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnChildScrollUpCallback {
+    method public abstract boolean canChildScrollUp(android.support.v4.widget.SwipeRefreshLayout, android.view.View);
+  }
+
+  public static abstract interface SwipeRefreshLayout.OnRefreshListener {
+    method public abstract void onRefresh();
+  }
+
+}
+
diff --git a/swiperefreshlayout/build.gradle b/swiperefreshlayout/build.gradle
index 0479bbe..6654e94 100644
--- a/swiperefreshlayout/build.gradle
+++ b/swiperefreshlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
     androidTestImplementation(ESPRESSO_CONTRIB, libs.exclude_support)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'swiperefreshlayout'
     }
 }
diff --git a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
index fe53293..96c2dac 100644
--- a/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
+++ b/swiperefreshlayout/src/androidTest/java/android/support/v4/widget/SwipeRefreshLayoutTest.java
@@ -39,7 +39,6 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.view.View;
 
 import org.junit.Before;
@@ -50,6 +49,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.testutils.PollingCheck;
+
 /**
  * Tests SwipeRefreshLayout widget.
  */
diff --git a/testutils/build.gradle b/testutils/build.gradle
index d75b6b7..d32244f 100644
--- a/testutils/build.gradle
+++ b/testutils/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/testutils/src/main/AndroidManifest.xml b/testutils/src/main/AndroidManifest.xml
index 4d2fd19..2feb440 100644
--- a/testutils/src/main/AndroidManifest.xml
+++ b/testutils/src/main/AndroidManifest.xml
@@ -14,4 +14,4 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
   -->
-<manifest package="android.support.testutils"/>
+<manifest package="androidx.testutils"/>
diff --git a/testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java b/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java
rename to testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
index 49ccc1b..e36a2ec 100644
--- a/testutils/src/main/java/android/support/testutils/AppCompatActivityUtils.java
+++ b/testutils/src/main/java/androidx/testutils/AppCompatActivityUtils.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.testutils;
+package androidx.testutils;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java b/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java
rename to testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
index 7d12deb..a4b67e7 100644
--- a/testutils/src/main/java/android/support/testutils/FragmentActivityUtils.java
+++ b/testutils/src/main/java/androidx/testutils/FragmentActivityUtils.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.support.testutils;
+package androidx.testutils;
 
 import static org.junit.Assert.assertTrue;
 
diff --git a/testutils/src/main/java/android/support/testutils/PollingCheck.java b/testutils/src/main/java/androidx/testutils/PollingCheck.java
similarity index 98%
rename from testutils/src/main/java/android/support/testutils/PollingCheck.java
rename to testutils/src/main/java/androidx/testutils/PollingCheck.java
index 8e85896..8fd4852 100644
--- a/testutils/src/main/java/android/support/testutils/PollingCheck.java
+++ b/testutils/src/main/java/androidx/testutils/PollingCheck.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.testutils;
+package androidx.testutils;
 
 import org.junit.Assert;
 
diff --git a/testutils/src/main/java/android/support/testutils/RecreatedActivity.java b/testutils/src/main/java/androidx/testutils/RecreatedActivity.java
similarity index 97%
rename from testutils/src/main/java/android/support/testutils/RecreatedActivity.java
rename to testutils/src/main/java/androidx/testutils/RecreatedActivity.java
index aaea3a9..8430dca 100644
--- a/testutils/src/main/java/android/support/testutils/RecreatedActivity.java
+++ b/testutils/src/main/java/androidx/testutils/RecreatedActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.testutils;
+package androidx.testutils;
 
 import android.os.Bundle;
 import android.support.annotation.Nullable;
diff --git a/testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
similarity index 97%
rename from testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java
rename to testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
index d5645a3..1a48cf8 100644
--- a/testutils/src/main/java/android/support/testutils/RecreatedAppCompatActivity.java
+++ b/testutils/src/main/java/androidx/testutils/RecreatedAppCompatActivity.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.support.testutils;
+package androidx.testutils;
 
 import android.os.Bundle;
 import android.support.annotation.Nullable;
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
index b01cbbf..a6e57de 100644
--- a/textclassifier/build.gradle
+++ b/textclassifier/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/transition/build.gradle b/transition/build.gradle
index d8257ab..c413a73 100644
--- a/transition/build.gradle
+++ b/transition/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/transition/proguard-rules.pro b/transition/proguard-rules.pro
index 6cae5e6..dda2c4e 100644
--- a/transition/proguard-rules.pro
+++ b/transition/proguard-rules.pro
@@ -12,10 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# FragmentTransitionSupport is instantiated in support-fragment via reflection.
--keep public class android.support.transition.FragmentTransitionSupport {
-}
-
 # Keep a field in transition that is used to keep a reference to weakly-referenced object
 -keepclassmembers class android.support.transition.ChangeBounds$* extends android.animation.AnimatorListenerAdapter {
   android.support.transition.ChangeBounds$ViewBounds mViewBounds;
diff --git a/tv-provider/api/current.txt b/tv-provider/api/current.txt
index c486190..ee11d8f 100644
--- a/tv-provider/api/current.txt
+++ b/tv-provider/api/current.txt
@@ -77,10 +77,68 @@
     method public static boolean storeChannelLogo(android.content.Context, long, android.graphics.Bitmap);
   }
 
+  public class PreviewChannel {
+    method public static android.support.media.tv.PreviewChannel fromCursor(android.database.Cursor);
+    method public android.content.Intent getAppLinkIntent() throws java.net.URISyntaxException;
+    method public android.net.Uri getAppLinkIntentUri();
+    method public java.lang.CharSequence getDescription();
+    method public java.lang.CharSequence getDisplayName();
+    method public long getId();
+    method public byte[] getInternalProviderDataByteArray();
+    method public java.lang.Long getInternalProviderFlag1();
+    method public java.lang.Long getInternalProviderFlag2();
+    method public java.lang.Long getInternalProviderFlag3();
+    method public java.lang.Long getInternalProviderFlag4();
+    method public java.lang.String getInternalProviderId();
+    method public android.graphics.Bitmap getLogo(android.content.Context);
+    method public java.lang.String getPackageName();
+    method public java.lang.String getType();
+    method public boolean hasAnyUpdatedValues(android.support.media.tv.PreviewChannel);
+    method public boolean isBrowsable();
+  }
+
+  public static final class PreviewChannel.Builder {
+    ctor public PreviewChannel.Builder();
+    ctor public PreviewChannel.Builder(android.support.media.tv.PreviewChannel);
+    method public android.support.media.tv.PreviewChannel build();
+    method public android.support.media.tv.PreviewChannel.Builder setAppLinkIntent(android.content.Intent);
+    method public android.support.media.tv.PreviewChannel.Builder setAppLinkIntentUri(android.net.Uri);
+    method public android.support.media.tv.PreviewChannel.Builder setDescription(java.lang.CharSequence);
+    method public android.support.media.tv.PreviewChannel.Builder setDisplayName(java.lang.CharSequence);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderData(byte[]);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag1(long);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag2(long);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag3(long);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderFlag4(long);
+    method public android.support.media.tv.PreviewChannel.Builder setInternalProviderId(java.lang.String);
+    method public android.support.media.tv.PreviewChannel.Builder setLogo(android.graphics.Bitmap);
+    method public android.support.media.tv.PreviewChannel.Builder setLogo(android.net.Uri);
+  }
+
+  public class PreviewChannelHelper {
+    ctor public PreviewChannelHelper(android.content.Context);
+    ctor public PreviewChannelHelper(android.content.Context, int, int);
+    method public void deletePreviewChannel(long);
+    method public void deletePreviewProgram(long);
+    method protected android.graphics.Bitmap downloadBitmap(android.net.Uri) throws java.io.IOException;
+    method public java.util.List<android.support.media.tv.PreviewChannel> getAllChannels();
+    method public android.support.media.tv.PreviewChannel getPreviewChannel(long);
+    method public android.support.media.tv.PreviewProgram getPreviewProgram(long);
+    method public android.support.media.tv.WatchNextProgram getWatchNextProgram(long);
+    method public long publishChannel(android.support.media.tv.PreviewChannel) throws java.io.IOException;
+    method public long publishDefaultChannel(android.support.media.tv.PreviewChannel) throws java.io.IOException;
+    method public long publishPreviewProgram(android.support.media.tv.PreviewProgram);
+    method public long publishWatchNextProgram(android.support.media.tv.WatchNextProgram);
+    method public void updatePreviewChannel(long, android.support.media.tv.PreviewChannel) throws java.io.IOException;
+    method public void updatePreviewProgram(long, android.support.media.tv.PreviewProgram);
+    method public void updateWatchNextProgram(android.support.media.tv.WatchNextProgram, long);
+  }
+
   public final class PreviewProgram {
     method public static android.support.media.tv.PreviewProgram fromCursor(android.database.Cursor);
     method public long getChannelId();
     method public int getWeight();
+    method public boolean hasAnyUpdatedValues(android.support.media.tv.PreviewProgram);
     method public android.content.ContentValues toContentValues();
   }
 
@@ -529,6 +587,7 @@
     method public static android.support.media.tv.WatchNextProgram fromCursor(android.database.Cursor);
     method public long getLastEngagementTimeUtcMillis();
     method public int getWatchNextType();
+    method public boolean hasAnyUpdatedValues(android.support.media.tv.WatchNextProgram);
     method public android.content.ContentValues toContentValues();
     field public static final int WATCH_NEXT_TYPE_UNKNOWN = -1; // 0xffffffff
   }
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index a8057c0..eb8cbd5 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -12,6 +12,7 @@
 
     androidTestImplementation(TEST_RUNNER)
     androidTestImplementation(TEST_RULES)
+    androidTestImplementation(MOCKITO_CORE)
 }
 
 supportLibrary {
diff --git a/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java
new file mode 100644
index 0000000..679e0ee
--- /dev/null
+++ b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelHelperTest.java
@@ -0,0 +1,612 @@
+/*
+ * Copyright 2018 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.media.tv;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.tv.TvContentRating;
+import android.net.Uri;
+import android.os.Build;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Test that {@link PreviewChannelHelper} can perform CRUD operations on
+ * {@link PreviewChannel PreviewChannels} and {@link PreviewProgram PreviewPrograms} correctly.
+ * All of the following tests involve the system content provider.
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(JUnit4.class)
+public class PreviewChannelHelperTest {
+
+
+    private Context mContext;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    /**
+     * taken from {@link PreviewProgram}
+     */
+    private static PreviewProgram.Builder createFullyPopulatedPreviewProgram(long channelId) {
+        return new PreviewProgram.Builder()
+                .setTitle("Google")
+                .setInternalProviderId("ID-4321")
+                .setChannelId(channelId)
+                .setWeight(100)
+                .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+                .setLastPlaybackPositionMillis(0)
+                .setDurationMillis(60 * 1000)
+                .setIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+                        Intent.URI_INTENT_SCHEME)))
+                .setTransient(false)
+                .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE)
+                .setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3)
+                .setThumbnailAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_16_9)
+                .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+                .setAvailability(TvContractCompat.PreviewPrograms.AVAILABILITY_AVAILABLE)
+                .setStartingPrice("12.99 USD")
+                .setOfferPrice("4.99 USD")
+                .setReleaseDate("1997")
+                .setItemCount(3)
+                .setLive(false)
+                .setInteractionType(TvContractCompat.PreviewPrograms.INTERACTION_TYPE_LIKES)
+                .setInteractionCount(10200)
+                .setAuthor("author_name")
+                .setReviewRatingStyle(TvContractCompat.PreviewPrograms.REVIEW_RATING_STYLE_STARS)
+                .setReviewRating("4.5")
+                .setSearchable(false)
+                .setThumbnailUri(Uri.parse("http://example.com/thumbnail.png"))
+                .setAudioLanguages(new String[]{"eng", "kor"})
+                .setCanonicalGenres(new String[]{TvContractCompat.Programs.Genres.MOVIES})
+                .setContentRatings(new TvContentRating[]{
+                        TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7")})
+                .setDescription("This is a sample program")
+                .setEpisodeNumber("Pilot", 0)
+                .setEpisodeTitle("Hello World")
+                .setLongDescription("This is a longer description than the previous description")
+                .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+                .setSeasonNumber("The Final Season", 7)
+                .setSeasonTitle("The Final Season")
+                .setVideoHeight(1080)
+                .setVideoWidth(1920)
+                .setInternalProviderFlag1(0x4)
+                .setInternalProviderFlag2(0x3)
+                .setInternalProviderFlag3(0x2)
+                .setInternalProviderFlag4(0x1)
+                .setBrowsable(true)
+                .setContentId("CID-8642");
+    }
+
+    private static void compareProgram(PreviewProgram programA, PreviewProgram programB) {
+        assertTrue(Arrays.equals(programA.getAudioLanguages(), programB.getAudioLanguages()));
+        assertTrue(Arrays.deepEquals(programA.getCanonicalGenres(), programB.getCanonicalGenres()));
+        assertEquals(programA.getChannelId(), programB.getChannelId());
+        assertTrue(Arrays.deepEquals(programA.getContentRatings(), programB.getContentRatings()));
+        assertEquals(programA.getDescription(), programB.getDescription());
+        assertEquals(programA.getEpisodeNumber(), programB.getEpisodeNumber());
+        assertEquals(programA.getEpisodeTitle(), programB.getEpisodeTitle());
+        assertEquals(programA.getLongDescription(), programB.getLongDescription());
+        assertEquals(programA.getPosterArtUri(), programB.getPosterArtUri());
+        assertEquals(programA.getSeasonNumber(), programB.getSeasonNumber());
+        assertEquals(programA.getThumbnailUri(), programB.getThumbnailUri());
+        assertEquals(programA.getTitle(), programB.getTitle());
+        assertEquals(programA.getVideoHeight(), programB.getVideoHeight());
+        assertEquals(programA.getVideoWidth(), programB.getVideoWidth());
+        assertEquals(programA.isSearchable(), programB.isSearchable());
+        assertEquals(programA.getInternalProviderFlag1(), programB.getInternalProviderFlag1());
+        assertEquals(programA.getInternalProviderFlag2(), programB.getInternalProviderFlag2());
+        assertEquals(programA.getInternalProviderFlag3(), programB.getInternalProviderFlag3());
+        assertEquals(programA.getInternalProviderFlag4(), programB.getInternalProviderFlag4());
+        assertTrue(Objects.equals(programA.getSeasonTitle(), programB.getSeasonTitle()));
+        assertEquals(programA.getInternalProviderId(), programB.getInternalProviderId());
+        assertEquals(programA.getPreviewVideoUri(), programB.getPreviewVideoUri());
+        assertEquals(programA.getLastPlaybackPositionMillis(),
+                programB.getLastPlaybackPositionMillis());
+        assertEquals(programA.getDurationMillis(), programB.getDurationMillis());
+        assertEquals(programA.getIntentUri(), programB.getIntentUri());
+        assertEquals(programA.getWeight(), programB.getWeight());
+        assertEquals(programA.isTransient(), programB.isTransient());
+        assertEquals(programA.getType(), programB.getType());
+        assertEquals(programA.getPosterArtAspectRatio(), programB.getPosterArtAspectRatio());
+        assertEquals(programA.getThumbnailAspectRatio(), programB.getThumbnailAspectRatio());
+        assertEquals(programA.getLogoUri(), programB.getLogoUri());
+        assertEquals(programA.getAvailability(), programB.getAvailability());
+        assertEquals(programA.getStartingPrice(), programB.getStartingPrice());
+        assertEquals(programA.getOfferPrice(), programB.getOfferPrice());
+        assertEquals(programA.getReleaseDate(), programB.getReleaseDate());
+        assertEquals(programA.getItemCount(), programB.getItemCount());
+        assertEquals(programA.isLive(), programB.isLive());
+        assertEquals(programA.getInteractionType(), programB.getInteractionType());
+        assertEquals(programA.getInteractionCount(), programB.getInteractionCount());
+        assertEquals(programA.getAuthor(), programB.getAuthor());
+        assertEquals(programA.getReviewRatingStyle(), programB.getReviewRatingStyle());
+        assertEquals(programA.getReviewRating(), programB.getReviewRating());
+        assertEquals(programA.getContentId(), programB.getContentId());
+    }
+
+    private static WatchNextProgram.Builder createFullyPopulatedWatchNextProgram() {
+        return new WatchNextProgram.Builder()
+                .setTitle("Google")
+                .setInternalProviderId("ID-4321")
+                .setPreviewVideoUri(Uri.parse("http://example.com/preview-video.mpg"))
+                .setLastPlaybackPositionMillis(0)
+                .setDurationMillis(60 * 1000)
+                .setIntentUri(Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(
+                        Intent.URI_INTENT_SCHEME)))
+                .setTransient(false)
+                .setType(TvContractCompat.WatchNextPrograms.TYPE_MOVIE)
+                .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE)
+                .setPosterArtAspectRatio(TvContractCompat.WatchNextPrograms.ASPECT_RATIO_2_3)
+                .setThumbnailAspectRatio(TvContractCompat.WatchNextPrograms.ASPECT_RATIO_16_9)
+                .setLogoUri(Uri.parse("http://example.com/program-logo.mpg"))
+                .setAvailability(TvContractCompat.WatchNextPrograms.AVAILABILITY_AVAILABLE)
+                .setStartingPrice("12.99 USD")
+                .setOfferPrice("4.99 USD")
+                .setReleaseDate("1997")
+                .setItemCount(3)
+                .setLive(false)
+                .setInteractionType(TvContractCompat.WatchNextPrograms.INTERACTION_TYPE_LIKES)
+                .setInteractionCount(10200)
+                .setAuthor("author_name")
+                .setReviewRatingStyle(TvContractCompat.WatchNextPrograms.REVIEW_RATING_STYLE_STARS)
+                .setReviewRating("4.5")
+                .setSearchable(false)
+                .setThumbnailUri(Uri.parse("http://example.com/thumbnail.png"))
+                .setAudioLanguages(new String[]{"eng", "kor"})
+                .setCanonicalGenres(new String[]{TvContractCompat.Programs.Genres.MOVIES})
+                .setContentRatings(new TvContentRating[]{
+                        TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7")})
+                .setDescription("This is a sample program")
+                .setEpisodeNumber("Pilot", 0)
+                .setEpisodeTitle("Hello World")
+                .setLongDescription("This is a longer description than the previous description")
+                .setPosterArtUri(Uri.parse("http://example.com/poster.png"))
+                .setSeasonNumber("The Final Season", 7)
+                .setSeasonTitle("The Final Season")
+                .setVideoHeight(1080)
+                .setVideoWidth(1920)
+                .setInternalProviderFlag1(0x4)
+                .setInternalProviderFlag2(0x3)
+                .setInternalProviderFlag3(0x2)
+                .setInternalProviderFlag4(0x1)
+                .setBrowsable(true)
+                .setContentId("CID-8442");
+    }
+
+    private static void compareProgram(WatchNextProgram programA, WatchNextProgram programB) {
+        assertTrue(Arrays.equals(programA.getAudioLanguages(), programB.getAudioLanguages()));
+        assertTrue(Arrays.deepEquals(programA.getCanonicalGenres(), programB.getCanonicalGenres()));
+        assertTrue(Arrays.deepEquals(programA.getContentRatings(), programB.getContentRatings()));
+        assertEquals(programA.getDescription(), programB.getDescription());
+        assertEquals(programA.getEpisodeNumber(), programB.getEpisodeNumber());
+        assertEquals(programA.getEpisodeTitle(), programB.getEpisodeTitle());
+        assertEquals(programA.getLongDescription(), programB.getLongDescription());
+        assertEquals(programA.getPosterArtUri(), programB.getPosterArtUri());
+        assertEquals(programA.getSeasonNumber(), programB.getSeasonNumber());
+        assertEquals(programA.getThumbnailUri(), programB.getThumbnailUri());
+        assertEquals(programA.getTitle(), programB.getTitle());
+        assertEquals(programA.getVideoHeight(), programB.getVideoHeight());
+        assertEquals(programA.getVideoWidth(), programB.getVideoWidth());
+        assertEquals(programA.isSearchable(), programB.isSearchable());
+        assertEquals(programA.getInternalProviderFlag1(), programB.getInternalProviderFlag1());
+        assertEquals(programA.getInternalProviderFlag2(), programB.getInternalProviderFlag2());
+        assertEquals(programA.getInternalProviderFlag3(), programB.getInternalProviderFlag3());
+        assertEquals(programA.getInternalProviderFlag4(), programB.getInternalProviderFlag4());
+        assertTrue(Objects.equals(programA.getSeasonTitle(), programB.getSeasonTitle()));
+        assertEquals(programA.getInternalProviderId(), programB.getInternalProviderId());
+        assertEquals(programA.getPreviewVideoUri(), programB.getPreviewVideoUri());
+        assertEquals(programA.getLastPlaybackPositionMillis(),
+                programB.getLastPlaybackPositionMillis());
+        assertEquals(programA.getDurationMillis(), programB.getDurationMillis());
+        assertEquals(programA.getIntentUri(), programB.getIntentUri());
+        assertEquals(programA.isTransient(), programB.isTransient());
+        assertEquals(programA.getType(), programB.getType());
+        assertEquals(programA.getWatchNextType(), programB.getWatchNextType());
+        assertEquals(programA.getPosterArtAspectRatio(), programB.getPosterArtAspectRatio());
+        assertEquals(programA.getThumbnailAspectRatio(), programB.getThumbnailAspectRatio());
+        assertEquals(programA.getLogoUri(), programB.getLogoUri());
+        assertEquals(programA.getAvailability(), programB.getAvailability());
+        assertEquals(programA.getStartingPrice(), programB.getStartingPrice());
+        assertEquals(programA.getOfferPrice(), programB.getOfferPrice());
+        assertEquals(programA.getReleaseDate(), programB.getReleaseDate());
+        assertEquals(programA.getItemCount(), programB.getItemCount());
+        assertEquals(programA.isLive(), programB.isLive());
+        assertEquals(programA.getInteractionType(), programB.getInteractionType());
+        assertEquals(programA.getInteractionCount(), programB.getInteractionCount());
+        assertEquals(programA.getAuthor(), programB.getAuthor());
+        assertEquals(programA.getReviewRatingStyle(), programB.getReviewRatingStyle());
+        assertEquals(programA.getReviewRating(), programB.getReviewRating());
+        assertEquals(programA.getContentId(), programB.getContentId());
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+
+    }
+
+    @After
+    public void tearDown() {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        mContext.getContentResolver().delete(
+                TvContractCompat.Channels.CONTENT_URI, null, null);
+        mContext = null;
+    }
+
+    /**
+     * Test CR of CRUD
+     * Test that the PreviewChannelHelper can correctly create and read preview channels.
+     */
+    @Test
+    public void testPreviewChannelCreation() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishDefaultChannel(builder.build());
+        PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+        assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+    }
+
+    @Test
+    public void testLogoRequiredForChannelCreation() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        builder.setLogo(Uri.parse("bogus"));
+        thrown.expect(IOException.class);
+        helper.publishDefaultChannel(builder.build());
+        List<PreviewChannel> channels = helper.getAllChannels();
+        assertEquals(0, channels.size());
+    }
+
+    /**
+     * Test CR of CRUD
+     * Test that the PreviewChannelHelper can correctly create and read preview channels, when
+     * internalProviderId is null.
+     */
+    @Test
+    public void testPreviewChannelCreationWithNullProviderId() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        builder.setInternalProviderId(null);
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        long channelId = helper.publishChannel(builder.build());
+        PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+        assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+    }
+
+    /**
+     * All this method is actually doing is
+     * <pre>
+     *
+     *     PreviewChannel channelFromTvProvider = helper.getPreviewChannel(channelId);
+     * </pre>
+     * However, due to a known issue, when logo is persisted, the file status is not consistent
+     * between openInputStream and openOutputStream. So as a workaround, a wait period is applied
+     * to make sure that the logo file is written into the disk.
+     */
+    private PreviewChannel getPreviewChannel(PreviewChannelHelper helper,
+            long channelId) {
+        boolean logoReady = false;
+        PreviewChannel channel = null;
+        while (!logoReady) {
+            try {
+                Thread.sleep(50);
+            } catch (InterruptedException e) {
+            }
+            channel = helper.getPreviewChannel(channelId);
+            logoReady = null != channel.getLogo(mContext);
+        }
+        return channel;
+    }
+
+    /**
+     * Test CR of CRUD
+     * Test that all published preview channels can be read at once.
+     */
+    @Test
+    public void testAllPublishedChannelsRead() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        builder.setInternalProviderId("1");
+        helper.publishChannel(builder.build());
+        builder.setInternalProviderId("11");
+        helper.publishChannel(builder.build());
+        builder.setInternalProviderId("111");
+        helper.publishChannel(builder.build());
+        builder.setInternalProviderId("1111");
+        helper.publishChannel(builder.build());
+        List<PreviewChannel> allChannels = helper.getAllChannels();
+        assertEquals(4, allChannels.size());
+    }
+
+    /**
+     * Test UR of CRUD
+     * Test that the PreviewChannelHelper can correctly update and read preview channels.
+     */
+    @Test
+    public void testPreviewChannelUpdate() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(builder.build());
+        PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+        PreviewChannel channel = builder.build();
+        assertTrue(channelsEqual(channel, channelFromTvProvider));
+
+        PreviewChannel patch = new PreviewChannel.Builder()
+                .setDisplayName(channel.getDisplayName())
+                .setAppLinkIntentUri(channel.getAppLinkIntentUri())
+                .setDescription("Patch description").build();
+        helper.updatePreviewChannel(channelId, patch);
+        channelFromTvProvider = helper.getPreviewChannel(channelId);
+        assertFalse(channelsEqual(channel, channelFromTvProvider));
+        assertEquals(channelFromTvProvider.getDescription(), "Patch description");
+    }
+
+    /**
+     * Tests that data is not being updated unnecessarily
+     */
+    @Test
+    public void testDefensiveUpdatePreviewChannel() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        final int[] channelUpdateCount = {0};
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+            @Override
+            protected void updatePreviewChannelInternal(long channelId, PreviewChannel channel) {
+                channelUpdateCount[0]++;
+            }
+        };
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(builder.build());
+        PreviewChannel fromProvider = helper.getPreviewChannel(channelId);
+        channelsEqual(builder.build(), fromProvider);
+        helper.updatePreviewChannel(channelId, builder.build());
+        assertEquals(0, channelUpdateCount[0]);
+
+        final Uri uri = Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(Intent.URI_INTENT_SCHEME));
+        PreviewChannel channel = new PreviewChannel.Builder()
+                .setDisplayName("Test Display Name Udpate")
+                .setDescription("Test Preview Channel Description")
+                .setAppLinkIntentUri(uri).build();
+
+        helper.updatePreviewChannel(channelId, channel);
+        assertEquals(1, channelUpdateCount[0]);
+    }
+
+    @Test
+    public void testPreviewResolverChannelDeletion() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder builder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(builder.build());
+        PreviewChannel channelFromTvProvider = getPreviewChannel(helper, channelId);
+        assertTrue(channelsEqual(builder.build(), channelFromTvProvider));
+
+        helper.deletePreviewChannel(channelId);
+        channelFromTvProvider = helper.getPreviewChannel(channelId);
+        assertNull(channelFromTvProvider);
+    }
+
+    @Test
+    public void testPreviewProgramCreation() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(channelBuilder.build());
+        PreviewProgram program = createFullyPopulatedPreviewProgram(channelId).build();
+        long programId = helper.publishPreviewProgram(program);
+        PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+        compareProgram(program, programFromProvider);
+    }
+
+    @Test
+    public void testPreviewProgramUpdate() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(channelBuilder.build());
+        PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+        long programId = helper.publishPreviewProgram(programBuilder.build());
+
+        programBuilder.setReleaseDate("2000");
+
+        helper.updatePreviewProgram(programId, programBuilder.build());
+        PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+        compareProgram(programBuilder.build(), programFromProvider);
+    }
+
+    /**
+     * Tests that data is not being updated unnecessarily
+     */
+    @Test
+    public void testDefensivePreviewProgramUpdateRequests() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        final int[] programUpdateCount = {0};
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+
+            @Override
+            public void updatePreviewProgramInternal(long programId, PreviewProgram upgrade) {
+                programUpdateCount[0]++;
+            }
+        };
+        PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(channelBuilder.build());
+        PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+        long programId = helper.publishPreviewProgram(programBuilder.build());
+        PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+        compareProgram(programBuilder.build(), programFromProvider);
+        helper.updatePreviewProgram(programId, programBuilder.build());
+        assertEquals(0, programUpdateCount[0]);
+        programBuilder.setDurationMillis(61 * 1000);
+        helper.updatePreviewProgram(programId, programBuilder.build());
+        assertEquals(1, programUpdateCount[0]);
+    }
+
+    @Test
+    public void testDeletePreviewProgram() throws IOException {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        PreviewChannel.Builder channelBuilder = createFullyPopulatedPreviewChannel();
+        long channelId = helper.publishChannel(channelBuilder.build());
+        PreviewProgram.Builder programBuilder = createFullyPopulatedPreviewProgram(channelId);
+        long programId = helper.publishPreviewProgram(programBuilder.build());
+
+        helper.deletePreviewProgram(programId);
+        PreviewProgram programFromProvider = helper.getPreviewProgram(programId);
+        assertNull(programFromProvider);
+    }
+
+    @Test
+    public void testWatchNextProgramCreation() {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        WatchNextProgram program = createFullyPopulatedWatchNextProgram().build();
+        long programId = helper.publishWatchNextProgram(program);
+        WatchNextProgram programFromProvider = helper.getWatchNextProgram(programId);
+        compareProgram(program, programFromProvider);
+    }
+
+    @Test
+    public void testUpdateWatchNextProgram() {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext);
+        WatchNextProgram.Builder builder = createFullyPopulatedWatchNextProgram();
+        long programId = helper.publishWatchNextProgram(builder.build());
+        builder.setOfferPrice("10.99 USD");
+        helper.updateWatchNextProgram(builder.build(), programId);
+
+        WatchNextProgram fromProvider = helper.getWatchNextProgram(programId);
+        compareProgram(builder.build(), fromProvider);
+    }
+
+    /**
+     * Tests that data is not being updated unnecessarily
+     */
+    @Test
+    public void testDefensiveUpdateWatchNextProgram() {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        final int[] programUpdateCount = {0};
+        PreviewChannelHelper helper = new PreviewChannelHelper(mContext) {
+            @Override
+            protected void updateWatchNextProgram(long programId, WatchNextProgram upgrade) {
+                programUpdateCount[0]++;
+            }
+        };
+        WatchNextProgram.Builder builder = createFullyPopulatedWatchNextProgram();
+        long programId = helper.publishWatchNextProgram(builder.build());
+        WatchNextProgram fromProvider = helper.getWatchNextProgram(programId);
+        compareProgram(builder.build(), fromProvider);
+        helper.updateWatchNextProgram(builder.build(), programId);
+        assertEquals(0, programUpdateCount[0]);
+        builder.setReleaseDate("2000");
+        helper.updateWatchNextProgram(builder.build(), programId);
+        assertEquals(1, programUpdateCount[0]);
+    }
+
+    private boolean channelsEqual(PreviewChannel channelA, PreviewChannel channelB) {
+        boolean result = channelA.getDisplayName().equals(channelB.getDisplayName())
+                && channelA.getType().equals(channelB.getType())
+                && channelA.getAppLinkIntentUri().equals(channelB.getAppLinkIntentUri())
+                && channelA.getDescription().equals(channelB.getDescription())
+                && channelA.getPackageName().equals(channelB.getPackageName())
+                && channelA.getInternalProviderFlag1() == channelB.getInternalProviderFlag1()
+                && channelA.getInternalProviderFlag2() == channelB.getInternalProviderFlag2()
+                && channelA.getInternalProviderFlag3() == channelB.getInternalProviderFlag3()
+                && channelA.getInternalProviderFlag4() == channelB.getInternalProviderFlag4()
+                && (channelA.getInternalProviderId() == null
+                && channelB.getInternalProviderId() == null
+                || channelA.getInternalProviderId().equals(channelB.getInternalProviderId()))
+                && (null != channelA.getLogo(mContext) && null != channelB.getLogo(
+                mContext))
+                && Arrays.equals(channelA.getInternalProviderDataByteArray(),
+                channelB.getInternalProviderDataByteArray());
+        return result;
+    }
+
+    public PreviewChannel.Builder createFullyPopulatedPreviewChannel() {
+        Bitmap logo = BitmapFactory.decodeResource(mContext.getResources(),
+                android.support.media.tv.test.R.drawable.test_icon);
+        assertNotNull(logo);
+        return new PreviewChannel.Builder()
+                .setAppLinkIntent(new Intent())
+                .setDescription("Test Preview Channel Description")
+                .setDisplayName("Test Display Name")
+                .setPackageName("android.support.media.tv.test")
+                .setInternalProviderFlag1(0x1)
+                .setInternalProviderFlag2(0x2)
+                .setInternalProviderFlag3(0x3)
+                .setInternalProviderFlag4(0x4)
+                .setInternalProviderId("Test Internal provider id")
+                .setInternalProviderData("Test byte array".getBytes())
+                .setLogo(logo);
+    }
+}
diff --git a/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java
new file mode 100644
index 0000000..ef5e22e
--- /dev/null
+++ b/tv-provider/src/androidTest/java/android/support/media/tv/PreviewChannelTest.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2018 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.media.tv;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.MatrixCursor;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Build;
+import android.support.media.tv.TvContractCompat.Channels;
+import android.support.media.tv.test.R;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import junit.framework.TestCase;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.Arrays;
+
+/**
+ * Tests that PreviewChannels can be created correctly. Additional test, the ones involving the
+ * System Content Provider, are inside {@link PreviewChannelHelperTest}
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.O)
+@RunWith(JUnit4.class)
+public class PreviewChannelTest extends TestCase {
+
+    private static final String TAG = "PreviewChannelTest";
+    private Context mContext;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+        mContext = InstrumentationRegistry.getContext();
+    }
+
+    @After
+    public void tearDown() {
+        if (!Utils.hasTvInputFramework(InstrumentationRegistry.getContext())) {
+            return;
+        }
+        ContentResolver resolver = mContext.getContentResolver();
+        resolver.delete(Channels.CONTENT_URI, null, null);
+        mContext = null;
+    }
+
+    @Test
+    public void testEmptyPreviewChannel() throws Exception {
+        PreviewChannel.Builder builder = new PreviewChannel.Builder();
+        thrown.expect(IllegalStateException.class);
+        thrown.expectMessage("Need channel name. "
+                + "Use method setDisplayName(String) to set it.");
+        PreviewChannel emptyChannel = builder.build();
+    }
+
+    @Test
+    public void testPartiallyPopulatedPreviewChannel() {
+        final String displayName = "Google";
+        final String description = "This is a test preview channel";
+        final Uri uri = Uri.parse(new Intent(Intent.ACTION_VIEW).toUri(Intent.URI_INTENT_SCHEME));
+
+        PreviewChannel channel = new PreviewChannel.Builder()
+                .setDisplayName(displayName)
+                .setDescription(description)
+                .setAppLinkIntentUri(uri)
+                .setLogo(createLogo()).build();
+
+        assertEquals(displayName, channel.getDisplayName());
+        assertEquals(description, channel.getDescription());
+        assertEquals(uri, channel.getAppLinkIntentUri());
+        assertNotNull(channel.getLogo(mContext));
+        assertNull(channel.getPackageName());
+        assertNull(channel.getInternalProviderDataByteArray());
+        assertNull(channel.getInternalProviderFlag1());
+        assertNull(channel.getInternalProviderFlag2());
+        assertNull(channel.getInternalProviderFlag3());
+        assertNull(channel.getInternalProviderFlag4());
+        assertNull(channel.getInternalProviderId());
+        assertFalse(channel.isBrowsable());
+    }
+
+    @Test
+    public void testFullyPopulatedPreviewChannel() {
+        //test cloning and database I/O
+        PreviewChannel channel = createFullyPopulatedPreviewChannel();
+        PreviewChannel clonedChannelFromCursor = PreviewChannel.fromCursor(
+                getPreviewChannelCursor(channel.toContentValues()));
+        assertTrue(channelsEqual(channel, clonedChannelFromCursor));
+
+        PreviewChannel clonedChannelFromBuilder = new PreviewChannel.Builder(channel).build();
+        assertTrue(channelsEqual(channel, clonedChannelFromBuilder));
+    }
+
+    @Test
+    public void testChannelEquals() {
+        assertEquals(createFullyPopulatedPreviewChannel(), createFullyPopulatedPreviewChannel());
+    }
+
+    private boolean channelsEqual(PreviewChannel channelA, PreviewChannel channelB) {
+        boolean result = channelA.getDisplayName().equals(channelB.getDisplayName())
+                && channelA.getType().equals(channelB.getType())
+                && channelA.getAppLinkIntentUri().equals(channelB.getAppLinkIntentUri())
+                && channelA.getDescription().equals(channelB.getDescription())
+                && channelA.getPackageName().equals(channelB.getPackageName())
+                && channelA.getInternalProviderFlag1() == channelB.getInternalProviderFlag1()
+                && channelA.getInternalProviderFlag2() == channelB.getInternalProviderFlag2()
+                && channelA.getInternalProviderFlag3() == channelB.getInternalProviderFlag3()
+                && channelA.getInternalProviderFlag4() == channelB.getInternalProviderFlag4()
+                && channelA.getInternalProviderId().equals(channelB.getInternalProviderId())
+                && Arrays.equals(channelA.getInternalProviderDataByteArray(),
+                channelB.getInternalProviderDataByteArray());
+        return result;
+    }
+
+    private PreviewChannel createFullyPopulatedPreviewChannel() {
+        return new PreviewChannel.Builder()
+                .setAppLinkIntent(new Intent())
+                .setDescription("Test Preview Channel Description")
+                .setDisplayName("Test Display Name")
+                .setPackageName("android.support.media.tv.test")
+                .setInternalProviderFlag1(0x1)
+                .setInternalProviderFlag2(0x2)
+                .setInternalProviderFlag3(0x3)
+                .setInternalProviderFlag4(0x4)
+                .setInternalProviderId("Test Internal provider id")
+                .setLogo(createLogo()).build();
+    }
+
+    private Bitmap createLogo() {
+        Bitmap logo = BitmapFactory.decodeResource(mContext.getResources(),
+                R.drawable.test_icon);
+        assertNotNull(logo);
+        return logo;
+    }
+
+    private MatrixCursor getPreviewChannelCursor(ContentValues contentValues) {
+        MatrixCursor cursor = new MatrixCursor(PreviewChannel.Columns.PROJECTION);
+        MatrixCursor.RowBuilder rowBuilder = cursor.newRow();
+        for (String col : PreviewChannel.Columns.PROJECTION) {
+            rowBuilder.add(col, contentValues.get(col));
+        }
+        cursor.moveToFirst();
+        return cursor;
+    }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java b/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java
new file mode 100644
index 0000000..79a65f9
--- /dev/null
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewChannel.java
@@ -0,0 +1,565 @@
+/*
+ * Copyright 2018 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.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.WorkerThread;
+import android.support.media.tv.TvContractCompat.Channels;
+import android.support.media.tv.TvContractCompat.Channels.Type;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Since API 26, all TV apps may create preview channels and publish them to the home screen.
+ * We call these App Channels (as distinct from the Live Channels row on the home screen). To help
+ * you create App Channels, the support library provides a number of classes prefixed by the word
+ * Preview-.
+ *
+ * This is a convenience class for mapping your app's content into a
+ * {@link TvContractCompat TvProvider Channel} for publication. Use the provided {@link Builder}
+ * for creating your preview channel object. Once you create a preview channel, you can
+ * use {@link PreviewChannelHelper} to publish it and add {@link PreviewProgram programs} to it.
+ */
+@TargetApi(26)
+public class PreviewChannel {
+
+    private static final String TAG = "PreviewChannel";
+    private static final long INVALID_CHANNEL_ID = -1;
+    private static final int IS_BROWSABLE = 1;
+
+    private ContentValues mValues;
+    private volatile Bitmap mLogoImage;
+
+    private Uri mLogoUri;
+    private boolean mLogoChanged;
+
+    /**
+     * Logo is fetched when it is explicitly asked for. mLogoFetched prevents repeated calls in
+     * case there is no logo in fact.
+     */
+    private volatile boolean mLogoFetched;
+
+    private PreviewChannel(Builder builder) {
+        mValues = builder.mValues;
+        mLogoImage = builder.mLogoBitmap;
+        mLogoUri = builder.mLogoUri;
+        mLogoChanged = (mLogoImage != null || mLogoUri != null);
+    }
+
+    /**
+     * Used by {@link PreviewChannelHelper} to transduce a TvProvider channel row into a
+     * PreviewChannel Java object. You never need to use this method unless you want to convert
+     * database rows to PreviewChannel objects yourself.
+     * <p/>
+     * This method assumes the cursor was obtained using {@link android.support.media.tv
+     * .PreviewChannel.Columns#PROJECTION}. This way, all indices are known
+     * beforehand.
+     *
+     * @param cursor a cursor row from the TvProvider
+     * @return a PreviewChannel whose values come from the cursor row
+     */
+    public static PreviewChannel fromCursor(Cursor cursor) {
+        Builder builder = new Builder();
+        builder.setId(cursor.getInt(Columns.COL_ID));
+        builder.setPackageName(cursor.getString(Columns.COL_PACKAGE_NAME));
+        builder.setType(cursor.getString(Columns.COL_TYPE));
+        builder.setDisplayName(cursor.getString(Columns.COL_DISPLAY_NAME));
+        builder.setDescription(cursor.getString(Columns.COL_DESCRIPTION));
+        builder.setAppLinkIntentUri(Uri.parse(cursor.getString(Columns.COL_APP_LINK_INTENT_URI)));
+        builder.setInternalProviderId(cursor.getString(Columns.COL_INTERNAL_PROVIDER_ID));
+        builder.setInternalProviderData(cursor.getBlob(Columns.COL_INTERNAL_PROVIDER_DATA));
+        builder.setInternalProviderFlag1(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG1));
+        builder.setInternalProviderFlag2(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG2));
+        builder.setInternalProviderFlag3(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG3));
+        builder.setInternalProviderFlag4(cursor.getLong(Columns.COL_INTERNAL_PROVIDER_FLAG4));
+        return builder.build();
+    }
+
+    /**
+     * @return the ID the system assigns to this preview channel upon publication.
+     */
+    public long getId() {
+        Long l = mValues.getAsLong(Channels._ID);
+        return l == null ? INVALID_CHANNEL_ID : l;
+    }
+
+    /**
+     * @return package name of the app that created this channel
+     */
+    public String getPackageName() {
+        return mValues.getAsString(Channels.COLUMN_PACKAGE_NAME);
+    }
+
+    /**
+     * @return what type of channel this is. For preview channels, the type is always
+     * TvContractCompat.Channels.TYPE_PREVIEW
+     */
+    @Type
+    public String getType() {
+        return mValues.getAsString(Channels.COLUMN_TYPE);
+    }
+
+    /**
+     * @return The name users see when this channel appears on the home screen
+     */
+    public CharSequence getDisplayName() {
+        return mValues.getAsString(Channels.COLUMN_DISPLAY_NAME);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_DESCRIPTION} for the channel. A short text
+     * explaining what this channel contains.
+     */
+    public CharSequence getDescription() {
+        return mValues.getAsString(Channels.COLUMN_DESCRIPTION);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the channel.
+     */
+    public Uri getAppLinkIntentUri() {
+        String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI);
+        return uri == null ? null : Uri.parse(uri);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_APP_LINK_INTENT_URI} for the program.
+     */
+    public Intent getAppLinkIntent() throws URISyntaxException {
+        String uri = mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI);
+        return uri == null ? null : Intent.parseUri(uri.toString(), Intent.URI_INTENT_SCHEME);
+    }
+
+    /**
+     * This method should be called on a worker thread since decoding Bitmap is an expensive
+     * operation and therefore should not be performed on the main thread.
+     *
+     * @return The logo associated with this preview channel
+     */
+    @WorkerThread
+    public Bitmap getLogo(Context context) {
+        if (!mLogoFetched && mLogoImage == null) {
+            try {
+                mLogoImage = BitmapFactory.decodeStream(
+                        context.getContentResolver().openInputStream(
+                                TvContract.buildChannelLogoUri(getId())
+                        ));
+            } catch (FileNotFoundException | SQLiteException e) {
+                Log.e(TAG, "Logo for preview channel (ID:" + getId() + ") not found.", e);
+            }
+            mLogoFetched = true;
+        }
+        return mLogoImage;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    boolean isLogoChanged() {
+        return mLogoChanged;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    Uri getLogoUri() {
+        return mLogoUri;
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_DATA} for the channel.
+     */
+    public byte[] getInternalProviderDataByteArray() {
+        return mValues.getAsByteArray(Channels.COLUMN_INTERNAL_PROVIDER_DATA);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG1} for the channel.
+     */
+    public Long getInternalProviderFlag1() {
+        return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG2} for the channel.
+     */
+    public Long getInternalProviderFlag2() {
+        return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG3} for the channel.
+     */
+    public Long getInternalProviderFlag3() {
+        return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_FLAG4} for the channel.
+     */
+    public Long getInternalProviderFlag4() {
+        return mValues.getAsLong(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_INTERNAL_PROVIDER_ID} for the channel.
+     */
+    public String getInternalProviderId() {
+        return mValues.getAsString(Channels.COLUMN_INTERNAL_PROVIDER_ID);
+    }
+
+    /**
+     * @return The value of {@link Channels#COLUMN_BROWSABLE} for the channel. A preview channel
+     * is BROWABLE when it is visible on the TV home screen.
+     */
+    public boolean isBrowsable() {
+        Integer i = mValues.getAsInteger(Channels.COLUMN_BROWSABLE);
+        return i != null && i == IS_BROWSABLE;
+    }
+
+    @Override
+    public int hashCode() {
+        return mValues.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (!(other instanceof PreviewChannel)) {
+            return false;
+        }
+        return mValues.equals(((PreviewChannel) other).mValues);
+    }
+
+    /**
+     * Indicates whether some other PreviewChannel has any set attribute that is different from
+     * this PreviewChannel's respective attributes. An attribute is considered "set" if its key
+     * is present in the ContentValues vector.
+     */
+    public boolean hasAnyUpdatedValues(PreviewChannel update) {
+        Set<String> updateKeys = update.mValues.keySet();
+        for (String key : updateKeys) {
+            Object updateValue = update.mValues.get(key);
+            Object currValue = mValues.get(key);
+            if (!Objects.deepEquals(updateValue, currValue)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "Channel{" + mValues.toString() + "}";
+    }
+
+    /**
+     * Used by {@link PreviewChannelHelper} to communicate PreviewChannel CRUD operations
+     * to the TvProvider. You never need to use this method unless you want to communicate to the
+     * TvProvider directly.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public ContentValues toContentValues() {
+        ContentValues values = new ContentValues(mValues);
+        return values;
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    public static class Columns {
+        public static final String[] PROJECTION = {
+                Channels._ID,
+                Channels.COLUMN_PACKAGE_NAME,
+                Channels.COLUMN_TYPE,
+                Channels.COLUMN_DISPLAY_NAME,
+                Channels.COLUMN_DESCRIPTION,
+                Channels.COLUMN_APP_LINK_INTENT_URI,
+                Channels.COLUMN_INTERNAL_PROVIDER_ID,
+                Channels.COLUMN_INTERNAL_PROVIDER_DATA,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG1,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG2,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG3,
+                Channels.COLUMN_INTERNAL_PROVIDER_FLAG4
+        };
+
+        public static final int COL_ID = 0;
+        public static final int COL_PACKAGE_NAME = 1;
+        public static final int COL_TYPE = 2;
+        public static final int COL_DISPLAY_NAME = 3;
+        public static final int COL_DESCRIPTION = 4;
+        public static final int COL_APP_LINK_INTENT_URI = 5;
+        public static final int COL_INTERNAL_PROVIDER_ID = 6;
+        public static final int COL_INTERNAL_PROVIDER_DATA = 7;
+        public static final int COL_INTERNAL_PROVIDER_FLAG1 = 8;
+        public static final int COL_INTERNAL_PROVIDER_FLAG2 = 9;
+        public static final int COL_INTERNAL_PROVIDER_FLAG3 = 10;
+        public static final int COL_INTERNAL_PROVIDER_FLAG4 = 11;
+    }
+
+    /**
+     * This builder makes it easy to create a PreviewChannel object by allowing you to chain
+     * setters. Even though this builder provides a no-arg constructor, certain fields are
+     * required or the {@link #build()} method will throw an exception. The required fields are
+     * displayName and appLinkIntentUri; use the respective methods to set them.
+     */
+    public static final class Builder {
+        private ContentValues mValues;
+        private Bitmap mLogoBitmap;
+        private Uri mLogoUri;
+
+        public Builder() {
+            mValues = new ContentValues();
+        }
+
+        public Builder(PreviewChannel other) {
+            mValues = new ContentValues(other.mValues);
+        }
+
+        private Builder setId(long id) {
+            mValues.put(Channels._ID, id);
+            return this;
+        }
+
+        /**
+         * Sets the package name of the Channel.
+         *
+         * @param packageName The value of {@link Channels#COLUMN_PACKAGE_NAME} for the channel.
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        Builder setPackageName(String packageName) {
+            mValues.put(Channels.COLUMN_PACKAGE_NAME, packageName);
+            return this;
+        }
+
+        // Private because this is always the same: setType(TvContractCompat.Channels.TYPE_PREVIEW)
+        private Builder setType(@Type String type) {
+            mValues.put(Channels.COLUMN_TYPE, type);
+            return this;
+        }
+
+        /**
+         * This is the name user sees when your channel appears on their TV home screen. For
+         * example "New Arrivals." This field is required.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_DISPLAY_NAME
+         */
+        public Builder setDisplayName(CharSequence displayName) {
+            mValues.put(Channels.COLUMN_DISPLAY_NAME, displayName.toString());
+            return this;
+        }
+
+        /**
+         * It's good practice to include a general description of the programs in this channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_DESCRIPTION
+         */
+        public Builder setDescription(CharSequence description) {
+            mValues.put(Channels.COLUMN_DESCRIPTION, description.toString());
+            return this;
+        }
+
+        /**
+         * When user clicks on this channel's logo, the system will send an Intent for your app to
+         * open an Activity with contents relevant to this channel. Hence, the Intent data you
+         * provide here must point to content relevant to this channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setAppLinkIntent(Intent appLinkIntent) {
+            return setAppLinkIntentUri(Uri.parse(appLinkIntent.toUri(Intent.URI_INTENT_SCHEME)));
+        }
+
+        /**
+         * When user clicks on this channel's logo, the system will send an Intent for your app to
+         * open an Activity with contents relevant to this channel. Hence, the Uri you provide here
+         * must point to content relevant to this channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_APP_LINK_INTENT_URI
+         */
+        public Builder setAppLinkIntentUri(Uri appLinkIntentUri) {
+            mValues.put(Channels.COLUMN_APP_LINK_INTENT_URI,
+                    null == appLinkIntentUri ? null : appLinkIntentUri.toString());
+            return this;
+        }
+
+        /**
+         * It is expected that your app or your server has its own internal representation
+         * (i.e. data structure) of channels. It is highly recommended that you store your
+         * app/server's channel ID here; so that you may easily relate this published preview
+         * channel with the corresponding channel from your server.
+         *
+         * The {@link PreviewChannelHelper#publishChannel(PreviewChannel) publish} method check this
+         * field to verify whether a preview channel being published would result in a duplicate.
+         * :
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_ID
+         */
+        public Builder setInternalProviderId(String internalProviderId) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_ID, internalProviderId);
+            return this;
+        }
+
+        /**
+         * This is one of the optional fields that your app may set. Use these fields at your
+         * discretion to help you remember important information about this channel.
+         *
+         * For example, if this channel needs a byte array that is expensive for your app to
+         * construct, you may choose to save it here.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_DATA
+         */
+        public Builder setInternalProviderData(byte[] internalProviderData) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_DATA, internalProviderData);
+            return this;
+        }
+
+        /**
+         * This is one of the optional fields that your app may set. Use these fields at your
+         * discretion to help you remember important information about this channel.
+         *
+         * For example, you may use this flag to track additional data about this particular
+         * channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG1
+         */
+        public Builder setInternalProviderFlag1(long flag) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, flag);
+            return this;
+        }
+
+        /**
+         * This is one of the optional fields that your app may set. Use these fields at your
+         * discretion to help you remember important information about this channel.
+         *
+         * For example, you may use this flag to track additional data about this particular
+         * channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG2
+         */
+        public Builder setInternalProviderFlag2(long flag) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, flag);
+            return this;
+        }
+
+        /**
+         * This is one of the optional fields that your app may set. Use these fields at your
+         * discretion to help you remember important information about this channel.
+         *
+         * For example, you may use this flag to track additional data about this particular
+         * channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG3
+         */
+        public Builder setInternalProviderFlag3(long flag) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG3, flag);
+            return this;
+        }
+
+        /**
+         * This is one of the optional fields that your app may set. Use these fields at your
+         * discretion to help you remember important information about this channel.
+         *
+         * For example, you may use this flag to track additional data about this particular
+         * channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         * @see TvContractCompat.Channels#COLUMN_INTERNAL_PROVIDER_FLAG4
+         */
+        public Builder setInternalProviderFlag4(long flag) {
+            mValues.put(Channels.COLUMN_INTERNAL_PROVIDER_FLAG4, flag);
+            return this;
+        }
+
+        /**
+         * A logo visually identifies your channel. Hence, you should consider adding a unique logo
+         * to every channel you create, so user can quickly identify your channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLogo(@NonNull Bitmap logoImage) {
+            mLogoBitmap = logoImage;
+            mLogoUri = null;
+            return this;
+        }
+
+        /**
+         * A logo visually identifies your channel. Hence, you should consider adding a unique logo
+         * to every channel you create, so user can quickly identify your channel.
+         *
+         * @return This Builder object to allow for chaining of calls to builder methods.
+         */
+        public Builder setLogo(@NonNull Uri logoUri) {
+            mLogoUri = logoUri;
+            mLogoBitmap = null;
+            return this;
+        }
+
+        /**
+         * Takes the values of the Builder object and creates a PreviewChannel object.
+         *
+         * @return PreviewChannel object with values from the Builder.
+         */
+        public PreviewChannel build() {
+            setType(Channels.TYPE_PREVIEW);
+
+            if (TextUtils.isEmpty(mValues.getAsString(Channels.COLUMN_DISPLAY_NAME))) {
+                throw new IllegalStateException("Need channel name."
+                        + " Use method setDisplayName(String) to set it.");
+            }
+
+            if (TextUtils.isEmpty(mValues.getAsString(Channels.COLUMN_APP_LINK_INTENT_URI))) {
+                throw new IllegalStateException("Need app link intent uri for channel."
+                        + " Use method setAppLinkIntent or setAppLinkIntentUri to set it.");
+            }
+
+            PreviewChannel previewChannel = new PreviewChannel(this);
+            return previewChannel;
+        }
+    }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java b/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java
new file mode 100644
index 0000000..05fa9f5
--- /dev/null
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewChannelHelper.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright 2018 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.media.tv;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import android.annotation.TargetApi;
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.support.annotation.NonNull;
+import android.support.annotation.RestrictTo;
+import android.support.annotation.WorkerThread;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * From a user's perspective, the TV home screen has two types of channels: the single Live
+ * Channels row versus the App preview Channels. This class is concerned with App Channels; or more
+ * precisely: <i>your</i> app's preview Channels. In API 26+, all TV apps are allowed to create
+ * multiple channels and publish those Channels to the home screen.
+ * <p>
+ * This class provides convenience methods to help you publish, update and delete channels; add,
+ * update or remove programs in a channel. You do not need to know anything about Content
+ * Providers, Content Resolvers, Cursors or such to publish your channels. This class abstracts
+ * away all database interactions for you.
+ * <p>
+ * To make it easy for you to distinguish classes that help you build App Channels, the support
+ * library uses the prefix Preview- to denote the classes that pertain to app Channels. Hence,
+ * the classes {@link PreviewChannel} and {@link PreviewProgram} help your app add channels to the
+ * TV home page.
+ *
+ * All calls to methods in the class should be made on worker threads.
+ */
+
+@TargetApi(26)
+@WorkerThread
+public class PreviewChannelHelper {
+
+    private static final String TAG = "PreviewChannelHelper";
+    private static final int DEFAULT_URL_CONNNECTION_TIMEOUT_MILLIS =
+            (int) (3 * DateUtils.SECOND_IN_MILLIS);
+    private static final int DEFAULT_READ_TIMEOUT_MILLIS = (int) (10 * DateUtils.SECOND_IN_MILLIS);
+    private static final int INVALID_CONTENT_ID = -1;
+    private final int mUrlConnectionTimeoutMillis;
+    private final int mUrlReadTimeoutMillis;
+    private final Context mContext;
+
+    public PreviewChannelHelper(Context context) {
+        this(context, DEFAULT_URL_CONNNECTION_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT_MILLIS);
+    }
+
+    /**
+     * @param urlConnectionTimeoutMillis see {@link URLConnection#setConnectTimeout(int)}
+     * @param urlReadTimeoutMillis       see {@link URLConnection#setReadTimeout(int)}
+     */
+    public PreviewChannelHelper(Context context, int urlConnectionTimeoutMillis,
+            int urlReadTimeoutMillis) {
+        mContext = context;
+        mUrlConnectionTimeoutMillis = urlConnectionTimeoutMillis;
+        mUrlReadTimeoutMillis = urlReadTimeoutMillis;
+    }
+
+    /**
+     * Publishing a channel to the TV home screen is a two step process: first, you add the
+     * channel to the TV content provider; second, you make the channel browsable (i.e. visible).
+     * {@link #publishChannel(PreviewChannel) This method} adds the channel to the
+     * TV content provider for you and returns a channelId. Next you must use the channelId
+     * to make the channel browsable.
+     * </br>
+     * There are two ways you can make a channel browsable:
+     * </br>
+     * a) For your first channel, simply ask the system to make the channel browsable:
+     * TvContractCompat.requestChannelBrowsable(context,channelId)
+     * </br>
+     * b) For any additional channel beyond the first channel, you must get permission
+     * from the user. So if this channel is not your first channel, you must request user
+     * permission through the following intent. So take the channelId returned by
+     * {@link #publishChannel(PreviewChannel) this method} and do the following
+     * inside an Activity or Fragment:
+     * </br>
+     * <pre>
+     * intent = new Intent(TvContractCompat.ACTION_REQUEST_CHANNEL_BROWSABLE);
+     * intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
+     * startActivityForResult(intent, REQUEST_CHANNEL_BROWSABLE);
+     * </pre>
+     *
+     * <p>
+     * Creating a PreviewChannel, you may pass to the builder a
+     * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+     * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+     * use your own networking code, override {@link #downloadBitmap(Uri)}.
+     *
+     * @return channelId or -1 if insertion fails. This is the id the system assigns to your
+     * published channel. You can use it later to get a reference to this published PreviewChannel.
+     */
+    public long publishChannel(@NonNull PreviewChannel channel) throws IOException {
+        try {
+            Uri channelUri = mContext.getContentResolver().insert(
+                    TvContractCompat.Channels.CONTENT_URI,
+                    channel.toContentValues());
+            if (null == channelUri || channelUri.equals(Uri.EMPTY)) {
+                throw new NullPointerException("Channel insertion failed");
+            }
+            long channelId = ContentUris.parseId(channelUri);
+            boolean logoAdded = addChannelLogo(channelId, channel);
+            // Rollback channel insertion if logo could not be added.
+            if (!logoAdded) {
+                deletePreviewChannel(channelId);
+                throw new IOException("Failed to add logo, so channel (ID="
+                        + channelId + ") was not created");
+            }
+            return channelId;
+        } catch (SecurityException e) {
+            Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+                    + " may have been revoked.", e);
+        }
+        return INVALID_CONTENT_ID;
+    }
+
+    /**
+     * This is a convenience method that simply publishes your first channel for you. After calling
+     * {@link #publishChannel(PreviewChannel)} to add the channel to the TvProvider, it
+     * calls {@link TvContractCompat#requestChannelBrowsable(Context, long)} to make the channel
+     * visible.
+     * <p>
+     * Only use this method to publish your first channel as you do not need user permission to
+     * make your first channel browsable (i.e. visible on home screen). For additional channels,
+     * see the documentations for {@link #publishChannel(PreviewChannel)}.
+     *
+     * <p>
+     * Creating a PreviewChannel, you may pass to the builder a
+     * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+     * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+     * use your own networking code, override {@link #downloadBitmap(Uri)}.
+     *
+     * @return channelId: This is the id the system assigns to your published channel. You can
+     * use it later to get a reference to this published PreviewChannel.
+     */
+    public long publishDefaultChannel(@NonNull PreviewChannel channel)
+            throws IOException {
+        long channelId = publishChannel(channel);
+        TvContractCompat.requestChannelBrowsable(mContext, channelId);
+        return channelId;
+    }
+
+    /**
+     * The TvProvider does not allow select queries. Hence, unless you are querying for a
+     * {@link #getPreviewChannel(long) single PreviewChannel by id}, you must get all of
+     * your channels at once and then use the returned list as necessary.
+     */
+    public List<PreviewChannel> getAllChannels() {
+        Cursor cursor = mContext.getContentResolver()
+                .query(
+                        TvContractCompat.Channels.CONTENT_URI,
+                        PreviewChannel.Columns.PROJECTION,
+                        null,
+                        null,
+                        null);
+
+        List<PreviewChannel> channels = new ArrayList<>();
+        if (cursor != null && cursor.moveToFirst()) {
+            do {
+                channels.add(PreviewChannel.fromCursor(cursor));
+            } while (cursor.moveToNext());
+        }
+        return channels;
+    }
+
+    /**
+     * Retrieves a single preview channel from the TvProvider. When you publish a preview channel,
+     * the TvProvider assigns an ID to it. That's the channelId to use here.
+     *
+     * @param channelId ID of preview channel in TvProvider
+     * @return PreviewChannel or null if not found
+     */
+    public PreviewChannel getPreviewChannel(long channelId) {
+        PreviewChannel channel = null;
+        Uri channelUri = TvContractCompat.buildChannelUri(channelId);
+        Cursor cursor = mContext.getContentResolver()
+                .query(channelUri, PreviewChannel.Columns.PROJECTION, null, null, null);
+        if (cursor != null && cursor.moveToFirst()) {
+            channel = PreviewChannel.fromCursor(cursor);
+        }
+        return channel;
+    }
+
+    /**
+     * To update a preview channel, you need to use the {@link PreviewChannel.Builder} to set the
+     * attributes you wish to change. Then simply pass in the built channel and the channelId of the
+     * preview channel. (The channelId is the ID you received when you originally
+     * {@link #publishChannel(PreviewChannel) published} the preview channel.)
+     * <p>
+     * Creating a PreviewChannel, you may pass to the builder a
+     * {@link PreviewChannel.Builder#setLogo(Uri) url as your logo}. In such case,
+     * {@link #updatePreviewChannel(long, PreviewChannel)} will load the logo over the network. To
+     * use your own networking code, override {@link #downloadBitmap(Uri)}.
+     */
+    public void updatePreviewChannel(long channelId,
+            @NonNull PreviewChannel update) throws IOException {
+        // To avoid possibly expensive no-op updates, first check that the current content that's
+        // in the database is different from the new content to be added.
+        PreviewChannel curr = getPreviewChannel(channelId);
+        if (curr != null && curr.hasAnyUpdatedValues(update)) {
+            updatePreviewChannelInternal(channelId, update);
+        }
+        if (update.isLogoChanged()) {
+            boolean logoAdded = addChannelLogo(channelId, update);
+            if (!logoAdded) {
+                throw new IOException("Fail to update channel (ID=" + channelId + ") logo.");
+            }
+        }
+    }
+
+    /**
+     * Inner methods that does the actual work of updating a Preview Channel. The method is
+     * extracted to make {@link #updatePreviewChannel(long, PreviewChannel)} testable.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    protected void updatePreviewChannelInternal(long channelId, @NonNull PreviewChannel upgrade) {
+        mContext.getContentResolver().update(
+                TvContractCompat.buildChannelUri(channelId),
+                upgrade.toContentValues(),
+                null,
+                null);
+    }
+
+    /**
+     * Internally, a logo is added to a channel after the channel has been added to the TvProvider.
+     * This private method is called by one of the publish methods, to add a logo to the TvProvider
+     * and associate the logo to the given channel identified by channelId. Because each channel
+     * must have a logo, a NullPointerException is thrown if the channel being published has no
+     * associated logo to publish with it.
+     */
+    private boolean addChannelLogo(long channelId, @NonNull PreviewChannel channel) {
+        boolean result = false;
+        if (!channel.isLogoChanged()) {
+            return result;
+        }
+        Bitmap logo = channel.getLogo(mContext);
+        if (logo == null) {
+            logo = getLogoFromUri(channel.getLogoUri());
+        }
+        Uri logoUri = TvContractCompat.buildChannelLogoUri(channelId);
+        try (OutputStream outputStream = mContext.getContentResolver().openOutputStream(
+                logoUri)) {
+            result = logo.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
+            outputStream.flush();
+        } catch (SQLiteException | IOException | NullPointerException e) {
+            Log.i(TAG, "Failed to add logo to the published channel (ID= " + channelId + ")", e);
+        }
+        return result;
+    }
+
+    /**
+     * Handles the case where the Bitmap must be fetched from a known uri. First the
+     * method checks if the Uri is local. If not, the method makes a connection to fetch the Bitmap
+     * data from its remote location. To use your own networking implementation, simply override
+     * {@link #downloadBitmap(Uri)}
+     */
+    private Bitmap getLogoFromUri(@NonNull Uri logoUri) {
+        String scheme = logoUri.normalizeScheme().getScheme();
+        InputStream inputStream = null;
+        Bitmap logoImage = null;
+
+        try {
+            if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)
+                    || ContentResolver.SCHEME_FILE.equals(scheme)
+                    || ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+                // for local resource
+                inputStream = mContext.getContentResolver().openInputStream(logoUri);
+                logoImage = BitmapFactory.decodeStream(inputStream);
+            } else {
+                logoImage = downloadBitmap(logoUri);
+            }
+
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to get logo from the URI: " + logoUri, e);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    // Do nothing
+                }
+            }
+        }
+        return logoImage;
+    }
+
+    /**
+     * Downloads a Bitmap from a remote server. It is declared protected to allow you
+     * to override it to use your own networking implementation if you so wish.
+     */
+    protected Bitmap downloadBitmap(@NonNull Uri logoUri) throws IOException {
+        URLConnection urlConnection = null;
+        InputStream inputStream = null;
+        Bitmap logoImage = null;
+        try {
+            // for remote resource
+            urlConnection = new URL(logoUri.toString()).openConnection();
+            urlConnection.setConnectTimeout(mUrlConnectionTimeoutMillis);
+            urlConnection.setReadTimeout(mUrlReadTimeoutMillis);
+            inputStream = urlConnection.getInputStream();
+            logoImage = BitmapFactory.decodeStream(inputStream);
+        } finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                } catch (IOException e) {
+                    // Do nothing
+                }
+            }
+            if (urlConnection instanceof HttpURLConnection) {
+                ((HttpURLConnection) urlConnection).disconnect();
+            }
+        }
+        return logoImage;
+    }
+
+    /**
+     * Removes a preview channel from the system's content provider (aka TvProvider).
+     */
+    public void deletePreviewChannel(long channelId) {
+        mContext.getContentResolver().delete(
+                TvContractCompat.buildChannelUri(channelId),
+                null,
+                null);
+    }
+
+    /**
+     * Adds programs to a preview channel.
+     */
+    public long publishPreviewProgram(@NonNull PreviewProgram program) {
+        try {
+            Uri programUri = mContext.getContentResolver().insert(
+                    TvContractCompat.PreviewPrograms.CONTENT_URI,
+                    program.toContentValues());
+            long programId = ContentUris.parseId(programUri);
+            return programId;
+        } catch (SecurityException e) {
+            Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+                    + " may have been revoked.", e);
+        }
+        return INVALID_CONTENT_ID;
+    }
+
+    /**
+     * Retrieves a single preview program from the system content provider (aka TvProvider).
+     */
+    public PreviewProgram getPreviewProgram(long programId) {
+        PreviewProgram program = null;
+        Uri programUri = TvContractCompat.buildPreviewProgramUri(programId);
+        Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
+        if (cursor != null && cursor.moveToFirst()) {
+            program = PreviewProgram.fromCursor(cursor);
+        }
+        return program;
+    }
+
+    /**
+     * Updates programs in a preview channel.
+     */
+    public void updatePreviewProgram(long programId, @NonNull PreviewProgram update) {
+        // To avoid possibly expensive no-op updates, first check that the current content that's
+        // in the database is different from the new content to be added.
+        PreviewProgram curr = getPreviewProgram(programId);
+        if (curr != null && curr.hasAnyUpdatedValues(update)) {
+            updatePreviewProgramInternal(programId, update);
+        }
+    }
+
+    /**
+     * Inner methods that does the actual work of updating a Preview Program. The method is
+     * extracted to make {@link #updatePreviewProgram(long, PreviewProgram)} testable.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    void updatePreviewProgramInternal(long programId, @NonNull PreviewProgram upgrade) {
+        mContext.getContentResolver().update(
+                TvContractCompat.buildPreviewProgramUri(programId),
+                upgrade.toContentValues(), null, null);
+    }
+
+    /**
+     * Removes programs from a preview channel.
+     */
+    public void deletePreviewProgram(long programId) {
+        mContext.getContentResolver().delete(
+                TvContractCompat.buildPreviewProgramUri(programId), null, null);
+    }
+
+    /**
+     * Adds a program to the Watch Next channel
+     */
+    public long publishWatchNextProgram(@NonNull WatchNextProgram program) {
+        try {
+            Uri programUri = mContext.getContentResolver().insert(
+                    TvContractCompat.WatchNextPrograms.CONTENT_URI, program.toContentValues());
+            return ContentUris.parseId(programUri);
+        } catch (SecurityException e) {
+            Log.e(TAG, "Your app's ability to insert data into the TvProvider"
+                    + " may have been revoked.", e);
+        }
+        return INVALID_CONTENT_ID;
+    }
+
+    /**
+     * Retrieves a single WatchNext program from the system content provider (aka TvProvider).
+     */
+    public WatchNextProgram getWatchNextProgram(long programId) {
+        WatchNextProgram program = null;
+        Uri programUri = TvContractCompat.buildWatchNextProgramUri(programId);
+        Cursor cursor = mContext.getContentResolver().query(programUri, null, null, null, null);
+        if (cursor != null && cursor.moveToFirst()) {
+            program = WatchNextProgram.fromCursor(cursor);
+        }
+        return program;
+    }
+
+    /**
+     * Updates a WatchNext program.
+     */
+    public void updateWatchNextProgram(@NonNull WatchNextProgram upgrade, long programId) {
+        // To avoid possibly expensive no-op updates, first check that the current content that's in
+        // the database is different from the new content to be added.
+        WatchNextProgram curr = getWatchNextProgram(programId);
+        if (curr != null && curr.hasAnyUpdatedValues(upgrade)) {
+            updateWatchNextProgram(programId, upgrade);
+        }
+    }
+
+    /**
+     * Inner methods that does the actual work of updating a Watch Next Program. The method is
+     * extracted to make {@link #updateWatchNextProgram(WatchNextProgram, long)} testable.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    void updateWatchNextProgram(long programId, @NonNull WatchNextProgram upgrade) {
+        mContext.getContentResolver().update(
+                TvContractCompat.buildWatchNextProgramUri(programId),
+                upgrade.toContentValues(), null, null);
+    }
+}
diff --git a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
index 2536f75..f44e18f 100644
--- a/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/PreviewProgram.java
@@ -23,6 +23,9 @@
 import android.support.annotation.RestrictTo;
 import android.support.media.tv.TvContractCompat.PreviewPrograms;
 
+import java.util.Objects;
+import java.util.Set;
+
 /**
  * A convenience class to access {@link PreviewPrograms} entries in the system content
  * provider.
@@ -108,6 +111,23 @@
         return mValues.equals(((PreviewProgram) other).mValues);
     }
 
+    /**
+     * Indicates whether some other PreviewProgram has any set attribute that is different from
+     * this PreviewProgram's respective attributes. An attribute is considered "set" if its key
+     * is present in the ContentValues vector.
+     */
+    public boolean hasAnyUpdatedValues(PreviewProgram update) {
+        Set<String> updateKeys = update.mValues.keySet();
+        for (String key : updateKeys) {
+            Object updateValue = update.mValues.get(key);
+            Object currValue = mValues.get(key);
+            if (!Objects.deepEquals(updateValue, currValue)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public String toString() {
         return "PreviewProgram{" + mValues.toString() + "}";
@@ -164,7 +184,7 @@
     }
 
     private static String[] getProjection() {
-        String[] oColumns = new String[] {
+        String[] oColumns = new String[]{
                 PreviewPrograms.COLUMN_CHANNEL_ID,
                 PreviewPrograms.COLUMN_WEIGHT,
         };
@@ -184,6 +204,7 @@
 
         /**
          * Creates a new Builder object with values copied from another Program.
+         *
          * @param other The Program you're copying from.
          */
         public Builder(PreviewProgram other) {
diff --git a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
index e5d12b2..cb317b7 100644
--- a/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
+++ b/tv-provider/src/main/java/android/support/media/tv/WatchNextProgram.java
@@ -26,6 +26,8 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+import java.util.Set;
 
 /**
  * A convenience class to access {@link WatchNextPrograms} entries in the system content
@@ -94,7 +96,8 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     @RestrictTo(LIBRARY_GROUP)
-    public @interface WatchNextType {}
+    public @interface WatchNextType {
+    }
 
     /**
      * The unknown watch next type. Use this type when the actual type is not known.
@@ -131,6 +134,23 @@
         return mValues.equals(((WatchNextProgram) other).mValues);
     }
 
+    /**
+     * Indicates whether some other WatchNextProgram has any set attribute that is different from
+     * this WatchNextProgram's respective attributes. An attribute is considered "set" if its key
+     * is present in the ContentValues vector.
+     */
+    public boolean hasAnyUpdatedValues(WatchNextProgram update) {
+        Set<String> updateKeys = update.mValues.keySet();
+        for (String key : updateKeys) {
+            Object updateValue = update.mValues.get(key);
+            Object currValue = mValues.get(key);
+            if (!Objects.deepEquals(updateValue, currValue)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public String toString() {
         return "WatchNextProgram{" + mValues.toString() + "}";
@@ -188,7 +208,7 @@
     }
 
     private static String[] getProjection() {
-        String[] oColumns = new String[] {
+        String[] oColumns = new String[]{
                 WatchNextPrograms.COLUMN_WATCH_NEXT_TYPE,
                 WatchNextPrograms.COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS,
         };
@@ -208,6 +228,7 @@
 
         /**
          * Creates a new Builder object with values copied from another Program.
+         *
          * @param other The Program you're copying from.
          */
         public Builder(WatchNextProgram other) {
@@ -235,7 +256,8 @@
          * Sets the time when the program is going to begin in milliseconds since the epoch.
          *
          * @param lastEngagementTimeUtcMillis The value of
-         * {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS} for the program.
+         *      {@link WatchNextPrograms#COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS}
+         *      for the program.
          * @return This Builder object to allow for chaining of calls to builder methods.
          */
         public Builder setLastEngagementTimeUtcMillis(long lastEngagementTimeUtcMillis) {
diff --git a/v13/build.gradle b/v13/build.gradle
index 82a48bd..cb9cdbf 100644
--- a/v13/build.gradle
+++ b/v13/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v14/preference/build.gradle b/v14/preference/build.gradle
index 86036bd..43f6e36 100644
--- a/v14/preference/build.gradle
+++ b/v14/preference/build.gradle
@@ -14,8 +14,8 @@
  * limitations under the License
  */
 
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v4/build.gradle b/v4/build.gradle
index 8725a46..640c5fe 100644
--- a/v4/build.gradle
+++ b/v4/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/appcompat/build.gradle b/v7/appcompat/build.gradle
index 799b7b3..2f50fff 100644
--- a/v7/appcompat/build.gradle
+++ b/v7/appcompat/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -17,7 +17,7 @@
     androidTestImplementation(ESPRESSO_CORE)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
-    androidTestImplementation project(':support-testutils'), {
+    androidTestImplementation project(':internal-testutils'), {
         exclude group: 'com.android.support', module: 'appcompat-v7'
     }
 }
@@ -36,6 +36,10 @@
         additionalParameters "--no-version-vectors"
         noCompress 'ttf'
     }
+
+    buildTypes.all {
+        consumerProguardFiles("proguard-rules.pro")
+    }
 }
 
 supportLibrary {
diff --git a/v7/appcompat/proguard-rules.pro b/v7/appcompat/proguard-rules.pro
new file mode 100644
index 0000000..98c23e5
--- /dev/null
+++ b/v7/appcompat/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Copyright (C) 2018 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.
+
+# Ensure that reflectively-loaded inflater is not obfuscated. This can be
+# removed when we stop supporting AAPT1 builds.
+-keepnames class android.support.v7.app.AppCompatViewInflater
diff --git a/v7/appcompat/res/values-land/dimens.xml b/v7/appcompat/res/values-land/dimens.xml
deleted file mode 100644
index f0b6892..0000000
--- a/v7/appcompat/res/values-land/dimens.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 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.
--->
-
-<resources>
-    <!-- Size of the indeterminate Progress Bar -->
-    <dimen name="abc_action_bar_progress_bar_size">32dp</dimen>
-
-</resources>
\ No newline at end of file
diff --git a/v7/appcompat/res/values-or/strings.xml b/v7/appcompat/res/values-or/strings.xml
index cf09b6e..4dc6eb4 100644
--- a/v7/appcompat/res/values-or/strings.xml
+++ b/v7/appcompat/res/values-or/strings.xml
@@ -20,8 +20,7 @@
     <string name="abc_action_bar_home_description" msgid="4600421777120114993">"ହୋମ୍ ପେଜ୍‍କୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
     <string name="abc_action_bar_up_description" msgid="1594238315039666878">"ଉପରକୁ ନେଭିଗେଟ୍ କରନ୍ତୁ"</string>
     <string name="abc_action_menu_overflow_description" msgid="3588849162933574182">"ଅଧିକ ବିକଳ୍ପ"</string>
-    <!-- no translation found for abc_toolbar_collapse_description (1603543279005712093) -->
-    <skip />
+    <string name="abc_toolbar_collapse_description" msgid="1603543279005712093">"ଛୋଟ କରନ୍ତୁ"</string>
     <string name="abc_searchview_description_search" msgid="8264924765203268293">"ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
     <string name="abc_search_hint" msgid="7723749260725869598">"ସର୍ଚ୍ଚ…"</string>
     <string name="abc_searchview_description_query" msgid="2550479030709304392">"ସର୍ଚ୍ଚ କ୍ୱେରୀ"</string>
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
index d42174f..7f636bd 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/app/NightModeTestCase.java
@@ -30,8 +30,6 @@
 import android.support.test.filters.LargeTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.AppCompatActivityUtils;
-import android.support.testutils.RecreatedAppCompatActivity;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.appcompat.test.R;
 
@@ -43,6 +41,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.testutils.AppCompatActivityUtils;
+import androidx.testutils.RecreatedAppCompatActivity;
+
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class NightModeTestCase {
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
index e4dbf26..c880768 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/testutils/BaseTestActivity.java
@@ -19,7 +19,6 @@
 import android.os.Bundle;
 import android.support.annotation.NonNull;
 import android.support.annotation.Nullable;
-import android.support.testutils.RecreatedAppCompatActivity;
 import android.support.v7.app.AppCompatCallback;
 import android.support.v7.appcompat.test.R;
 import android.support.v7.view.ActionMode;
@@ -28,6 +27,8 @@
 import android.view.MenuItem;
 import android.view.WindowManager;
 
+import androidx.testutils.RecreatedAppCompatActivity;
+
 public abstract class BaseTestActivity extends RecreatedAppCompatActivity {
 
     private Menu mMenu;
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
index cae216d..c1326ac 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/widget/PopupMenuTest.java
@@ -56,7 +56,6 @@
 import android.support.test.filters.SdkSuppress;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.support.v4.view.MenuItemCompat;
 import android.support.v7.appcompat.test.R;
 import android.text.TextUtils;
@@ -80,6 +79,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.PollingCheck;
+
 @RunWith(AndroidJUnit4.class)
 public class PopupMenuTest {
     @Rule
diff --git a/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
index ea919e8..7d61d54 100644
--- a/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
+++ b/v7/appcompat/src/androidTest/java/android/support/v7/widget/SearchView_CursorTest.java
@@ -36,7 +36,6 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.support.v4.widget.CursorAdapter;
 import android.support.v4.widget.SimpleCursorAdapter;
 import android.support.v7.appcompat.test.R;
@@ -50,6 +49,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import androidx.testutils.PollingCheck;
+
 /**
  * Test {@link SearchView} with {@link Cursor}-backed suggestions adapter.
  */
diff --git a/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java b/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
index 1c17922..db8c1a2 100644
--- a/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
+++ b/v7/appcompat/src/main/java/android/support/v7/app/WindowDecorActionBar.java
@@ -239,7 +239,7 @@
             return ((Toolbar) view).getWrapper();
         } else {
             throw new IllegalStateException("Can't make a decor toolbar out of " +
-                    view != null ? view.getClass().getSimpleName() : "null");
+                    (view != null ? view.getClass().getSimpleName() : "null"));
         }
     }
 
diff --git a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
index 0b5cb48..8e58754 100644
--- a/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
+++ b/v7/appcompat/src/main/java/android/support/v7/view/menu/ListMenuItemView.java
@@ -196,9 +196,8 @@
         if (checkable) {
             compoundButton.setChecked(mItemData.isChecked());
 
-            final int newVisibility = checkable ? VISIBLE : GONE;
-            if (compoundButton.getVisibility() != newVisibility) {
-                compoundButton.setVisibility(newVisibility);
+            if (compoundButton.getVisibility() != VISIBLE) {
+                compoundButton.setVisibility(VISIBLE);
             }
 
             // Make sure the other compound button isn't visible
diff --git a/v7/cardview/build.gradle b/v7/cardview/build.gradle
index 88ce452..cb597ad 100644
--- a/v7/cardview/build.gradle
+++ b/v7/cardview/build.gradle
@@ -1,5 +1,5 @@
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/gridlayout/build.gradle b/v7/gridlayout/build.gradle
index 329cb00..85021b1 100644
--- a/v7/gridlayout/build.gradle
+++ b/v7/gridlayout/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/mediarouter/build.gradle b/v7/mediarouter/build.gradle
index f28938b..3d19227 100644
--- a/v7/mediarouter/build.gradle
+++ b/v7/mediarouter/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java
index cc372ec..a80ed00 100644
--- a/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java
+++ b/v7/mediarouter/src/main/java/android/support/v7/media/MediaRouter.java
@@ -1632,14 +1632,19 @@
                 if (descriptor != null) {
                     List<String> groupMemberIds = descriptor.getGroupMemberIds();
                     List<RouteInfo> routes = new ArrayList<>();
-                    changed = groupMemberIds.size() != mRoutes.size();
-                    for (String groupMemberId : groupMemberIds) {
-                        String uniqueId = sGlobal.getUniqueId(getProvider(), groupMemberId);
-                        RouteInfo groupMember = sGlobal.getRoute(uniqueId);
-                        if (groupMember != null) {
-                            routes.add(groupMember);
-                            if (!changed && !mRoutes.contains(groupMember)) {
-                                changed = true;
+                    if (groupMemberIds == null) {
+                        Log.w(TAG, "groupMemberIds shouldn't be null.");
+                        changed = true;
+                    } else {
+                        changed = groupMemberIds.size() != mRoutes.size();
+                        for (String groupMemberId : groupMemberIds) {
+                            String uniqueId = sGlobal.getUniqueId(getProvider(), groupMemberId);
+                            RouteInfo groupMember = sGlobal.getRoute(uniqueId);
+                            if (groupMember != null) {
+                                routes.add(groupMember);
+                                if (!changed && !mRoutes.contains(groupMember)) {
+                                    changed = true;
+                                }
                             }
                         }
                     }
@@ -2289,10 +2294,10 @@
                             final MediaRouteDescriptor routeDescriptor = routeDescriptors.get(i);
                             final String id = routeDescriptor.getId();
                             final int sourceIndex = provider.findRouteByDescriptorId(id);
+                            boolean isGroup = routeDescriptor.getGroupMemberIds() != null;
                             if (sourceIndex < 0) {
                                 // 1. Add the route to the list.
                                 String uniqueId = assignRouteUniqueId(provider, id);
-                                boolean isGroup = routeDescriptor.getGroupMemberIds() != null;
                                 RouteInfo route = isGroup ? new RouteGroup(provider, id, uniqueId) :
                                         new RouteInfo(provider, id, uniqueId);
                                 provider.mRoutes.add(targetIndex++, route);
@@ -2313,15 +2318,22 @@
                                 Log.w(TAG, "Ignoring route descriptor with duplicate id: "
                                         + routeDescriptor);
                             } else {
-                                // 1. Reorder the route within the list.
                                 RouteInfo route = provider.mRoutes.get(sourceIndex);
+                                // 1. Replace route if a group route becomes a normal route
+                                // or vice versa.
+                                if ((route instanceof RouteGroup) != isGroup) {
+                                    route = isGroup ? new RouteGroup(provider, id, route.getId()) :
+                                            new RouteInfo(provider, id, route.getId());
+                                    provider.mRoutes.set(sourceIndex, route);
+                                }
+                                // 2. Reorder the route within the list.
                                 Collections.swap(provider.mRoutes,
                                         sourceIndex, targetIndex++);
-                                // 2. Update the route's contents.
+                                // 3. Update the route's contents.
                                 if (route instanceof RouteGroup) {
                                     updatedGroups.add(new Pair<>(route, routeDescriptor));
                                 } else {
-                                    // 3. Notify clients about changes.
+                                    // 4. Notify clients about changes.
                                     if (updateRouteDescriptorAndNotify(route, routeDescriptor)
                                             != 0) {
                                         if (route == mSelectedRoute) {
diff --git a/v7/palette/build.gradle b/v7/palette/build.gradle
index 8829dcb..9c91601 100644
--- a/v7/palette/build.gradle
+++ b/v7/palette/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/preference/build.gradle b/v7/preference/build.gradle
index 7707883..a0c9bd9 100644
--- a/v7/preference/build.gradle
+++ b/v7/preference/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/v7/preference/lint-baseline.xml b/v7/preference/lint-baseline.xml
index a069f13..884c7da 100644
--- a/v7/preference/lint-baseline.xml
+++ b/v7/preference/lint-baseline.xml
@@ -3,39 +3,6 @@
 
     <issue
         id="NewApi"
-        message="`@android:id/icon_frame` requires API level 24 (current min is 14)"
-        errorLine1="        android:id=&quot;@android:id/icon_frame&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/layout-v7/expand_button.xml"
-            line="31"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="`?android:attr/textAppearanceListItemSecondary` requires API level 21 (current min is 14)"
-        errorLine1="            android:textAppearance=&quot;?android:attr/textAppearanceListItemSecondary&quot;"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/layout-v7/expand_button.xml"
-            line="69"
-            column="13"/>
-    </issue>
-
-    <issue
-        id="NewApi"
-        message="Using theme references in XML drawables requires API level 21 (current min is 14)"
-        errorLine1="        android:tint=&quot;?android:attr/colorAccent&quot;>"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="res/drawable/ic_arrow_down_24dp.xml"
-            line="22"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="NewApi"
         message="`@android:id/list_container` requires API level 24 (current min is 14)"
         errorLine1="        android:id=&quot;@android:id/list_container&quot;"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
@@ -62,17 +29,6 @@
         errorLine1="        android:layout_width=&quot;0dp&quot;"
         errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~">
         <location
-            file="res/layout-v11/preference_dropdown.xml"
-            line="30"
-            column="9"/>
-    </issue>
-
-    <issue
-        id="Suspicious0dp"
-        message="Suspicious size: this will make the view invisible, should be used with `layout_weight`"
-        errorLine1="        android:layout_width=&quot;0dp&quot;"
-        errorLine2="        ~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
             file="res/layout-v17/preference_dropdown_material.xml"
             line="32"
             column="9"/>
diff --git a/v7/preference/res/values/attrs.xml b/v7/preference/res/values/attrs.xml
index bb52593..332a3df 100644
--- a/v7/preference/res/values/attrs.xml
+++ b/v7/preference/res/values/attrs.xml
@@ -176,6 +176,9 @@
         <attr name="iconSpaceReserved" format="boolean" />
         <attr name="android:iconSpaceReserved" />
 
+        <!-- Whether the Preference is visible. By default, this is set to true. -->
+        <attr name="isPreferenceVisible" format="boolean" />
+
     </declare-styleable>
 
     <!-- Base attributes available to CheckBoxPreference. -->
diff --git a/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java
new file mode 100644
index 0000000..9000f15
--- /dev/null
+++ b/v7/preference/src/androidTest/java/android/support/v7/preference/tests/PreferenceVisibilityTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.v7.preference.tests;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+import android.support.v7.preference.test.R;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test for {@link android.support.v7.preference.Preference} visibility set with XML.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PreferenceVisibilityTest {
+
+    @Test
+    @UiThreadTest
+    public void testPreferencesAreCreatedWithTheVisibilitySetInXml() {
+        final Context context = InstrumentationRegistry.getTargetContext();
+        final PreferenceManager manager = new PreferenceManager(context);
+        final PreferenceScreen screen = manager.inflateFromResource(context,
+                R.layout.test_visibility,
+                null);
+
+        // Preference without visibility set should be visible
+        assertTrue(screen.getPreference(0).isVisible());
+        // Preference with visibility set to true should be visible
+        assertTrue(screen.getPreference(1).isVisible());
+        // Preference with visibility set to false should not be invisible
+        assertFalse(screen.getPreference(2).isVisible());
+    }
+}
diff --git a/v7/preference/src/androidTest/res/layout/test_visibility.xml b/v7/preference/src/androidTest/res/layout/test_visibility.xml
new file mode 100644
index 0000000..5623cd1
--- /dev/null
+++ b/v7/preference/src/androidTest/res/layout/test_visibility.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Copyright (C) 2018 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.
+-->
+<PreferenceScreen
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+    <Preference android:summary="This preference is visible by default" />
+
+    <Preference
+        android:summary="This preference is forced to be visible"
+        app:isPreferenceVisible="true" />
+
+    <Preference
+        android:summary="This preference is invisible"
+        app:isPreferenceVisible="false" />
+</PreferenceScreen>
diff --git a/v7/preference/src/main/java/android/support/v7/preference/Preference.java b/v7/preference/src/main/java/android/support/v7/preference/Preference.java
index 88262cd..79fbceb 100644
--- a/v7/preference/src/main/java/android/support/v7/preference/Preference.java
+++ b/v7/preference/src/main/java/android/support/v7/preference/Preference.java
@@ -323,6 +323,9 @@
         mIconSpaceReserved = TypedArrayUtils.getBoolean(a, R.styleable.Preference_iconSpaceReserved,
                 R.styleable.Preference_android_iconSpaceReserved, false);
 
+        mVisible = TypedArrayUtils.getBoolean(a, R.styleable.Preference_isPreferenceVisible,
+                R.styleable.Preference_isPreferenceVisible, true);
+
         a.recycle();
     }
 
@@ -871,6 +874,8 @@
      * {@link PreferenceFragmentCompat#findPreference(CharSequence)}.
      *
      * @param visible Set false if this preference should be hidden from the list.
+     *
+     * @attr ref R.styleable#Preference_isPreferenceVisible
      */
     public final void setVisible(boolean visible) {
         if (mVisible != visible) {
diff --git a/v7/recyclerview/build.gradle b/v7/recyclerview/build.gradle
index e58e5b1..5f7630c 100644
--- a/v7/recyclerview/build.gradle
+++ b/v7/recyclerview/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
@@ -18,7 +18,7 @@
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it"s own MockMaker
     androidTestImplementation(JUNIT)
     androidTestImplementation(KOTLIN_STDLIB)
-    androidTestImplementation(project(":support-testutils"))
+    androidTestImplementation(project(":internal-testutils"))
 
     testImplementation(JUNIT)
     testImplementation(MOCKITO_CORE)
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index e47a480..cf6e228 100644
--- a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -36,7 +36,6 @@
 import android.support.annotation.Nullable;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.rule.ActivityTestRule;
-import android.support.testutils.PollingCheck;
 import android.support.v4.view.ViewCompat;
 import android.support.v7.recyclerview.test.R;
 import android.util.Log;
@@ -63,6 +62,8 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import androidx.testutils.PollingCheck;
+
 abstract public class BaseRecyclerViewInstrumentationTest {
 
     private static final String TAG = "RecyclerViewTest";
@@ -80,7 +81,8 @@
     Thread mInstrumentationThread;
 
     @Rule
-    public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule(TestActivity.class);
+    public ActivityTestRule<TestActivity> mActivityRule =
+            new ActivityTestRule<>(TestActivity.class);
 
     public BaseRecyclerViewInstrumentationTest() {
         this(false);
diff --git a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
index 99d1066..6d73fbc 100644
--- a/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
+++ b/v7/recyclerview/src/androidTest/java/android/support/v7/widget/helper/ItemTouchHelperTest.java
@@ -32,7 +32,6 @@
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
-import android.support.testutils.PollingCheck;
 import android.support.v4.util.Pair;
 import android.support.v7.util.TouchUtils;
 import android.support.v7.widget.BaseRecyclerViewInstrumentationTest;
@@ -47,6 +46,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import androidx.testutils.PollingCheck;
+
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class ItemTouchHelperTest extends BaseRecyclerViewInstrumentationTest {
diff --git a/viewpager/api/0.0.0.txt b/viewpager/api/0.0.0.txt
new file mode 100644
index 0000000..31baf49
--- /dev/null
+++ b/viewpager/api/0.0.0.txt
@@ -0,0 +1,125 @@
+package android.support.v4.view {
+
+  public abstract class PagerAdapter {
+    ctor public PagerAdapter();
+    method public void destroyItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void destroyItem(android.view.View, int, java.lang.Object);
+    method public void finishUpdate(android.view.ViewGroup);
+    method public deprecated void finishUpdate(android.view.View);
+    method public abstract int getCount();
+    method public int getItemPosition(java.lang.Object);
+    method public java.lang.CharSequence getPageTitle(int);
+    method public float getPageWidth(int);
+    method public java.lang.Object instantiateItem(android.view.ViewGroup, int);
+    method public deprecated java.lang.Object instantiateItem(android.view.View, int);
+    method public abstract boolean isViewFromObject(android.view.View, java.lang.Object);
+    method public void notifyDataSetChanged();
+    method public void registerDataSetObserver(android.database.DataSetObserver);
+    method public void restoreState(android.os.Parcelable, java.lang.ClassLoader);
+    method public android.os.Parcelable saveState();
+    method public void setPrimaryItem(android.view.ViewGroup, int, java.lang.Object);
+    method public deprecated void setPrimaryItem(android.view.View, int, java.lang.Object);
+    method public void startUpdate(android.view.ViewGroup);
+    method public deprecated void startUpdate(android.view.View);
+    method public void unregisterDataSetObserver(android.database.DataSetObserver);
+    field public static final int POSITION_NONE = -2; // 0xfffffffe
+    field public static final int POSITION_UNCHANGED = -1; // 0xffffffff
+  }
+
+  public class PagerTabStrip extends android.support.v4.view.PagerTitleStrip {
+    ctor public PagerTabStrip(android.content.Context);
+    ctor public PagerTabStrip(android.content.Context, android.util.AttributeSet);
+    method public boolean getDrawFullUnderline();
+    method public int getTabIndicatorColor();
+    method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setDrawFullUnderline(boolean);
+    method public void setTabIndicatorColor(int);
+    method public void setTabIndicatorColorResource(int);
+  }
+
+  public class PagerTitleStrip extends android.view.ViewGroup {
+    ctor public PagerTitleStrip(android.content.Context);
+    ctor public PagerTitleStrip(android.content.Context, android.util.AttributeSet);
+    method public int getTextSpacing();
+    method public void setGravity(int);
+    method public void setNonPrimaryAlpha(float);
+    method public void setTextColor(int);
+    method public void setTextSize(int, float);
+    method public void setTextSpacing(int);
+  }
+
+  public class ViewPager extends android.view.ViewGroup {
+    ctor public ViewPager(android.content.Context);
+    ctor public ViewPager(android.content.Context, android.util.AttributeSet);
+    method public void addOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void addOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public boolean arrowScroll(int);
+    method public boolean beginFakeDrag();
+    method protected boolean canScroll(android.view.View, boolean, int, int, int);
+    method public void clearOnPageChangeListeners();
+    method public void endFakeDrag();
+    method public boolean executeKeyEvent(android.view.KeyEvent);
+    method public void fakeDragBy(float);
+    method public android.support.v4.view.PagerAdapter getAdapter();
+    method public int getCurrentItem();
+    method public int getOffscreenPageLimit();
+    method public int getPageMargin();
+    method public boolean isFakeDragging();
+    method protected void onPageScrolled(int, float, int);
+    method public void onRestoreInstanceState(android.os.Parcelable);
+    method public android.os.Parcelable onSaveInstanceState();
+    method public void removeOnAdapterChangeListener(android.support.v4.view.ViewPager.OnAdapterChangeListener);
+    method public void removeOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setAdapter(android.support.v4.view.PagerAdapter);
+    method public void setCurrentItem(int);
+    method public void setCurrentItem(int, boolean);
+    method public void setOffscreenPageLimit(int);
+    method public deprecated void setOnPageChangeListener(android.support.v4.view.ViewPager.OnPageChangeListener);
+    method public void setPageMargin(int);
+    method public void setPageMarginDrawable(android.graphics.drawable.Drawable);
+    method public void setPageMarginDrawable(int);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer);
+    method public void setPageTransformer(boolean, android.support.v4.view.ViewPager.PageTransformer, int);
+    field public static final int SCROLL_STATE_DRAGGING = 1; // 0x1
+    field public static final int SCROLL_STATE_IDLE = 0; // 0x0
+    field public static final int SCROLL_STATE_SETTLING = 2; // 0x2
+  }
+
+  public static abstract class ViewPager.DecorView implements java.lang.annotation.Annotation {
+  }
+
+  public static class ViewPager.LayoutParams extends android.view.ViewGroup.LayoutParams {
+    ctor public ViewPager.LayoutParams();
+    ctor public ViewPager.LayoutParams(android.content.Context, android.util.AttributeSet);
+    field public int gravity;
+    field public boolean isDecor;
+  }
+
+  public static abstract interface ViewPager.OnAdapterChangeListener {
+    method public abstract void onAdapterChanged(android.support.v4.view.ViewPager, android.support.v4.view.PagerAdapter, android.support.v4.view.PagerAdapter);
+  }
+
+  public static abstract interface ViewPager.OnPageChangeListener {
+    method public abstract void onPageScrollStateChanged(int);
+    method public abstract void onPageScrolled(int, float, int);
+    method public abstract void onPageSelected(int);
+  }
+
+  public static abstract interface ViewPager.PageTransformer {
+    method public abstract void transformPage(android.view.View, float);
+  }
+
+  public static class ViewPager.SavedState extends android.support.v4.view.AbsSavedState {
+    ctor public ViewPager.SavedState(android.os.Parcelable);
+    field public static final android.os.Parcelable.Creator<android.support.v4.view.ViewPager.SavedState> CREATOR;
+  }
+
+  public static class ViewPager.SimpleOnPageChangeListener implements android.support.v4.view.ViewPager.OnPageChangeListener {
+    ctor public ViewPager.SimpleOnPageChangeListener();
+    method public void onPageScrollStateChanged(int);
+    method public void onPageScrolled(int, float, int);
+    method public void onPageSelected(int);
+  }
+
+}
+
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
index fdf3b29..5da06de 100644
--- a/viewpager/build.gradle
+++ b/viewpager/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index a4eb3ad..d645f3c 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -14,16 +14,16 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
 }
 
 dependencies {
-    api(project(":support-core-utils"))
+    api(project(":support-fragment"))
     api(project(":recyclerview-v7"))
 
     androidTestImplementation(TEST_RUNNER)
diff --git a/viewpager2/src/androidTest/AndroidManifest.xml b/viewpager2/src/androidTest/AndroidManifest.xml
index ac723e6..22028ad 100755
--- a/viewpager2/src/androidTest/AndroidManifest.xml
+++ b/viewpager2/src/androidTest/AndroidManifest.xml
@@ -15,10 +15,10 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.widget.viewpager2.test">
+          package="androidx.viewpager2.test">
     <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application android:supportsRtl="true">
-        <activity android:name="androidx.widget.viewpager2.tests.TestActivity"/>
+        <activity android:name="androidx.viewpager2.widget.tests.TestActivity"/>
     </application>
 </manifest>
\ No newline at end of file
diff --git a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
similarity index 81%
rename from viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java
rename to viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
index 351ad9a..f94d9d6 100644
--- a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/TestActivity.java
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/TestActivity.java
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-package androidx.widget.viewpager2.tests;
+package androidx.viewpager2.widget.tests;
 
-import android.app.Activity;
 import android.os.Bundle;
+import android.support.v4.app.FragmentActivity;
 
-import androidx.widget.viewpager2.test.R;
+import androidx.viewpager2.test.R;
 
-public class TestActivity extends Activity {
+public class TestActivity extends FragmentActivity {
     @Override
     public void onCreate(Bundle bundle) {
         super.onCreate(bundle);
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java
new file mode 100644
index 0000000..119256d
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/tests/ViewPager2Tests.java
@@ -0,0 +1,571 @@
+/*
+ * 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 androidx.viewpager2.widget.tests;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
+import static android.view.View.OVER_SCROLL_NEVER;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.ViewActions;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.v4.app.Fragment;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import androidx.viewpager2.test.R;
+import androidx.viewpager2.widget.ViewPager2;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class ViewPager2Tests {
+    private static final Random RANDOM = new Random();
+    private static final int[] sColors = {
+            Color.parseColor("#BBA9FF00"),
+            Color.parseColor("#BB00E87E"),
+            Color.parseColor("#BB00C7FF"),
+            Color.parseColor("#BBB30CE8"),
+            Color.parseColor("#BBFF00D0")};
+
+    @Rule
+    public final ActivityTestRule<TestActivity> mActivityTestRule;
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
+    private ViewPager2 mViewPager;
+
+    // allows to wait until swipe operation is finished (Smooth Scroller done)
+    private CountDownLatch mStableAfterSwipe;
+
+    public ViewPager2Tests() {
+        mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
+    }
+
+    @Before
+    public void setUp() {
+        mViewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
+
+        mViewPager.addOnScrollListener(new RecyclerView.OnScrollListener() {
+            @Override
+            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+                // coming to idle from another state (dragging or setting) means we're stable now
+                if (newState == SCROLL_STATE_IDLE) {
+                    mStableAfterSwipe.countDown();
+                }
+            }
+        });
+
+        final long seed = RANDOM.nextLong();
+        RANDOM.setSeed(seed);
+        Log.i(getClass().getName(), "Random seed: " + seed);
+    }
+
+    public static class PageFragment extends Fragment {
+        private static final String KEY_VALUE = "value";
+
+        public interface EventListener {
+            void onEvent(PageFragment fragment);
+
+            EventListener NO_OP = new EventListener() {
+                @Override
+                public void onEvent(PageFragment fragment) {
+                    // do nothing
+                }
+            };
+        }
+
+        private EventListener mOnAttachListener = EventListener.NO_OP;
+        private EventListener mOnDestroyListener = EventListener.NO_OP;
+
+        private int mPosition;
+        private int mValue;
+
+        public static PageFragment create(int position, int value) {
+            PageFragment result = new PageFragment();
+            Bundle args = new Bundle(1);
+            args.putInt(KEY_VALUE, value);
+            result.setArguments(args);
+            result.mPosition = position;
+            return result;
+        }
+
+        @Override
+        public void onAttach(Context context) {
+            super.onAttach(context);
+            mOnAttachListener.onEvent(this);
+        }
+
+        @NonNull
+        @Override
+        public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
+                @Nullable Bundle savedInstanceState) {
+            return inflater.inflate(R.layout.item_test_layout, container, false);
+        }
+
+        @Override
+        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
+            Bundle data = savedInstanceState != null ? savedInstanceState : getArguments();
+            setValue(data.getInt(KEY_VALUE));
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+            mOnDestroyListener.onEvent(this);
+        }
+
+        @Override
+        public void onSaveInstanceState(@NonNull Bundle outState) {
+            outState.putInt(KEY_VALUE, mValue);
+        }
+
+        public void setValue(int value) {
+            mValue = value;
+            TextView textView = getView().findViewById(R.id.text_view);
+            applyViewValue(textView, mValue);
+        }
+    }
+
+    private static void applyViewValue(TextView textView, int value) {
+        textView.setText(String.valueOf(value));
+        textView.setBackgroundColor(getColor(value));
+    }
+
+    private static int getColor(int value) {
+        return sColors[value % sColors.length];
+    }
+
+    @Test
+    public void fragmentAdapter_fullPass() throws Throwable {
+        testFragmentLifecycle(8, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0));
+    }
+
+    @Test
+    public void fragmentAdapter_random() throws Throwable {
+        final int totalPages = 10;
+        final int sequenceLength = 50;
+        testFragmentLifecycle_random(totalPages, sequenceLength, PageMutator.NO_OP);
+    }
+
+    @Test
+    public void fragmentAdapter_random_withMutations() throws Throwable {
+        final int totalPages = 10;
+        final int sequenceLength = 50;
+        testFragmentLifecycle_random(totalPages, sequenceLength, PageMutator.RANDOM);
+    }
+
+    private void testFragmentLifecycle_random(int totalPages, int sequenceLength,
+            PageMutator pageMutator) throws Throwable {
+        List<Integer> pageSequence = generateRandomPageSequence(totalPages, sequenceLength);
+
+        Log.i(getClass().getName(),
+                String.format("Testing with a sequence [%s]", TextUtils.join(", ", pageSequence)));
+
+        testFragmentLifecycle(totalPages, pageSequence, pageMutator);
+    }
+
+    @NonNull
+    private List<Integer> generateRandomPageSequence(int totalPages, int sequenceLength) {
+        List<Integer> pageSequence = new ArrayList<>(sequenceLength);
+
+        int pageIx = 0;
+        Double goRightProbability = null;
+        while (pageSequence.size() != sequenceLength) {
+            boolean goRight;
+            if (pageIx == 0) {
+                goRight = true;
+                goRightProbability = 0.7;
+            } else if (pageIx == totalPages - 1) { // last page
+                goRight = false;
+                goRightProbability = 0.3;
+            } else {
+                goRight = RANDOM.nextDouble() < goRightProbability;
+            }
+
+            pageSequence.add(goRight ? ++pageIx : --pageIx);
+        }
+
+        return pageSequence;
+    }
+
+    /**
+     * Test added when caught a bug: after the last swipe: actual=6, expected=4
+     * <p>
+     * Bug was caused by an invalid test assumption (new Fragment value can be inferred from number
+     * of instances created) - invalid in a case when we sometimes create Fragments off-screen and
+     * end up scrapping them.
+     **/
+    @Test
+    public void fragmentAdapter_regression1() throws Throwable {
+        testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 2, 1, 2, 3, 4));
+    }
+
+    /**
+     * Test added when caught a bug: after the last swipe: actual=4, expected=5
+     * <p>
+     * Bug was caused by mSavedStates.add(position, ...) instead of mSavedStates.set(position, ...)
+     **/
+    @Test
+    public void fragmentAdapter_regression2() throws Throwable {
+        testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 5));
+    }
+
+    /**
+     * Test added when caught a bug: after the last swipe: ArrayIndexOutOfBoundsException: length=5;
+     * index=-1 at androidx.viewpager2.widget.tests.ViewPager2Tests$PageFragment.onCreateView
+     * <p>
+     * Bug was caused by always saving states of unattached fragments as null (even if there was a
+     * valid previously saved state)
+     */
+    @Test
+    public void fragmentAdapter_regression3() throws Throwable {
+        testFragmentLifecycle(10, Arrays.asList(1, 2, 3, 2, 1, 2, 3, 2, 1, 0));
+    }
+
+    /** Goes left on left edge / right on right edge */
+    @Test
+    public void fragmentAdapter_edges() throws Throwable {
+        testFragmentLifecycle(4, Arrays.asList(0, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0));
+    }
+
+    private interface PageMutator {
+        void mutate(PageFragment fragment);
+
+        PageMutator NO_OP = new PageMutator() {
+            @Override
+            public void mutate(PageFragment fragment) {
+                // do nothing
+            }
+        };
+
+        /** At random modifies the page under Fragment */
+        PageMutator RANDOM = new PageMutator() {
+            @Override
+            public void mutate(PageFragment fragment) {
+                Random random = ViewPager2Tests.RANDOM;
+                if (random.nextDouble() < 0.125) {
+                    int delta = (1 + random.nextInt(5)) * sColors.length;
+                    fragment.setValue(fragment.mValue + delta);
+                }
+            }
+        };
+    }
+
+    /** @see this#testFragmentLifecycle(int, List, PageMutator) */
+    private void testFragmentLifecycle(final int totalPages, List<Integer> pageSequence)
+            throws Throwable {
+        testFragmentLifecycle(totalPages, pageSequence, PageMutator.NO_OP);
+    }
+
+    /**
+     * Verifies:
+     * <ul>
+     * <li>page content / background
+     * <li>maximum number of Fragments held in memory
+     * <li>Fragment state saving / restoring
+     * </ul>
+     */
+    private void testFragmentLifecycle(final int totalPages, List<Integer> pageSequence,
+            final PageMutator pageMutator) throws Throwable {
+        final AtomicInteger attachCount = new AtomicInteger(0);
+        final AtomicInteger destroyCount = new AtomicInteger(0);
+        final boolean[] wasEverAttached = new boolean[totalPages];
+        final PageFragment[] fragments = new PageFragment[totalPages];
+
+        final int[] expectedValues = new int[totalPages];
+        for (int i = 0; i < totalPages; i++) {
+            expectedValues[i] = i;
+        }
+
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mViewPager.setAdapter(mActivityTestRule.getActivity().getSupportFragmentManager(),
+                        new ViewPager2.FragmentProvider() {
+                            @Override
+                            public Fragment getItem(final int position) {
+                                // if the fragment was attached in the past, it means we have
+                                // provided it with the correct value already; give a dummy one
+                                // to prove state save / restore functionality works
+                                int value = wasEverAttached[position] ? -1 : position;
+                                PageFragment fragment = PageFragment.create(position, value);
+
+                                fragment.mOnAttachListener = new PageFragment.EventListener() {
+                                    @Override
+                                    public void onEvent(PageFragment fragment) {
+                                        attachCount.incrementAndGet();
+                                        wasEverAttached[fragment.mPosition] = true;
+                                    }
+                                };
+
+                                fragment.mOnDestroyListener = new PageFragment.EventListener() {
+                                    @Override
+                                    public void onEvent(PageFragment fragment) {
+                                        destroyCount.incrementAndGet();
+                                    }
+                                };
+
+                                fragments[position] = fragment;
+                                return fragment;
+                            }
+
+                            @Override
+                            public int getCount() {
+                                return totalPages;
+                            }
+                        }, ViewPager2.FragmentRetentionPolicy.SAVE_STATE);
+            }
+        });
+
+        final AtomicInteger currentPage = new AtomicInteger(0);
+        verifyView(expectedValues[currentPage.get()]);
+        for (int nextPage : pageSequence) {
+            swipe(currentPage.get(), nextPage, totalPages);
+            currentPage.set(nextPage);
+            verifyView(expectedValues[currentPage.get()]);
+
+            // TODO: validate Fragments that are instantiated, but not attached. No destruction
+            // steps are done to them - they're just left to the Garbage Collector. Maybe
+            // WeakReferences could help, but the GC behaviour is not predictable. Alternatively,
+            // we could only create Fragments onAttach, but there is a potential performance
+            // trade-off.
+            assertThat(attachCount.get() - destroyCount.get(), isBetween(1, 4));
+
+            mActivityTestRule.runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    final int page = currentPage.get();
+                    PageFragment fragment = fragments[page];
+                    pageMutator.mutate(fragment);
+                    expectedValues[page] = fragment.mValue;
+                }
+            });
+        }
+    }
+
+    private void swipe(int currentPageIx, int nextPageIx, int totalPages)
+            throws InterruptedException {
+        if (nextPageIx >= totalPages) {
+            throw new IllegalArgumentException("Invalid nextPageIx: >= totalPages.");
+        }
+
+        if (currentPageIx == nextPageIx) { // dedicated for testing edge behaviour
+            if (nextPageIx == 0) {
+                swipeRight(); // bounce off the left edge
+                return;
+            }
+            if (nextPageIx == totalPages - 1) { // bounce off the right edge
+                swipeLeft();
+                return;
+            }
+            throw new IllegalArgumentException(
+                    "Invalid sequence. Not on an edge, and currentPageIx/nextPageIx pages same.");
+        }
+
+        if (Math.abs(nextPageIx - currentPageIx) > 1) {
+            throw new IllegalArgumentException(
+                    "Specified nextPageIx not adjacent to the current page.");
+        }
+
+        if (nextPageIx > currentPageIx) {
+            swipeLeft();
+        } else {
+            swipeRight();
+        }
+    }
+
+    private Matcher<Integer> isBetween(int min, int max) {
+        return allOf(greaterThanOrEqualTo(min), lessThanOrEqualTo(max));
+    }
+
+    @Test
+    public void viewAdapter_rendersAndHandlesSwiping() throws Throwable {
+        final int totalPages = 8;
+
+        if (Build.VERSION.SDK_INT < 16) { // TODO(b/71500143): remove temporary workaround
+            RecyclerView mRecyclerView = (RecyclerView) mViewPager.getChildAt(0);
+            mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
+        }
+
+        onView(withId(mViewPager.getId())).check(matches(isDisplayed()));
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mViewPager.setAdapter(
+                        new Adapter<ViewHolder>() {
+                            @NonNull
+                            @Override
+                            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                                    int viewType) {
+                                return new ViewHolder(
+                                        mActivityTestRule.getActivity().getLayoutInflater().inflate(
+                                                R.layout.item_test_layout, parent, false)) {
+                                };
+                            }
+
+                            @Override
+                            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+                                TextView view = (TextView) holder.itemView;
+                                applyViewValue(view, position);
+                            }
+
+                            @Override
+                            public int getItemCount() {
+                                return totalPages;
+                            }
+                        });
+            }
+        });
+
+        List<Integer> pageSequence = Arrays.asList(0, 0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 6, 5, 4, 3, 2,
+                1, 0, 0, 0);
+        verifyView(0);
+        int currentPage = 0;
+        for (int nextPage : pageSequence) {
+            swipe(currentPage, nextPage, totalPages);
+            currentPage = nextPage;
+            verifyView(currentPage);
+        }
+    }
+
+    private void verifyView(int pageNumber) {
+        onView(allOf(withId(R.id.text_view), isDisplayed())).check(
+                matches(allOf(withText(String.valueOf(pageNumber)),
+                        new BackgroundColorMatcher(getColor(pageNumber)))));
+    }
+
+    private static class BackgroundColorMatcher extends BaseMatcher<View> {
+        private final int mColor;
+
+        BackgroundColorMatcher(int color) {
+            mColor = color;
+        }
+
+        @Override
+        public void describeTo(Description description) {
+            description.appendText("should have background color: ").appendValue(mColor);
+        }
+
+        @Override
+        public boolean matches(Object item) {
+            ColorDrawable background = (ColorDrawable) ((View) item).getBackground();
+            return background.getColor() == mColor;
+        }
+    }
+
+    private void swipeLeft() throws InterruptedException {
+        performSwipe(ViewActions.swipeLeft());
+    }
+
+    private void swipeRight() throws InterruptedException {
+        performSwipe(ViewActions.swipeRight());
+    }
+
+    private void performSwipe(ViewAction swipeAction) throws InterruptedException {
+        mStableAfterSwipe = new CountDownLatch(1);
+        onView(allOf(isDisplayed(), withId(R.id.text_view))).perform(swipeAction);
+        mStableAfterSwipe.await(1, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void itemViewSizeMatchParentEnforced() {
+        mExpectedException.expect(IllegalStateException.class);
+        mExpectedException.expectMessage(
+                "Item's root view must fill the whole ViewPager2 (use match_parent)");
+
+        ViewPager2 viewPager = new ViewPager2(InstrumentationRegistry.getContext());
+        viewPager.setAdapter(new Adapter<ViewHolder>() {
+            @NonNull
+            @Override
+            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                View view = new View(parent.getContext());
+                view.setLayoutParams(new ViewGroup.LayoutParams(50, 50)); // arbitrary fixed size
+                return new ViewHolder(view) {
+                };
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
+                // do nothing
+            }
+
+            @Override
+            public int getItemCount() {
+                return 1;
+            }
+        });
+
+        viewPager.measure(0, 0); // equivalent of unspecified
+    }
+
+    @Test
+    public void childrenNotAllowed() throws Exception {
+        mExpectedException.expect(IllegalStateException.class);
+        mExpectedException.expectMessage("ViewPager2 does not support direct child views");
+
+        Context context = InstrumentationRegistry.getContext();
+        ViewPager2 viewPager = new ViewPager2(context);
+        viewPager.addView(new View(context));
+    }
+
+    // TODO: verify correct padding behavior
+    // TODO: add test for screen orientation change
+    // TODO: port some of the fragment adapter tests as view adapter tests
+}
diff --git a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java b/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java
deleted file mode 100644
index 45b42aa..0000000
--- a/viewpager2/src/androidTest/java/androidx/widget/viewpager2/tests/ViewPager2Tests.java
+++ /dev/null
@@ -1,214 +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 androidx.widget.viewpager2.tests;
-
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_IDLE;
-import static android.support.v7.widget.RecyclerView.SCROLL_STATE_SETTLING;
-import static android.view.View.OVER_SCROLL_NEVER;
-
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.ViewAction;
-import android.support.test.espresso.action.ViewActions;
-import android.support.test.espresso.idling.CountingIdlingResource;
-import android.support.test.filters.MediumTest;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-import androidx.widget.ViewPager2;
-import androidx.widget.viewpager2.test.R;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class ViewPager2Tests {
-    private static final int[] sColors = {
-            Color.parseColor("#BBA9FF00"),
-            Color.parseColor("#BB00E87E"),
-            Color.parseColor("#BB00C7FF"),
-            Color.parseColor("#BBB30CE8"),
-            Color.parseColor("#BBFF00D0")};
-
-    @Rule
-    public final ActivityTestRule<TestActivity> mActivityTestRule;
-    @Rule
-    public ExpectedException mExpectedException = ExpectedException.none();
-
-    private ViewPager2 mViewPager;
-    private CountingIdlingResource mIdlingResource;
-
-    public ViewPager2Tests() {
-        mActivityTestRule = new ActivityTestRule<>(TestActivity.class);
-    }
-
-    @Before
-    public void setUp() {
-        mViewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
-
-        mIdlingResource = new CountingIdlingResource(getClass().getSimpleName() + "IdlingResource");
-        mViewPager.addOnScrollListener(new RecyclerView.OnScrollListener() {
-            @Override
-            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
-                if (newState == SCROLL_STATE_IDLE && !mIdlingResource.isIdleNow()) {
-                    mIdlingResource.decrement();
-                } else if (newState == SCROLL_STATE_SETTLING && mIdlingResource.isIdleNow()) {
-                    mIdlingResource.increment();
-                }
-            }
-        });
-        IdlingRegistry.getInstance().register(mIdlingResource);
-    }
-
-    @After
-    public void tearDown() {
-        IdlingRegistry.getInstance().unregister(mIdlingResource);
-    }
-
-    @Test
-    public void rendersAndHandlesSwiping() throws Throwable {
-        final int pageCount = sColors.length;
-
-        if (Build.VERSION.SDK_INT < 16) { // TODO(b/71500143): remove temporary workaround
-            RecyclerView mRecyclerView = (RecyclerView) mViewPager.getChildAt(0);
-            mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
-        }
-
-        onView(withId(mViewPager.getId())).check(matches(isDisplayed()));
-        mActivityTestRule.runOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                mViewPager.setAdapter(
-                        new Adapter<ViewHolder>() {
-                            @NonNull
-                            @Override
-                            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
-                                    int viewType) {
-                                return new ViewHolder(
-                                        mActivityTestRule.getActivity().getLayoutInflater().inflate(
-                                                R.layout.item_test_layout, parent, false)) {
-                                };
-                            }
-
-                            @Override
-                            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
-                                TextView view = (TextView) holder.itemView;
-                                view.setText(String.valueOf(position));
-                                view.setBackgroundColor(sColors[position]);
-                            }
-
-                            @Override
-                            public int getItemCount() {
-                                return pageCount;
-                            }
-                        });
-            }
-        });
-
-        final int pageIxFirst = 0;
-        final int pageIxLast = pageCount - 1;
-        final int swipeCount = pageCount + 1; // two swipes beyond edge to test 'edge behavior'
-        int pageNumber = pageIxFirst;
-        for (int i = 0; i < swipeCount; i++, pageNumber = Math.min(pageIxLast, ++pageNumber)) {
-            verifyView(pageNumber);
-            performSwipe(ViewActions.swipeLeft());
-        }
-        assertThat(pageNumber, equalTo(pageIxLast));
-        for (int i = 0; i < swipeCount; i++, pageNumber = Math.max(pageIxFirst, --pageNumber)) {
-            verifyView(pageNumber);
-            performSwipe(ViewActions.swipeRight());
-        }
-        assertThat(pageNumber, equalTo(pageIxFirst));
-    }
-
-    private void verifyView(int pageNumber) {
-        onView(allOf(withId(R.id.text_view), isDisplayed())).check(
-                matches(withText(String.valueOf(pageNumber))));
-    }
-
-    private void performSwipe(ViewAction swipeAction) throws InterruptedException {
-        onView(allOf(isDisplayed(), withId(R.id.text_view))).perform(swipeAction);
-    }
-
-    @Test
-    public void itemViewSizeMatchParentEnforced() {
-        mExpectedException.expect(IllegalStateException.class);
-        mExpectedException.expectMessage(
-                "Item's root view must fill the whole ViewPager2 (use match_parent)");
-
-        ViewPager2 viewPager = new ViewPager2(InstrumentationRegistry.getContext());
-        viewPager.setAdapter(new Adapter<ViewHolder>() {
-            @NonNull
-            @Override
-            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-                View view = new View(parent.getContext());
-                view.setLayoutParams(new ViewGroup.LayoutParams(50, 50)); // arbitrary fixed size
-                return new ViewHolder(view) {
-                };
-            }
-
-            @Override
-            public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
-                // do nothing
-            }
-
-            @Override
-            public int getItemCount() {
-                return 1;
-            }
-        });
-
-        viewPager.measure(0, 0); // equivalent of unspecified
-    }
-
-    @Test
-    public void childrenNotAllowed() throws Exception {
-        mExpectedException.expect(IllegalStateException.class);
-        mExpectedException.expectMessage("ViewPager2 does not support direct child views");
-
-        Context context = InstrumentationRegistry.getContext();
-        ViewPager2 viewPager = new ViewPager2(context);
-        viewPager.addView(new View(context));
-    }
-
-    // TODO: verify correct padding behavior
-    // TODO: add test for screen orientation change
-}
diff --git a/viewpager2/src/androidTest/res/layout/activity_test_layout.xml b/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
index 3037029..9d996ab 100644
--- a/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
+++ b/viewpager2/src/androidTest/res/layout/activity_test_layout.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<androidx.widget.ViewPager2
+<androidx.viewpager2.widget.ViewPager2
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/view_pager"
     android:layout_width="match_parent"
diff --git a/viewpager2/src/main/AndroidManifest.xml b/viewpager2/src/main/AndroidManifest.xml
index ebddd6c..cc03d91 100644
--- a/viewpager2/src/main/AndroidManifest.xml
+++ b/viewpager2/src/main/AndroidManifest.xml
@@ -14,4 +14,4 @@
      limitations under the License.
 -->
 
-<manifest package="androidx.widget.viewpager2"/>
\ No newline at end of file
+<manifest package="androidx.viewpager2"/>
\ No newline at end of file
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
new file mode 100644
index 0000000..ba40912
--- /dev/null
+++ b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
@@ -0,0 +1,358 @@
+/*
+ * 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 androidx.viewpager2.widget;
+
+import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+
+import static java.lang.annotation.RetentionPolicy.CLASS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.annotation.RestrictTo;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.app.FragmentStatePagerAdapter;
+import android.support.v4.view.ViewCompat;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.PagerSnapHelper;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.support.v7.widget.RecyclerView.ViewHolder;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import java.lang.annotation.Retention;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Work in progress: go/viewpager2
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class ViewPager2 extends ViewGroup {
+    // reused in layout(...)
+    private final Rect mTmpContainerRect = new Rect();
+    private final Rect mTmpChildRect = new Rect();
+
+    private RecyclerView mRecyclerView;
+
+    public ViewPager2(Context context) {
+        super(context);
+        initialize(context);
+    }
+
+    public ViewPager2(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        initialize(context);
+    }
+
+    @RequiresApi(21)
+    public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        // TODO(b/70663531): handle attrs, defStyleAttr, defStyleRes
+        super(context, attrs, defStyleAttr, defStyleRes);
+        initialize(context);
+    }
+
+    private void initialize(Context context) {
+        mRecyclerView = new RecyclerView(context);
+
+        LinearLayoutManager layoutManager = new LinearLayoutManager(context);
+        // TODO(b/69103581): add support for vertical layout
+        // TODO(b/69398856): add support for RTL
+        layoutManager.setOrientation(RecyclerView.HORIZONTAL);
+        mRecyclerView.setLayoutManager(layoutManager);
+
+        mRecyclerView.setLayoutParams(
+                new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
+
+        // TODO(b/70666992): add automated test for orientation change
+        new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
+
+        attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
+    }
+
+    /**
+     * TODO(b/70663708): decide on an Adapter class. Here supporting RecyclerView.Adapter.
+     *
+     * @see RecyclerView#setAdapter(Adapter)
+     */
+    public <VH extends ViewHolder> void setAdapter(final Adapter<VH> adapter) {
+        mRecyclerView.setAdapter(new Adapter<VH>() {
+            private final Adapter<VH> mAdapter = adapter;
+
+            @NonNull
+            @Override
+            public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+                VH viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
+
+                LayoutParams layoutParams = viewHolder.itemView.getLayoutParams();
+                if (layoutParams.width != LayoutParams.MATCH_PARENT
+                        || layoutParams.height != LayoutParams.MATCH_PARENT) {
+                    // TODO(b/70666614): decide if throw an exception or wrap in FrameLayout
+                    // ourselves; consider accepting exact size equal to parent's exact size
+                    throw new IllegalStateException(String.format(
+                            "Item's root view must fill the whole %s (use match_parent)",
+                            ViewPager2.this.getClass().getSimpleName()));
+                }
+
+                return viewHolder;
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull VH holder, int position) {
+                mAdapter.onBindViewHolder(holder, position);
+            }
+
+            @Override
+            public int getItemCount() {
+                return mAdapter.getItemCount();
+            }
+        });
+    }
+
+    /**
+     * TODO(b/70663708): decide on an Adapter class. Here supporting {@link Fragment}s.
+     *
+     * @param fragmentRetentionPolicy allows for future parameterization of Fragment memory
+     *                                strategy, similar to what {@link FragmentPagerAdapter} and
+     *                                {@link FragmentStatePagerAdapter} provide.
+     */
+    public void setAdapter(FragmentManager fragmentManager, FragmentProvider fragmentProvider,
+            @FragmentRetentionPolicy int fragmentRetentionPolicy) {
+        if (fragmentRetentionPolicy != FragmentRetentionPolicy.SAVE_STATE) {
+            throw new IllegalArgumentException("Currently only SAVE_STATE policy is supported");
+        }
+
+        mRecyclerView.setAdapter(new FragmentStateAdapter(fragmentManager, fragmentProvider));
+    }
+
+    /**
+     * Similar in behavior to {@link FragmentStatePagerAdapter}
+     * <p>
+     * Lifecycle within {@link RecyclerView}:
+     * <ul>
+     * <li>{@link RecyclerView.ViewHolder} initially an empty {@link FrameLayout}, serves as a
+     * re-usable container for a {@link Fragment} in later stages.
+     * <li>{@link RecyclerView.Adapter#onBindViewHolder} we ask for a {@link Fragment} for the
+     * position. If we already have the fragment, or have previously saved its state, we use those.
+     * <li>{@link RecyclerView.Adapter#onAttachedToWindow} we attach the {@link Fragment} to a
+     * container.
+     * <li>{@link RecyclerView.Adapter#onViewRecycled} and
+     * {@link RecyclerView.Adapter#onFailedToRecycleView} we remove, save state, destroy the
+     * {@link Fragment}.
+     * </ul>
+     */
+    private static class FragmentStateAdapter extends RecyclerView.Adapter<FragmentViewHolder> {
+        private final List<Fragment.SavedState> mSavedStates = new ArrayList<>();
+        // TODO: handle current item's menuVisibility userVisibleHint as FragmentStatePagerAdapter
+
+        private final FragmentManager mFragmentManager;
+        private final FragmentProvider mFragmentProvider;
+
+        private FragmentStateAdapter(FragmentManager fragmentManager,
+                FragmentProvider fragmentProvider) {
+            this.mFragmentManager = fragmentManager;
+            this.mFragmentProvider = fragmentProvider;
+        }
+
+        @NonNull
+        @Override
+        public FragmentViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+            return FragmentViewHolder.create(parent);
+        }
+
+        @Override
+        public void onBindViewHolder(@NonNull FragmentViewHolder holder, int position) {
+            if (ViewCompat.isAttachedToWindow(holder.getContainer())) {
+                // this should never happen; if it does, it breaks our assumption that attaching
+                // a Fragment can reliably happen inside onViewAttachedToWindow
+                throw new IllegalStateException(
+                        String.format("View %s unexpectedly attached to a window.",
+                                holder.getContainer()));
+            }
+
+            holder.mFragment = getFragment(position);
+        }
+
+        private Fragment getFragment(int position) {
+            Fragment fragment = mFragmentProvider.getItem(position);
+            if (mSavedStates.size() > position) {
+                Fragment.SavedState savedState = mSavedStates.get(position);
+                if (savedState != null) {
+                    fragment.setInitialSavedState(savedState);
+                }
+            }
+            return fragment;
+        }
+
+        @Override
+        public void onViewAttachedToWindow(@NonNull FragmentViewHolder holder) {
+            if (holder.mFragment.isAdded()) {
+                return;
+            }
+            mFragmentManager.beginTransaction().add(holder.getContainer().getId(),
+                    holder.mFragment).commitNowAllowingStateLoss();
+        }
+
+        @Override
+        public int getItemCount() {
+            return mFragmentProvider.getCount();
+        }
+
+        @Override
+        public void onViewRecycled(@NonNull FragmentViewHolder holder) {
+            removeFragment(holder);
+        }
+
+        @Override
+        public boolean onFailedToRecycleView(@NonNull FragmentViewHolder holder) {
+            // This happens when a ViewHolder is in a transient state (e.g. during custom
+            // animation). We don't have sufficient information on how to clear up what lead to
+            // the transient state, so we are throwing away the ViewHolder to stay on the
+            // conservative side.
+            removeFragment(holder);
+            return false; // don't recycle the view
+        }
+
+        private void removeFragment(@NonNull FragmentViewHolder holder) {
+            if (holder.mFragment == null) {
+                return; // fresh ViewHolder, nothing to do
+            }
+
+            int position = holder.getAdapterPosition();
+
+            if (holder.mFragment.isAdded()) {
+                while (mSavedStates.size() <= position) {
+                    mSavedStates.add(null);
+                }
+                mSavedStates.set(position,
+                        mFragmentManager.saveFragmentInstanceState(holder.mFragment));
+            }
+
+            mFragmentManager.beginTransaction().remove(
+                    holder.mFragment).commitNowAllowingStateLoss();
+            holder.mFragment = null;
+        }
+    }
+
+    private static class FragmentViewHolder extends RecyclerView.ViewHolder {
+        private Fragment mFragment;
+
+        private FragmentViewHolder(FrameLayout container) {
+            super(container);
+        }
+
+        static FragmentViewHolder create(ViewGroup parent) {
+            FrameLayout container = new FrameLayout(parent.getContext());
+            container.setLayoutParams(
+                    new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                            ViewGroup.LayoutParams.MATCH_PARENT));
+            container.setId(ViewCompat.generateViewId());
+            return new FragmentViewHolder(container);
+        }
+
+        FrameLayout getContainer() {
+            return (FrameLayout) itemView;
+        }
+    }
+
+    /**
+     * Provides {@link Fragment}s for pages
+     */
+    public interface FragmentProvider {
+        /**
+         * Return the Fragment associated with a specified position.
+         */
+        Fragment getItem(int position);
+
+        /**
+         * Return the number of pages available.
+         */
+        int getCount();
+    }
+
+    @Retention(CLASS)
+    @IntDef({FragmentRetentionPolicy.SAVE_STATE})
+    public @interface FragmentRetentionPolicy {
+        /** Approach similar to {@link FragmentStatePagerAdapter} */
+        int SAVE_STATE = 0;
+    }
+
+    @Override
+    public void onViewAdded(View child) {
+        // TODO(b/70666620): consider adding a support for Decor views
+        throw new IllegalStateException(
+                getClass().getSimpleName() + " does not support direct child views");
+    }
+
+    /** @see RecyclerView#addOnScrollListener(RecyclerView.OnScrollListener) */
+    public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
+        mRecyclerView.addOnScrollListener(listener);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // TODO(b/70666622): consider margin support
+        // TODO(b/70666626): consider delegating all this to RecyclerView
+        // TODO(b/70666625): write automated tests for this
+
+        measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
+        int width = mRecyclerView.getMeasuredWidth();
+        int height = mRecyclerView.getMeasuredHeight();
+        int childState = mRecyclerView.getMeasuredState();
+
+        width += getPaddingLeft() + getPaddingRight();
+        height += getPaddingTop() + getPaddingBottom();
+
+        width = Math.max(width, getSuggestedMinimumWidth());
+        height = Math.max(height, getSuggestedMinimumHeight());
+
+        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
+                resolveSizeAndState(height, heightMeasureSpec,
+                        childState << MEASURED_HEIGHT_STATE_SHIFT));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int width = mRecyclerView.getMeasuredWidth();
+        int height = mRecyclerView.getMeasuredHeight();
+
+        // TODO(b/70666626): consider delegating padding handling to the RecyclerView to avoid
+        // an unnatural page transition effect: http://shortn/_Vnug3yZpQT
+        mTmpContainerRect.left = getPaddingLeft();
+        mTmpContainerRect.right = r - l - getPaddingRight();
+        mTmpContainerRect.top = getPaddingTop();
+        mTmpContainerRect.bottom = b - t - getPaddingBottom();
+
+        Gravity.apply(Gravity.TOP | Gravity.START, width, height, mTmpContainerRect, mTmpChildRect);
+        mRecyclerView.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right,
+                mTmpChildRect.bottom);
+    }
+}
diff --git a/viewpager2/src/main/java/androidx/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/widget/ViewPager2.java
deleted file mode 100644
index 9ebdea1..0000000
--- a/viewpager2/src/main/java/androidx/widget/ViewPager2.java
+++ /dev/null
@@ -1,176 +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 androidx.widget;
-
-import static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.content.Context;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.RequiresApi;
-import android.support.annotation.RestrictTo;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.PagerSnapHelper;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.Adapter;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.View;
-import android.view.ViewGroup;
-
-/**
- * Work in progress: go/viewpager2
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ViewPager2 extends ViewGroup {
-    // reused in layout(...)
-    private final Rect mTmpContainerRect = new Rect();
-    private final Rect mTmpChildRect = new Rect();
-
-    private RecyclerView mRecyclerView;
-
-    public ViewPager2(Context context) {
-        super(context);
-        initialize(context);
-    }
-
-    public ViewPager2(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr) {
-        super(context, attrs, defStyleAttr);
-        initialize(context);
-    }
-
-    @RequiresApi(21)
-    public ViewPager2(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        // TODO(b/70663531): handle attrs, defStyleAttr, defStyleRes
-        super(context, attrs, defStyleAttr, defStyleRes);
-        initialize(context);
-    }
-
-    private void initialize(Context context) {
-        mRecyclerView = new RecyclerView(context);
-
-        LinearLayoutManager layoutManager = new LinearLayoutManager(context);
-        // TODO(b/69103581): add support for vertical layout
-        // TODO(b/69398856): add support for RTL
-        layoutManager.setOrientation(RecyclerView.HORIZONTAL);
-        mRecyclerView.setLayoutManager(layoutManager);
-
-        mRecyclerView.setLayoutParams(
-                new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-
-        // TODO(b/70666992): add automated test for orientation change
-        new PagerSnapHelper().attachToRecyclerView(mRecyclerView);
-
-        attachViewToParent(mRecyclerView, 0, mRecyclerView.getLayoutParams());
-    }
-
-    /**
-     * TODO(b/70663708): decide on an Adapter class (for now reusing RecyclerView.Adapter)
-     *
-     * @see RecyclerView#setAdapter(Adapter)
-     */
-    public <VH extends ViewHolder> void setAdapter(final Adapter<VH> adapter) {
-        mRecyclerView.setAdapter(new Adapter<VH>() {
-            private final Adapter<VH> mAdapter = adapter;
-
-            @NonNull
-            @Override
-            public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
-                VH viewHolder = mAdapter.onCreateViewHolder(parent, viewType);
-
-                LayoutParams layoutParams = viewHolder.itemView.getLayoutParams();
-                if ((layoutParams.width | layoutParams.height) != LayoutParams.MATCH_PARENT) {
-                    // TODO(b/70666614): decide if throw an exception or wrap in FrameLayout
-                    // ourselves; consider accepting exact size equal to parent's exact size
-                    throw new IllegalStateException(String.format(
-                            "Item's root view must fill the whole %s (use match_parent)",
-                            ViewPager2.this.getClass().getSimpleName()));
-                }
-
-                return viewHolder;
-            }
-
-            @Override
-            public void onBindViewHolder(@NonNull VH holder, int position) {
-                mAdapter.onBindViewHolder(holder, position);
-            }
-
-            @Override
-            public int getItemCount() {
-                return mAdapter.getItemCount();
-            }
-        });
-    }
-
-    @Override
-    public void onViewAdded(View child) {
-        // TODO(b/70666620): consider adding a support for Decor views
-        throw new IllegalStateException(
-                getClass().getSimpleName() + " does not support direct child views");
-    }
-
-    /** @see RecyclerView#addOnScrollListener(RecyclerView.OnScrollListener) */
-    public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
-        mRecyclerView.addOnScrollListener(listener);
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        // TODO(b/70666622): consider margin support
-        // TODO(b/70666626): consider delegating all this to RecyclerView
-        // TODO(b/70666625): write automated tests for this
-
-        measureChild(mRecyclerView, widthMeasureSpec, heightMeasureSpec);
-        int width = mRecyclerView.getMeasuredWidth();
-        int height = mRecyclerView.getMeasuredHeight();
-        int childState = mRecyclerView.getMeasuredState();
-
-        width += getPaddingLeft() + getPaddingRight();
-        height += getPaddingTop() + getPaddingBottom();
-
-        width = Math.max(width, getSuggestedMinimumWidth());
-        height = Math.max(height, getSuggestedMinimumHeight());
-
-        setMeasuredDimension(resolveSizeAndState(width, widthMeasureSpec, childState),
-                resolveSizeAndState(height, heightMeasureSpec,
-                        childState << MEASURED_HEIGHT_STATE_SHIFT));
-    }
-
-    @Override
-    protected void onLayout(boolean changed, int l, int t, int r, int b) {
-        int width = mRecyclerView.getMeasuredWidth();
-        int height = mRecyclerView.getMeasuredHeight();
-
-        // TODO(b/70666626): consider delegating padding handling to the RecyclerView to avoid
-        // an unnatural page transition effect: http://shortn/_Vnug3yZpQT
-        mTmpContainerRect.left = getPaddingLeft();
-        mTmpContainerRect.right = r - l - getPaddingRight();
-        mTmpContainerRect.top = getPaddingTop();
-        mTmpContainerRect.bottom = b - t - getPaddingBottom();
-
-        Gravity.apply(Gravity.TOP | Gravity.START, width, height, mTmpContainerRect, mTmpChildRect);
-        mRecyclerView.layout(mTmpChildRect.left, mTmpChildRect.top, mTmpChildRect.right,
-                mTmpChildRect.bottom);
-    }
-}
diff --git a/wear/build.gradle b/wear/build.gradle
index 2b832e7..ffc7990 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,6 +1,6 @@
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/webkit-codegen/build.gradle b/webkit-codegen/build.gradle
index 92090e1..891382b 100644
--- a/webkit-codegen/build.gradle
+++ b/webkit-codegen/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
+import static androidx.build.dependencies.DependenciesKt.*
 
 apply plugin: 'maven'
 apply plugin: 'application'
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index b0d66d6..2a39d42 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -1,7 +1,19 @@
 package androidx.webkit {
 
+  public class WebSettingsCompat {
+    method public static int getDisabledActionModeMenuItems(android.webkit.WebSettings);
+    method public static boolean getOffscreenPreRaster(android.webkit.WebSettings);
+    method public static boolean getSafeBrowsingEnabled(android.webkit.WebSettings);
+    method public static void setDisabledActionModeMenuItems(android.webkit.WebSettings, int);
+    method public static void setOffscreenPreRaster(android.webkit.WebSettings, boolean);
+    method public static void setSafeBrowsingEnabled(android.webkit.WebSettings, boolean);
+  }
+
   public class WebViewCompat {
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public static void postVisualStateCallback(android.webkit.WebView, long, androidx.webkit.WebViewCompat.VisualStateCallback);
+    method public static void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
+    method public static void startSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
   }
 
   public static abstract interface WebViewCompat.VisualStateCallback {
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 6e099e1..b74fa88 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-import static android.support.dependencies.DependenciesKt.*
-import android.support.LibraryGroups
-import android.support.LibraryVersions
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
 
 plugins {
     id("SupportAndroidLibraryPlugin")
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
new file mode 100644
index 0000000..1e5c152
--- /dev/null
+++ b/webkit/src/androidTest/java/androidx/webkit/WebSettingsCompatTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.webkit.WebSettings;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class WebSettingsCompatTest {
+    WebViewOnUiThread mWebViewOnUiThread;
+
+    @Before
+    public void setUp() {
+        mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
+    }
+
+    @Test
+    public void testOffscreenPreRaster() {
+        // TODO(gsennton) activate this test for pre-M devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return;
+
+        assertFalse(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setOffscreenPreRaster(mWebViewOnUiThread.getSettings(), true);
+        assertTrue(WebSettingsCompat.getOffscreenPreRaster(mWebViewOnUiThread.getSettings()));
+    }
+
+    @Test
+    public void testEnableSafeBrowsing() throws Throwable {
+        // TODO(gsennton) activate this test for old devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) return;
+
+        WebSettingsCompat.setSafeBrowsingEnabled(mWebViewOnUiThread.getSettings(), false);
+        assertFalse(WebSettingsCompat.getSafeBrowsingEnabled(mWebViewOnUiThread.getSettings()));
+    }
+
+    @Test
+    public void testDisabledActionModeMenuItems() throws Throwable {
+        // TODO(gsennton) activate this test for old devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
+
+        assertEquals(WebSettings.MENU_ITEM_NONE,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+                WebSettings.MENU_ITEM_SHARE);
+        assertEquals(WebSettings.MENU_ITEM_SHARE,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+
+        WebSettingsCompat.setDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings(),
+                WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH);
+        assertEquals(WebSettings.MENU_ITEM_PROCESS_TEXT | WebSettings.MENU_ITEM_WEB_SEARCH,
+                WebSettingsCompat.getDisabledActionModeMenuItems(mWebViewOnUiThread.getSettings()));
+    }
+}
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index 8b38d99..a9ffead 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -17,20 +17,38 @@
 package androidx.webkit;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.Build;
+import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.support.v4.os.BuildCompat;
+import android.webkit.SafeBrowsingResponse;
+import android.webkit.ValueCallback;
+import android.webkit.WebResourceRequest;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
 
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+@MediumTest
 @RunWith(AndroidJUnit4.class)
 public class WebViewCompatTest {
     WebViewOnUiThread mWebViewOnUiThread;
@@ -42,7 +60,6 @@
         mWebViewOnUiThread = new androidx.webkit.WebViewOnUiThread();
     }
 
-    @MediumTest
     @Test
     public void testVisualStateCallbackCalled() throws Exception {
         // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
@@ -65,7 +82,6 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
-    @MediumTest
     @Test
     public void testCheckThread() {
         try {
@@ -80,4 +96,142 @@
         }
         fail("Calling a WebViewCompat method on the wrong thread must cause a run-time exception");
     }
+
+    private static class MockContext extends ContextWrapper {
+        private boolean mGetApplicationContextWasCalled;
+
+        MockContext(Context context) {
+            super(context);
+        }
+
+        public Context getApplicationContext() {
+            mGetApplicationContextWasCalled = true;
+            return super.getApplicationContext();
+        }
+
+        public boolean wasGetApplicationContextCalled() {
+            return mGetApplicationContextWasCalled;
+        }
+    }
+
+    @Test
+    public void testStartSafeBrowsingUseApplicationContext() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        final MockContext ctx =
+                new MockContext(InstrumentationRegistry.getTargetContext().getApplicationContext());
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebViewCompat.startSafeBrowsing(ctx, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean value) {
+                assertTrue(ctx.wasGetApplicationContextCalled());
+                resultLatch.countDown();
+                return;
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testStartSafeBrowsingWithNullCallbackDoesntCrash() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        WebViewCompat.startSafeBrowsing(InstrumentationRegistry.getTargetContext(), null);
+    }
+
+    @Test
+    public void testStartSafeBrowsingInvokesCallback() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebViewCompat.startSafeBrowsing(
+                InstrumentationRegistry.getTargetContext().getApplicationContext(),
+                new ValueCallback<Boolean>() {
+                    @Override
+                    public void onReceiveValue(Boolean value) {
+                        assertTrue(Looper.getMainLooper().isCurrentThread());
+                        resultLatch.countDown();
+                        return;
+                    }
+                });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSetSafeBrowsingWhitelistWithMalformedList() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        List whitelist = new ArrayList<String>();
+        // Protocols are not supported in the whitelist
+        whitelist.add("http://google.com");
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebViewCompat.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean success) {
+                assertFalse(success);
+                resultLatch.countDown();
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testSetSafeBrowsingWhitelistWithValidList() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        List whitelist = new ArrayList<String>();
+        whitelist.add("safe-browsing");
+        final CountDownLatch resultLatch = new CountDownLatch(1);
+        WebViewCompat.setSafeBrowsingWhitelist(whitelist, new ValueCallback<Boolean>() {
+            @Override
+            public void onReceiveValue(Boolean success) {
+                assertTrue(success);
+                resultLatch.countDown();
+            }
+        });
+        assertTrue(resultLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+
+        final CountDownLatch resultLatch2 = new CountDownLatch(1);
+        mWebViewOnUiThread.setWebViewClient(new WebViewClient() {
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                resultLatch2.countDown();
+            }
+
+            @Override
+            public void onSafeBrowsingHit(WebView view, WebResourceRequest request, int threatType,
+                    SafeBrowsingResponse callback) {
+                Assert.fail("Should not invoke onSafeBrowsingHit");
+            }
+        });
+
+        mWebViewOnUiThread.loadUrl("chrome://safe-browsing/match?type=malware");
+
+        // Wait until page load has completed
+        assertTrue(resultLatch2.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
+    }
+
+    @Test
+    public void testGetSafeBrowsingPrivacyPolicyUrl() throws Exception {
+        // TODO(gsennton) activate this test for pre-P devices when we can pre-install a WebView APK
+        // containing support for the WebView Support Library, see b/73454652.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) return;
+
+        assertNotNull(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl());
+        try {
+            new URL(WebViewCompat.getSafeBrowsingPrivacyPolicyUrl().toString());
+        } catch (MalformedURLException e) {
+            Assert.fail("The privacy policy URL should be a well-formed URL");
+        }
+    }
 }
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
index 6219bd3..9b4c9e9 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewOnUiThread.java
@@ -17,7 +17,9 @@
 package androidx.webkit;
 
 import android.support.test.InstrumentationRegistry;
+import android.webkit.WebSettings;
 import android.webkit.WebView;
+import android.webkit.WebViewClient;
 
 public class WebViewOnUiThread {
     private WebView mWebView;
@@ -40,6 +42,15 @@
         });
     }
 
+    public void setWebViewClient(final WebViewClient webviewClient) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+            @Override
+            public void run() {
+                mWebView.setWebViewClient(webviewClient);
+            }
+        });
+    }
+
     public void postVisualStateCallbackCompat(final long requestId,
             final WebViewCompat.VisualStateCallback callback) {
         InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
@@ -50,7 +61,36 @@
         });
     }
 
+    public WebSettings getSettings() {
+        return getValue(new ValueGetter<WebSettings>() {
+            @Override
+            public WebSettings capture() {
+                return mWebView.getSettings();
+            }
+        });
+    }
+
     public WebView getWebViewOnCurrentThread() {
         return mWebView;
     }
+
+    private <T> T getValue(ValueGetter<T> getter) {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(getter);
+        return getter.getValue();
+    }
+
+    private abstract class ValueGetter<T> implements Runnable {
+        private T mValue;
+
+        @Override
+        public void run() {
+            mValue = capture();
+        }
+
+        protected abstract T capture();
+
+        public T getValue() {
+            return mValue;
+        }
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
new file mode 100644
index 0000000..c73cda6
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/WebSettingsCompat.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit;
+
+import android.os.Build;
+import android.webkit.WebSettings;
+
+import androidx.webkit.internal.WebSettingsAdapter;
+import androidx.webkit.internal.WebViewGlueCommunicator;
+
+/**
+ * Compatibility version of {@link android.webkit.WebSettings}
+ */
+public class WebSettingsCompat {
+    private WebSettingsCompat() {}
+
+    // TODO(gsennton): add feature detection
+
+    /**
+     * Sets whether this WebView should raster tiles when it is
+     * offscreen but attached to a window. Turning this on can avoid
+     * rendering artifacts when animating an offscreen WebView on-screen.
+     * Offscreen WebViews in this mode use more memory. The default value is
+     * false.<br>
+     * Please follow these guidelines to limit memory usage:
+     * <ul>
+     * <li> WebView size should be not be larger than the device screen size.
+     * <li> Limit use of this mode to a small number of WebViews. Use it for
+     *   visible WebViews and WebViews about to be animated to visible.
+     * </ul>
+     */
+    public static void setOffscreenPreRaster(WebSettings webSettings, boolean enabled) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            webSettings.setOffscreenPreRaster(enabled);
+        } else {
+            getAdapter(webSettings).setOffscreenPreRaster(enabled);
+        }
+    }
+
+    /**
+     * Gets whether this WebView should raster tiles when it is
+     * offscreen but attached to a window.
+     * @return {@code true} if this WebView will raster tiles when it is
+     * offscreen but attached to a window.
+     */
+    public static boolean getOffscreenPreRaster(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return webSettings.getOffscreenPreRaster();
+        } else {
+            return getAdapter(webSettings).getOffscreenPreRaster();
+        }
+    }
+
+    /**
+     * Sets whether Safe Browsing is enabled. Safe Browsing allows WebView to
+     * protect against malware and phishing attacks by verifying the links.
+     *
+     * <p>
+     * Safe Browsing can be disabled for all WebViews using a manifest tag (read <a
+     * href="{@docRoot}reference/android/webkit/WebView.html">general Safe Browsing info</a>). The
+     * manifest tag has a lower precedence than this API.
+     *
+     * <p>
+     * Safe Browsing is enabled by default for devices which support it.
+     *
+     * @param enabled Whether Safe Browsing is enabled.
+     */
+    public static void setSafeBrowsingEnabled(WebSettings webSettings, boolean enabled) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            webSettings.setSafeBrowsingEnabled(enabled);
+        } else {
+            getAdapter(webSettings).setSafeBrowsingEnabled(enabled);
+        }
+    }
+
+    /**
+     * Gets whether Safe Browsing is enabled.
+     * See {@link #setSafeBrowsingEnabled}.
+     *
+     * @return {@code true} if Safe Browsing is enabled and {@code false} otherwise.
+     */
+    public static boolean getSafeBrowsingEnabled(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            return webSettings.getSafeBrowsingEnabled();
+        } else {
+            return getAdapter(webSettings).getSafeBrowsingEnabled();
+        }
+    }
+
+    /**
+     * Disables the action mode menu items according to {@code menuItems} flag.
+     * @param menuItems an integer field flag for the menu items to be disabled.
+     */
+    public static void setDisabledActionModeMenuItems(WebSettings webSettings, int menuItems) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            webSettings.setDisabledActionModeMenuItems(menuItems);
+        } else {
+            getAdapter(webSettings).setDisabledActionModeMenuItems(menuItems);
+        }
+    }
+
+    /**
+     * Gets the action mode menu items that are disabled, expressed in an integer field flag.
+     * The default value is {@link WebSettings#MENU_ITEM_NONE}
+     *
+     * @return all the disabled menu item flags combined with bitwise OR.
+     */
+    public static int getDisabledActionModeMenuItems(WebSettings webSettings) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+            return webSettings.getDisabledActionModeMenuItems();
+        } else {
+            return getAdapter(webSettings).getDisabledActionModeMenuItems();
+        }
+    }
+
+    private static WebSettingsAdapter getAdapter(WebSettings webSettings) {
+        return WebViewGlueCommunicator.getCompatConverter().convertSettings(webSettings);
+    }
+}
+
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 3141918..ee328aa 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -16,16 +16,21 @@
 
 package androidx.webkit;
 
+import android.content.Context;
+import android.net.Uri;
 import android.os.Build;
 import android.os.Looper;
 import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
 import android.support.v4.os.BuildCompat;
+import android.webkit.ValueCallback;
 import android.webkit.WebView;
 
 import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.util.List;
 
 import androidx.webkit.internal.WebViewGlueCommunicator;
 import androidx.webkit.internal.WebViewProviderAdapter;
@@ -120,6 +125,79 @@
         }
     }
 
+    /**
+     * Starts Safe Browsing initialization.
+     * <p>
+     * URL loads are not guaranteed to be protected by Safe Browsing until after {@code callback} is
+     * invoked with {@code true}. Safe Browsing is not fully supported on all devices. For those
+     * devices {@code callback} will receive {@code false}.
+     * <p>
+     * This should not be called if Safe Browsing has been disabled by manifest tag or {@link
+     * android.webkit.WebSettings#setSafeBrowsingEnabled}. This prepares resources used for Safe
+     * Browsing.
+     * <p>
+     * This should be called with the Application Context (and will always use the Application
+     * context to do its work regardless).
+     *
+     * @param context Application Context.
+     * @param callback will be called on the UI thread with {@code true} if initialization is
+     * successful, {@code false} otherwise.
+     */
+    public static void startSafeBrowsing(@NonNull Context context,
+            @Nullable ValueCallback<Boolean> callback) {
+        if (Build.VERSION.SDK_INT >= 27) {
+            WebView.startSafeBrowsing(context, callback);
+        } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+            getFactory().getStatics().initSafeBrowsing(context, callback);
+        }
+    }
+
+    /**
+     * Sets the list of hosts (domain names/IP addresses) that are exempt from SafeBrowsing checks.
+     * The list is global for all the WebViews.
+     * <p>
+     * Each rule should take one of these:
+     * <table>
+     * <tr><th> Rule </th> <th> Example </th> <th> Matches Subdomain</th> </tr>
+     * <tr><td> HOSTNAME </td> <td> example.com </td> <td> Yes </td> </tr>
+     * <tr><td> .HOSTNAME </td> <td> .example.com </td> <td> No </td> </tr>
+     * <tr><td> IPV4_LITERAL </td> <td> 192.168.1.1 </td> <td> No </td></tr>
+     * <tr><td> IPV6_LITERAL_WITH_BRACKETS </td><td>[10:20:30:40:50:60:70:80]</td><td>No</td></tr>
+     * </table>
+     * <p>
+     * All other rules, including wildcards, are invalid.
+     * <p>
+     * The correct syntax for hosts is defined by <a
+     * href="https://tools.ietf.org/html/rfc3986#section-3.2.2">RFC 3986</a>.
+     *
+     * @param hosts the list of hosts
+     * @param callback will be called with {@code true} if hosts are successfully added to the
+     * whitelist. It will be called with {@code false} if any hosts are malformed. The callback
+     * will be run on the UI thread
+     */
+    public static void setSafeBrowsingWhitelist(@NonNull List<String> hosts,
+            @Nullable ValueCallback<Boolean> callback) {
+        if (Build.VERSION.SDK_INT >= 27) {
+            WebView.setSafeBrowsingWhitelist(hosts, callback);
+        } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+            getFactory().getStatics().setSafeBrowsingWhitelist(hosts, callback);
+        }
+    }
+
+    /**
+     * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+     *
+     * @return the url pointing to a privacy policy document which can be displayed to users.
+     */
+    @NonNull
+    public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+        if (Build.VERSION.SDK_INT >= 27) {
+            return WebView.getSafeBrowsingPrivacyPolicyUrl();
+        } else { // TODO(gsennton): guard with WebViewApk.hasFeature(SafeBrowsing)
+            return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+        }
+    }
+
     private static WebViewProviderAdapter getProvider(WebView webview) {
         return new WebViewProviderAdapter(createProvider(webview));
     }
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
new file mode 100644
index 0000000..091879c
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebSettingsAdapter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+
+/**
+ * Adapter between WebSettingsCompat and
+ * {@link org.chromium.support_lib_boundary.WebSettingsBoundaryInterface} (the
+ * corresponding interface shared with the support library glue in the WebView APK).
+ */
+public class WebSettingsAdapter {
+    private WebSettingsBoundaryInterface mBoundaryInterface;
+
+    public WebSettingsAdapter(WebSettingsBoundaryInterface boundaryInterface) {
+        mBoundaryInterface = boundaryInterface;
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setOffscreenPreRaster}.
+     */
+    public void setOffscreenPreRaster(boolean enabled) {
+        mBoundaryInterface.setOffscreenPreRaster(enabled);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getOffscreenPreRaster}.
+     */
+    public boolean getOffscreenPreRaster() {
+        return mBoundaryInterface.getOffscreenPreRaster();
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setSafeBrowsingEnabled}.
+     */
+    public void setSafeBrowsingEnabled(boolean enabled) {
+        mBoundaryInterface.setSafeBrowsingEnabled(enabled);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getSafeBrowsingEnabled}.
+     */
+    public boolean getSafeBrowsingEnabled() {
+        return mBoundaryInterface.getSafeBrowsingEnabled();
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#setDisabledActionModeMenuItems}.
+     */
+    public void setDisabledActionModeMenuItems(int menuItems) {
+        mBoundaryInterface.setDisabledActionModeMenuItems(menuItems);
+    }
+
+    /**
+     * Adapter method for {@link androidx.webkit.WebSettingsCompat#getDisabledActionModeMenuItems}.
+     */
+    public int getDisabledActionModeMenuItems() {
+        return mBoundaryInterface.getDisabledActionModeMenuItems();
+    }
+
+}
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
index 690c8ba..24bb2d1 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewGlueCommunicator.java
@@ -19,8 +19,8 @@
 import android.support.v4.os.BuildCompat;
 import android.webkit.WebView;
 
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
 import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
-import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
 
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
@@ -42,10 +42,17 @@
         return LAZY_FACTORY_HOLDER.INSTANCE;
     }
 
+    public static WebkitToCompatConverter getCompatConverter() {
+        return LAZY_FACTORY_HOLDER.COMPAT_CONVERTER;
+    }
+
     private static class LAZY_FACTORY_HOLDER {
         static final WebViewProviderFactoryAdapter INSTANCE =
                 new WebViewProviderFactoryAdapter(
                         WebViewGlueCommunicator.createGlueProviderFactory());
+        static final WebkitToCompatConverter COMPAT_CONVERTER =
+                new WebkitToCompatConverter(
+                        INSTANCE.getWebkitToCompatConverter());
     }
 
     private static InvocationHandler fetchGlueProviderFactoryImpl() {
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
index 2093e0b..249d367 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderAdapter.java
@@ -16,8 +16,8 @@
 
 package androidx.webkit.internal;
 
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
 import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
-import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
 
 import androidx.webkit.WebViewCompat;
 
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
index 364b381..80067ed 100644
--- a/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
+++ b/webkit/src/main/java/androidx/webkit/internal/WebViewProviderFactoryAdapter.java
@@ -18,9 +18,11 @@
 
 import android.webkit.WebView;
 
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.StaticsBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderBoundaryInterface;
 import org.chromium.support_lib_boundary.WebViewProviderFactoryBoundaryInterface;
-import org.chromium.support_lib_boundary.util.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
 
 /**
  * Adapter for WebViewProviderFactoryBoundaryInterface providing static WebView functionality
@@ -42,4 +44,23 @@
         return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
                 WebViewProviderBoundaryInterface.class, mImpl.createWebView(webview));
     }
+
+    /**
+     * Adapter method for creating a new support library version of
+     * {@link androidx.webkit.internal.WebkitToCompatConverter}, which converts android.webkit
+     * classes into their corresponding support library classes.
+     */
+    public WebkitToCompatConverterBoundaryInterface getWebkitToCompatConverter() {
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebkitToCompatConverterBoundaryInterface.class, mImpl.getWebkitToCompatConverter());
+    }
+
+    /**
+     * Adapter method for fetching the support library class representing
+     * {@link android.webkit.WebViewFactoryProvider#Statics}.
+     */
+    public StaticsBoundaryInterface getStatics() {
+        return BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                StaticsBoundaryInterface.class, mImpl.getStatics());
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
new file mode 100644
index 0000000..cb40530
--- /dev/null
+++ b/webkit/src/main/java/androidx/webkit/internal/WebkitToCompatConverter.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.webkit.internal;
+
+import android.webkit.WebSettings;
+
+import org.chromium.support_lib_boundary.BoundaryInterfaceReflectionUtil;
+import org.chromium.support_lib_boundary.WebSettingsBoundaryInterface;
+import org.chromium.support_lib_boundary.WebkitToCompatConverterBoundaryInterface;
+
+/**
+ * A class providing functionality for converting android.webkit classes into support library
+ * classes.
+ */
+public class WebkitToCompatConverter {
+    private final WebkitToCompatConverterBoundaryInterface mImpl;
+
+    public WebkitToCompatConverter(WebkitToCompatConverterBoundaryInterface impl) {
+        mImpl = impl;
+    }
+
+    /**
+     * Return a WebSettingsAdapter linked to webSettings such that calls on either of those
+     * objects affect the other object. That WebSettingsAdapter can be used to implement
+     * {@link androidx.webkit.WebSettingsCompat}.
+     */
+    public WebSettingsAdapter convertSettings(WebSettings webSettings) {
+        return new WebSettingsAdapter(BoundaryInterfaceReflectionUtil.castToSuppLibClass(
+                WebSettingsBoundaryInterface.class, mImpl.convertSettings(webSettings)));
+    }
+}