Merge "[WebView Support Library] Add ServiceWorker non-framework support." into pi-dev
diff --git a/annotations/api/current.txt b/annotations/api/current.txt
new file mode 100644
index 0000000..7c7450d
--- /dev/null
+++ b/annotations/api/current.txt
@@ -0,0 +1,180 @@
+package androidx.annotation {
+
+  public abstract class AnimRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class AnimatorRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class AnyRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class AnyThread implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ArrayRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class AttrRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class BinderThread implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class BoolRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class CallSuper implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class CheckResult implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ColorInt implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ColorLong implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ColorRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class DimenRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Dimension implements java.lang.annotation.Annotation {
+    field public static final int DP = 0; // 0x0
+    field public static final int PX = 1; // 0x1
+    field public static final int SP = 2; // 0x2
+  }
+
+  public abstract class DrawableRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class FloatRange implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class FontRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class FractionRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class GuardedBy implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class HalfFloat implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class IdRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class IntDef implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class IntRange implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class IntegerRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class InterpolatorRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Keep implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class LayoutRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class LongDef implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class MainThread implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class MenuRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class NavigationRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class NonNull implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Nullable implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class PluralsRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Px implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RawRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RequiresApi implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RequiresFeature implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RequiresPermission implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class RequiresPermission.Read implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class RequiresPermission.Write implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RestrictTo implements java.lang.annotation.Annotation {
+  }
+
+  public static final class RestrictTo.Scope extends java.lang.Enum {
+    method public static androidx.annotation.RestrictTo.Scope valueOf(java.lang.String);
+    method public static final androidx.annotation.RestrictTo.Scope[] values();
+    enum_constant public static final deprecated androidx.annotation.RestrictTo.Scope GROUP_ID;
+    enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY;
+    enum_constant public static final androidx.annotation.RestrictTo.Scope LIBRARY_GROUP;
+    enum_constant public static final androidx.annotation.RestrictTo.Scope SUBCLASSES;
+    enum_constant public static final androidx.annotation.RestrictTo.Scope TESTS;
+  }
+
+  public abstract class Size implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class StringDef implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class StringRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class StyleRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class StyleableRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TransitionRes implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class UiThread implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class VisibleForTesting implements java.lang.annotation.Annotation {
+    field public static final int NONE = 5; // 0x5
+    field public static final int PACKAGE_PRIVATE = 3; // 0x3
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+  }
+
+  public abstract class WorkerThread implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class XmlRes implements java.lang.annotation.Annotation {
+  }
+
+}
+
diff --git a/app-toolkit/core-testing/api/current.txt b/app-toolkit/core-testing/api/current.txt
index 69f5d7a..37e16fb 100644
--- a/app-toolkit/core-testing/api/current.txt
+++ b/app-toolkit/core-testing/api/current.txt
@@ -1,4 +1,4 @@
-package androidx.executor.testing {
+package androidx.arch.core.executor.testing {
 
   public class CountingTaskExecutorRule extends org.junit.rules.TestWatcher {
     ctor public CountingTaskExecutorRule();
diff --git a/app-toolkit/core-testing/src/androidTest/java/androidx/executor/testing/CountingTaskExecutorRuleTest.java b/app-toolkit/core-testing/src/androidTest/java/androidx/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
similarity index 97%
rename from app-toolkit/core-testing/src/androidTest/java/androidx/executor/testing/CountingTaskExecutorRuleTest.java
rename to app-toolkit/core-testing/src/androidTest/java/androidx/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
index 2e3cfb5..200e64f 100644
--- a/app-toolkit/core-testing/src/androidTest/java/androidx/executor/testing/CountingTaskExecutorRuleTest.java
+++ b/app-toolkit/core-testing/src/androidTest/java/androidx/arch/core/executor/testing/CountingTaskExecutorRuleTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor.testing;
+package androidx.arch.core.executor.testing;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -22,7 +22,7 @@
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/app-toolkit/core-testing/src/main/AndroidManifest.xml b/app-toolkit/core-testing/src/main/AndroidManifest.xml
index d169e00..f5cee7e 100644
--- a/app-toolkit/core-testing/src/main/AndroidManifest.xml
+++ b/app-toolkit/core-testing/src/main/AndroidManifest.xml
@@ -15,5 +15,5 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.arch.core.testing">
+          package="androidx.arch.core.testing">
 </manifest>
diff --git a/app-toolkit/core-testing/src/main/java/androidx/executor/JunitTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java
similarity index 98%
rename from app-toolkit/core-testing/src/main/java/androidx/executor/JunitTaskExecutorRule.java
rename to app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java
index 4fb7584..b02339d 100644
--- a/app-toolkit/core-testing/src/main/java/androidx/executor/JunitTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/JunitTaskExecutorRule.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor;
+package androidx.arch.core.executor;
 
 import androidx.annotation.RestrictTo;
 
diff --git a/app-toolkit/core-testing/src/main/java/androidx/executor/TaskExecutorWithFakeMainThread.java b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/TaskExecutorWithFakeMainThread.java
similarity index 98%
rename from app-toolkit/core-testing/src/main/java/androidx/executor/TaskExecutorWithFakeMainThread.java
rename to app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/TaskExecutorWithFakeMainThread.java
index 8afd7fb..a9c1ff6 100644
--- a/app-toolkit/core-testing/src/main/java/androidx/executor/TaskExecutorWithFakeMainThread.java
+++ b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/TaskExecutorWithFakeMainThread.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor;
+package androidx.arch.core.executor;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
diff --git a/app-toolkit/core-testing/src/main/java/androidx/executor/testing/CountingTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/CountingTaskExecutorRule.java
similarity index 96%
rename from app-toolkit/core-testing/src/main/java/androidx/executor/testing/CountingTaskExecutorRule.java
rename to app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/CountingTaskExecutorRule.java
index 20e4669..d3c9878 100644
--- a/app-toolkit/core-testing/src/main/java/androidx/executor/testing/CountingTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/CountingTaskExecutorRule.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package androidx.executor.testing;
+package androidx.arch.core.executor.testing;
 
 import android.os.SystemClock;
 
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.DefaultTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.DefaultTaskExecutor;
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
diff --git a/app-toolkit/core-testing/src/main/java/androidx/executor/testing/InstantTaskExecutorRule.java b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/InstantTaskExecutorRule.java
similarity index 92%
rename from app-toolkit/core-testing/src/main/java/androidx/executor/testing/InstantTaskExecutorRule.java
rename to app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/InstantTaskExecutorRule.java
index 1d8e83f..8c5d0b5 100644
--- a/app-toolkit/core-testing/src/main/java/androidx/executor/testing/InstantTaskExecutorRule.java
+++ b/app-toolkit/core-testing/src/main/java/androidx/arch/core/executor/testing/InstantTaskExecutorRule.java
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package androidx.executor.testing;
+package androidx.arch.core.executor.testing;
 
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.TaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.TaskExecutor;
 
 import org.junit.rules.TestWatcher;
 import org.junit.runner.Description;
diff --git a/app-toolkit/core-testing/src/test/java/androidx/executor/testing/InstantTaskExecutorRuleTest.java b/app-toolkit/core-testing/src/test/java/androidx/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
similarity index 95%
rename from app-toolkit/core-testing/src/test/java/androidx/executor/testing/InstantTaskExecutorRuleTest.java
rename to app-toolkit/core-testing/src/test/java/androidx/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
index a901a69..ecbcfd5 100644
--- a/app-toolkit/core-testing/src/test/java/androidx/executor/testing/InstantTaskExecutorRuleTest.java
+++ b/app-toolkit/core-testing/src/test/java/androidx/arch/core/executor/testing/InstantTaskExecutorRuleTest.java
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package androidx.executor.testing;
+package androidx.arch.core.executor.testing;
 
 import static org.junit.Assert.assertTrue;
 
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/app-toolkit/runtime/src/main/AndroidManifest.xml b/app-toolkit/runtime/src/main/AndroidManifest.xml
index 3f40068..e56fa1a 100644
--- a/app-toolkit/runtime/src/main/AndroidManifest.xml
+++ b/app-toolkit/runtime/src/main/AndroidManifest.xml
@@ -15,5 +15,5 @@
   -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.arch.core">
+          package="androidx.arch.core">
 </manifest>
diff --git a/app-toolkit/runtime/src/main/java/androidx/executor/ArchTaskExecutor.java b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/ArchTaskExecutor.java
similarity index 98%
rename from app-toolkit/runtime/src/main/java/androidx/executor/ArchTaskExecutor.java
rename to app-toolkit/runtime/src/main/java/androidx/arch/core/executor/ArchTaskExecutor.java
index 25182ac..a38dff8 100644
--- a/app-toolkit/runtime/src/main/java/androidx/executor/ArchTaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/ArchTaskExecutor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor;
+package androidx.arch.core.executor;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
diff --git a/app-toolkit/runtime/src/main/java/androidx/executor/DefaultTaskExecutor.java b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
similarity index 97%
rename from app-toolkit/runtime/src/main/java/androidx/executor/DefaultTaskExecutor.java
rename to app-toolkit/runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
index 4c77cc8..a942324 100644
--- a/app-toolkit/runtime/src/main/java/androidx/executor/DefaultTaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/DefaultTaskExecutor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor;
+package androidx.arch.core.executor;
 
 import android.os.Handler;
 import android.os.Looper;
diff --git a/app-toolkit/runtime/src/main/java/androidx/executor/TaskExecutor.java b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/TaskExecutor.java
similarity index 97%
rename from app-toolkit/runtime/src/main/java/androidx/executor/TaskExecutor.java
rename to app-toolkit/runtime/src/main/java/androidx/arch/core/executor/TaskExecutor.java
index cf9442c..4b3c5fa 100644
--- a/app-toolkit/runtime/src/main/java/androidx/executor/TaskExecutor.java
+++ b/app-toolkit/runtime/src/main/java/androidx/arch/core/executor/TaskExecutor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.executor;
+package androidx.arch.core.executor;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
diff --git a/app-toolkit/settings.gradle b/app-toolkit/settings.gradle
index b463df7..3cd11cc 100644
--- a/app-toolkit/settings.gradle
+++ b/app-toolkit/settings.gradle
@@ -59,6 +59,7 @@
 includeProject(":lifecycle:lifecycle-livedata-core", new File(supportRoot, "lifecycle/livedata-core"))
 includeProject(":lifecycle:lifecycle-livedata", new File(supportRoot, "lifecycle/livedata"))
 includeProject(":lifecycle:lifecycle-reactivestreams", new File(supportRoot, "lifecycle/reactivestreams"))
+includeProject(":lifecycle:lifecycle-reactivestreams-ktx", new File(supportRoot, "lifecycle/reactivestreams/ktx"))
 includeProject(":lifecycle:lifecycle-runtime", new File(supportRoot, "lifecycle/runtime"))
 includeProject(":lifecycle:lifecycle-viewmodel", new File(supportRoot, "lifecycle/viewmodel"))
 includeProject(":paging:integration-tests:testapp", new File(supportRoot, "paging/integration-tests/testapp"))
@@ -75,6 +76,7 @@
 includeProject(":room:room-testing", new File(supportRoot, "room/testing"))
 includeProject(":sqlite:sqlite", new File(supportRoot, "persistence/db"))
 includeProject(":sqlite:sqlite-framework", new File(supportRoot, "persistence/db-framework"))
+includeProject(":sqlite:sqlite-ktx", new File(supportRoot, "persistence/db/ktx"))
 
 includeProject(":jetifier-core", new File(supportRoot, "jetifier/jetifier/core"))
 includeProject(":jetifier-gradle-plugin", new File(supportRoot, "jetifier/jetifier/gradle-plugin"))
diff --git a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
index 213a8a8..36321af 100644
--- a/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/DiffAndDocs.kt
@@ -39,11 +39,60 @@
 data class DacOptions(val libraryroot: String, val dataname: String)
 
 object DiffAndDocs {
+    private lateinit var allChecksTask: Task
+    private lateinit var generateDocsTask: GenerateDocsTask
+
     @JvmStatic
-    fun configureDiffAndDocs(
-            root: Project,
-            supportRootFolder: File,
-            dacOptions: DacOptions) = configure(root, supportRootFolder, dacOptions)
+    fun configureDiffAndDocs(root: Project, supportRootFolder: File, dacOptions: DacOptions): Task {
+        allChecksTask = root.tasks.create("anchorCheckApis")
+        val doclavaConfiguration = root.configurations.getByName("doclava")
+        val generateSdkApiTask = createGenerateSdkApiTask(root, doclavaConfiguration)
+        generateDocsTask = createGenerateDocsTask(root, generateSdkApiTask,
+                doclavaConfiguration, supportRootFolder, dacOptions)
+        createDistDocsTask(root, generateDocsTask)
+        return allChecksTask
+    }
+
+    fun registerJavaProject(project: Project, extension: SupportLibraryExtension) {
+        if (!hasApiTasks(project, extension)) {
+            return
+        }
+        val compileJava = project.properties["compileJava"] as JavaCompile
+        registerJavaProjectForDocsTask(generateDocsTask, compileJava)
+        if (!hasApiFolder(project)) {
+            project.logger.info("Project ${project.name} doesn't have an api folder, " +
+                    "ignoring API tasks.")
+            return
+        }
+        val tasks = initializeApiChecksForProject(project, generateDocsTask)
+        registerJavaProjectForDocsTask(tasks.generateApi, compileJava)
+        registerJavaProjectForDocsTask(tasks.generateDiffs, compileJava)
+        allChecksTask.dependsOn(tasks.checkApiTask)
+    }
+
+    fun registerAndroidProject(project: Project, library: LibraryExtension,
+            extension: SupportLibraryExtension) {
+        if (!hasApiTasks(project, extension)) {
+            return
+        }
+        library.libraryVariants.all { variant ->
+            if (variant.name == "release") {
+                registerAndroidProjectForDocsTask(generateDocsTask, variant)
+                if (!hasJavaSources(variant)) {
+                    return@all
+                }
+                if (!hasApiFolder(project)) {
+                    project.logger.info("Project ${project.name} doesn't have " +
+                            "an api folder, ignoring API tasks.")
+                    return@all
+                }
+                val tasks = initializeApiChecksForProject(project, generateDocsTask)
+                registerAndroidProjectForDocsTask(tasks.generateApi, variant)
+                registerAndroidProjectForDocsTask(tasks.generateDiffs, variant)
+                allChecksTask.dependsOn(tasks.checkApiTask)
+            }
+        }
+    }
 }
 
 private data class CheckApiConfig(
@@ -492,70 +541,18 @@
     return Tasks(generateApi, generateDiffTask, checkApi)
 }
 
-private fun configure(root: Project, supportRootFolder: File, dacOptions: DacOptions): Task {
-    val allChecks = root.tasks.create("AnchorCheckApis")
-    val doclavaConfiguration = root.configurations.getByName("doclava")
-    val generateSdkApiTask = createGenerateSdkApiTask(root, doclavaConfiguration)
-
-    val generateDocsTask = createGenerateDocsTask(root, generateSdkApiTask,
-            doclavaConfiguration, supportRootFolder, dacOptions)
-    createDistDocsTask(root, generateDocsTask)
-
-    root.subprojects { subProject ->
-        subProject.afterEvaluate { project ->
-            val extension = if (project.hasProperty("supportLibrary")) {
-                project.properties["supportLibrary"] as SupportLibraryExtension
-            } else {
-                null
-            }
-            if (extension == null || !extension.publish) {
-                project.logger.info("Project ${project.name} is not published, ignoring API tasks.")
-                return@afterEvaluate
-            }
-
-            if (!extension.generateDocs) {
-                project.logger.info("Project ${project.name} specified generateDocs = false, " +
-                        "ignoring API tasks.")
-                return@afterEvaluate
-            }
-
-            val library = project.extensions.findByType(LibraryExtension::class.java)
-            if (library != null) {
-                library.libraryVariants.all { variant ->
-                    if (variant.name == "release") {
-                        registerAndroidProjectForDocsTask(generateDocsTask, variant)
-                        if (!hasJavaSources(variant)) {
-                            return@all
-                        }
-                        if (!hasApiFolder(project)) {
-                            project.logger.info("Project ${project.name} doesn't have " +
-                                    "an api folder, ignoring API tasks.")
-                            return@all
-                        }
-                        val tasks = initializeApiChecksForProject(project, generateDocsTask)
-                        registerAndroidProjectForDocsTask(tasks.generateApi, variant)
-                        registerAndroidProjectForDocsTask(tasks.generateDiffs, variant)
-                        allChecks.dependsOn(tasks.checkApiTask)
-                    }
-                }
-            } else if (project.hasProperty("compileJava")) {
-                val compileJava = project.properties["compileJava"] as JavaCompile
-                registerJavaProjectForDocsTask(generateDocsTask, compileJava)
-                if (!hasApiFolder(project)) {
-                    project.logger.info("Project ${project.name} doesn't have an api folder, " +
-                            "ignoring API tasks.")
-                    return@afterEvaluate
-                }
-                project.afterEvaluate { proj ->
-                    val tasks = initializeApiChecksForProject(proj, generateDocsTask)
-                    registerJavaProjectForDocsTask(tasks.generateApi, compileJava)
-                    registerJavaProjectForDocsTask(tasks.generateDiffs, compileJava)
-                    allChecks.dependsOn(tasks.checkApiTask)
-                }
-            }
-        }
+fun hasApiTasks(project: Project, extension: SupportLibraryExtension): Boolean {
+    if (!extension.publish) {
+        project.logger.info("Project ${project.name} is not published, ignoring API tasks.")
+        return false
     }
-    return allChecks
+
+    if (!extension.generateDocs) {
+        project.logger.info("Project ${project.name} specified generateDocs = false, " +
+                "ignoring API tasks.")
+        return false
+    }
+    return true
 }
 
 private fun sdkApiFile(project: Project) = File(project.docsDir(), "release/sdk_current.txt")
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
index 0d3fa3a..d65dd5e 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportAndroidLibraryPlugin.kt
@@ -64,6 +64,7 @@
             library.compileOptions.setTargetCompatibility(javaVersion)
 
             VersionFileWriterTask.setUpAndroidLibrary(project, library)
+            DiffAndDocs.registerAndroidProject(project, library, supportLibraryExtension)
         }
 
         project.apply(mapOf("plugin" to "com.android.library"))
diff --git a/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
index 24546f1..e8bd816 100644
--- a/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/SupportJavaLibraryPlugin.kt
@@ -46,6 +46,7 @@
                 convention.sourceCompatibility = JavaVersion.VERSION_1_7
                 convention.targetCompatibility = JavaVersion.VERSION_1_7
             }
+            DiffAndDocs.registerJavaProject(project, supportLibraryExtension)
         }
 
         project.apply(mapOf("plugin" to ErrorProneBasePlugin::class.java))
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 6fea40e..9cd1a93 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -36,7 +36,7 @@
 const val LINT = "com.android.tools.lint:lint:26.0.0"
 const val MOCKITO_CORE = "org.mockito:mockito-core:2.7.6"
 const val MULTIDEX = "androidx.multidex:multidex:2.0.0"
-const val NULLAWAY = "com.uber.nullaway:nullaway:0.2.0"
+const val NULLAWAY = "com.uber.nullaway:nullaway:0.3.7"
 const val REACTIVE_STREAMS = "org.reactivestreams:reactive-streams:1.0.0"
 const val RX_JAVA = "io.reactivex.rxjava2:rxjava:2.0.6"
 const val TEST_RUNNER = "com.android.support.test:runner:1.0.1"
diff --git a/collection/api/current.txt b/collection/api/current.txt
new file mode 100644
index 0000000..5f644fe
--- /dev/null
+++ b/collection/api/current.txt
@@ -0,0 +1,163 @@
+package androidx.collection {
+
+  public class ArrayMap<K, V> extends androidx.collection.SimpleArrayMap implements java.util.Map {
+    ctor public ArrayMap();
+    ctor public ArrayMap(int);
+    ctor public ArrayMap(androidx.collection.SimpleArrayMap);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public java.util.Set<K> keySet();
+    method public void putAll(java.util.Map<? extends K, ? extends V>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public java.util.Collection<V> values();
+  }
+
+  public final class ArraySet<E> implements java.util.Collection java.util.Set {
+    ctor public ArraySet();
+    ctor public ArraySet(int);
+    ctor public ArraySet(androidx.collection.ArraySet<E>);
+    ctor public ArraySet(java.util.Collection<E>);
+    method public boolean add(E);
+    method public void addAll(androidx.collection.ArraySet<? extends E>);
+    method public boolean addAll(java.util.Collection<? extends E>);
+    method public void clear();
+    method public boolean contains(java.lang.Object);
+    method public boolean containsAll(java.util.Collection<?>);
+    method public void ensureCapacity(int);
+    method public int indexOf(java.lang.Object);
+    method public boolean isEmpty();
+    method public java.util.Iterator<E> iterator();
+    method public boolean remove(java.lang.Object);
+    method public boolean removeAll(androidx.collection.ArraySet<? extends E>);
+    method public boolean removeAll(java.util.Collection<?>);
+    method public E removeAt(int);
+    method public boolean retainAll(java.util.Collection<?>);
+    method public int size();
+    method public java.lang.Object[] toArray();
+    method public <T> T[] toArray(T[]);
+    method public E valueAt(int);
+  }
+
+  public final class CircularArray<E> {
+    ctor public CircularArray();
+    ctor public CircularArray(int);
+    method public void addFirst(E);
+    method public void addLast(E);
+    method public void clear();
+    method public E get(int);
+    method public E getFirst();
+    method public E getLast();
+    method public boolean isEmpty();
+    method public E popFirst();
+    method public E popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public final class CircularIntArray {
+    ctor public CircularIntArray();
+    ctor public CircularIntArray(int);
+    method public void addFirst(int);
+    method public void addLast(int);
+    method public void clear();
+    method public int get(int);
+    method public int getFirst();
+    method public int getLast();
+    method public boolean isEmpty();
+    method public int popFirst();
+    method public int popLast();
+    method public void removeFromEnd(int);
+    method public void removeFromStart(int);
+    method public int size();
+  }
+
+  public class LongSparseArray<E> implements java.lang.Cloneable {
+    ctor public LongSparseArray();
+    ctor public LongSparseArray(int);
+    method public void append(long, E);
+    method public void clear();
+    method public androidx.collection.LongSparseArray<E> clone();
+    method public void delete(long);
+    method public E get(long);
+    method public E get(long, E);
+    method public int indexOfKey(long);
+    method public int indexOfValue(E);
+    method public boolean isEmpty();
+    method public long keyAt(int);
+    method public void put(long, E);
+    method public void remove(long);
+    method public void removeAt(int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+  public class LruCache<K, V> {
+    ctor public LruCache(int);
+    method protected V create(K);
+    method public final synchronized int createCount();
+    method protected void entryRemoved(boolean, K, V, V);
+    method public final void evictAll();
+    method public final synchronized int evictionCount();
+    method public final V get(K);
+    method public final synchronized int hitCount();
+    method public final synchronized int maxSize();
+    method public final synchronized int missCount();
+    method public final V put(K, V);
+    method public final synchronized int putCount();
+    method public final V remove(K);
+    method public void resize(int);
+    method public final synchronized int size();
+    method protected int sizeOf(K, V);
+    method public final synchronized java.util.Map<K, V> snapshot();
+    method public final synchronized java.lang.String toString();
+    method public void trimToSize(int);
+  }
+
+  public class SimpleArrayMap<K, V> {
+    ctor public SimpleArrayMap();
+    ctor public SimpleArrayMap(int);
+    ctor public SimpleArrayMap(androidx.collection.SimpleArrayMap<K, V>);
+    method public void clear();
+    method public boolean containsKey(java.lang.Object);
+    method public boolean containsValue(java.lang.Object);
+    method public void ensureCapacity(int);
+    method public V get(java.lang.Object);
+    method public int indexOfKey(java.lang.Object);
+    method public boolean isEmpty();
+    method public K keyAt(int);
+    method public V put(K, V);
+    method public void putAll(androidx.collection.SimpleArrayMap<? extends K, ? extends V>);
+    method public V remove(java.lang.Object);
+    method public V removeAt(int);
+    method public V setValueAt(int, V);
+    method public int size();
+    method public V valueAt(int);
+  }
+
+  public class SparseArrayCompat<E> implements java.lang.Cloneable {
+    ctor public SparseArrayCompat();
+    ctor public SparseArrayCompat(int);
+    method public void append(int, E);
+    method public void clear();
+    method public androidx.collection.SparseArrayCompat<E> clone();
+    method public void delete(int);
+    method public E get(int);
+    method public E get(int, E);
+    method public int indexOfKey(int);
+    method public int indexOfValue(E);
+    method public boolean isEmpty();
+    method public int keyAt(int);
+    method public void put(int, E);
+    method public void remove(int);
+    method public void removeAt(int);
+    method public void removeAtRange(int, int);
+    method public void setValueAt(int, E);
+    method public int size();
+    method public E valueAt(int);
+  }
+
+}
+
diff --git a/collection-ktx/OWNERS b/collection/ktx/OWNERS
similarity index 100%
rename from collection-ktx/OWNERS
rename to collection/ktx/OWNERS
diff --git a/collection-ktx/build.gradle b/collection/ktx/build.gradle
similarity index 100%
rename from collection-ktx/build.gradle
rename to collection/ktx/build.gradle
diff --git a/collection-ktx/src/main/java/androidx/collection/ArrayMap.kt b/collection/ktx/src/main/java/androidx/collection/ArrayMap.kt
similarity index 100%
rename from collection-ktx/src/main/java/androidx/collection/ArrayMap.kt
rename to collection/ktx/src/main/java/androidx/collection/ArrayMap.kt
diff --git a/collection-ktx/src/main/java/androidx/collection/ArraySet.kt b/collection/ktx/src/main/java/androidx/collection/ArraySet.kt
similarity index 100%
rename from collection-ktx/src/main/java/androidx/collection/ArraySet.kt
rename to collection/ktx/src/main/java/androidx/collection/ArraySet.kt
diff --git a/collection-ktx/src/main/java/androidx/collection/LongSparseArray.kt b/collection/ktx/src/main/java/androidx/collection/LongSparseArray.kt
similarity index 100%
rename from collection-ktx/src/main/java/androidx/collection/LongSparseArray.kt
rename to collection/ktx/src/main/java/androidx/collection/LongSparseArray.kt
diff --git a/collection-ktx/src/main/java/androidx/collection/LruCache.kt b/collection/ktx/src/main/java/androidx/collection/LruCache.kt
similarity index 100%
rename from collection-ktx/src/main/java/androidx/collection/LruCache.kt
rename to collection/ktx/src/main/java/androidx/collection/LruCache.kt
diff --git a/collection-ktx/src/main/java/androidx/collection/SparseArray.kt b/collection/ktx/src/main/java/androidx/collection/SparseArray.kt
similarity index 100%
rename from collection-ktx/src/main/java/androidx/collection/SparseArray.kt
rename to collection/ktx/src/main/java/androidx/collection/SparseArray.kt
diff --git a/collection-ktx/src/test/java/androidx/collection/ArrayMapTest.kt b/collection/ktx/src/test/java/androidx/collection/ArrayMapTest.kt
similarity index 100%
rename from collection-ktx/src/test/java/androidx/collection/ArrayMapTest.kt
rename to collection/ktx/src/test/java/androidx/collection/ArrayMapTest.kt
diff --git a/collection-ktx/src/test/java/androidx/collection/ArraySetTest.kt b/collection/ktx/src/test/java/androidx/collection/ArraySetTest.kt
similarity index 100%
rename from collection-ktx/src/test/java/androidx/collection/ArraySetTest.kt
rename to collection/ktx/src/test/java/androidx/collection/ArraySetTest.kt
diff --git a/collection-ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt b/collection/ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt
similarity index 100%
rename from collection-ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt
rename to collection/ktx/src/test/java/androidx/collection/LongSparseArrayTest.kt
diff --git a/collection-ktx/src/test/java/androidx/collection/LruCacheTest.kt b/collection/ktx/src/test/java/androidx/collection/LruCacheTest.kt
similarity index 100%
rename from collection-ktx/src/test/java/androidx/collection/LruCacheTest.kt
rename to collection/ktx/src/test/java/androidx/collection/LruCacheTest.kt
diff --git a/collection-ktx/src/test/java/androidx/collection/SparseArrayTest.kt b/collection/ktx/src/test/java/androidx/collection/SparseArrayTest.kt
similarity index 100%
rename from collection-ktx/src/test/java/androidx/collection/SparseArrayTest.kt
rename to collection/ktx/src/test/java/androidx/collection/SparseArrayTest.kt
diff --git a/compat/api/current.txt b/compat/api/current.txt
index 143e239..52ae6ea 100644
--- a/compat/api/current.txt
+++ b/compat/api/current.txt
@@ -870,6 +870,7 @@
     method public static void colorToLAB(int, double[]);
     method public static void colorToXYZ(int, double[]);
     method public static int compositeColors(int, int);
+    method public static android.graphics.Color compositeColors(android.graphics.Color, android.graphics.Color);
     method public static double distanceEuclidean(double[], double[]);
     method public static int setAlphaComponent(int, int);
   }
@@ -878,6 +879,19 @@
     method public static boolean hasGlyph(android.graphics.Paint, java.lang.String);
   }
 
+  public final class PathSegment {
+    ctor public PathSegment(android.graphics.PointF, float, android.graphics.PointF, float);
+    method public android.graphics.PointF getEnd();
+    method public float getEndFraction();
+    method public android.graphics.PointF getStart();
+    method public float getStartFraction();
+  }
+
+  public final class PathUtils {
+    method public static java.util.Collection<androidx.core.graphics.PathSegment> flatten(android.graphics.Path);
+    method public static java.util.Collection<androidx.core.graphics.PathSegment> flatten(android.graphics.Path, float);
+  }
+
 }
 
 package androidx.core.graphics.drawable {
@@ -904,13 +918,29 @@
   }
 
   public class IconCompat {
+    method public static androidx.core.graphics.drawable.IconCompat createFromBundle(android.os.Bundle);
+    method public static androidx.core.graphics.drawable.IconCompat createFromIcon(android.graphics.drawable.Icon);
     method public static androidx.core.graphics.drawable.IconCompat createWithAdaptiveBitmap(android.graphics.Bitmap);
     method public static androidx.core.graphics.drawable.IconCompat createWithBitmap(android.graphics.Bitmap);
     method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(java.lang.String);
     method public static androidx.core.graphics.drawable.IconCompat createWithContentUri(android.net.Uri);
     method public static androidx.core.graphics.drawable.IconCompat createWithData(byte[], int, int);
     method public static androidx.core.graphics.drawable.IconCompat createWithResource(android.content.Context, int);
+    method public int getResId();
+    method public static int getResId(android.graphics.drawable.Icon);
+    method public java.lang.String getResPackage();
+    method public static java.lang.String getResPackage(android.graphics.drawable.Icon);
+    method public int getType();
+    method public static int getType(android.graphics.drawable.Icon);
+    method public android.net.Uri getUri();
+    method public android.net.Uri getUri(android.graphics.drawable.Icon);
+    method public android.graphics.drawable.Drawable loadDrawable(android.content.Context);
+    method public androidx.core.graphics.drawable.IconCompat setTint(int);
+    method public androidx.core.graphics.drawable.IconCompat setTintList(android.content.res.ColorStateList);
+    method public androidx.core.graphics.drawable.IconCompat setTintMode(android.graphics.PorterDuff.Mode);
+    method public android.os.Bundle toBundle();
     method public android.graphics.drawable.Icon toIcon();
+    field public static final int TYPE_UNKOWN = -1; // 0xffffffff
   }
 
   public abstract class RoundedBitmapDrawable extends android.graphics.drawable.Drawable {
diff --git a/compat/res/values/dimens.xml b/compat/res/values/dimens.xml
index 1dcff5e..41abbe6 100644
--- a/compat/res/values/dimens.xml
+++ b/compat/res/values/dimens.xml
@@ -70,4 +70,10 @@
 
     <!-- the paddingtop on the right side of the notification (for time etc.) -->
     <dimen name="notification_right_side_padding_top">2dp</dimen>
+
+    <!-- the maximum width of the large icon, above which it will be downscaled -->
+    <dimen name="notification_icon_max_width">320dp</dimen>
+
+    <!-- the maximum height of the large icon, above which it will be downscaled -->
+    <dimen name="notification_icon_max_height">320dp</dimen>
 </resources>
diff --git a/compat/src/androidTest/java/androidx/core/graphics/ColorUtilsTest.java b/compat/src/androidTest/java/androidx/core/graphics/ColorUtilsTest.java
index f637f39..2940599 100644
--- a/compat/src/androidTest/java/androidx/core/graphics/ColorUtilsTest.java
+++ b/compat/src/androidTest/java/androidx/core/graphics/ColorUtilsTest.java
@@ -16,10 +16,16 @@
 
 package androidx.core.graphics;
 
+import static android.graphics.ColorSpace.Named.CIE_LAB;
+import static android.graphics.ColorSpace.Named.SRGB;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -82,6 +88,57 @@
                 .setWhiteMinAlpha30(0.39f).setWhiteMinAlpha45(0.54f));
     }
 
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void addColorsDifferentModels() {
+        Color lab = Color.valueOf(54.0f, 80.0f, 70.0f, 1.0f, ColorSpace.get(CIE_LAB));
+        Color rgb = Color.valueOf(0.0f, 0.5f, 0.0f, 0.5f, ColorSpace.get(SRGB));
+        try {
+            ColorUtils.compositeColors(rgb, lab);
+            fail();
+        } catch (IllegalArgumentException e) {
+            assertEquals("Color models must match (RGB vs. LAB)", e.getMessage());
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void addColorsSameColorSpace() {
+        Color result = ColorUtils.compositeColors(Color.valueOf(0x7f007f00),
+                Color.valueOf(0x7f7f0000));
+        assertEquals(0.16f, result.red(), 1e-2f);
+        assertEquals(0.33f, result.green(), 1e-2f);
+        assertEquals(0.00f, result.blue(), 1e-2f);
+        assertEquals(0.75f, result.alpha(), 1e-2f);
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void addColorsDifferentColorSpace() {
+        ColorSpace p3 = ColorSpace.get(ColorSpace.Named.DISPLAY_P3);
+        Color red = Color.valueOf(0.5f, 0.0f, 0.0f, 0.5f, p3);
+        Color green = Color.valueOf(0x7f007f00);
+
+        Color mixed = ColorUtils.compositeColors(green, red);
+        assertEquals(p3, mixed.getColorSpace());
+        assertEquals(0.31f, mixed.red(), 1e-2f);
+        assertEquals(0.33f, mixed.green(), 1e-2f);
+        assertEquals(0.09f, mixed.blue(), 1e-2f);
+        assertEquals(0.75f, mixed.alpha(), 1e-2f);
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void addColorsZeroAlpha() {
+        // Test potential divide by zero
+        assertEquals(0, ColorUtils.compositeColors(Color.valueOf(0x00007f00),
+                Color.valueOf(0x007f0000)).toArgb());
+
+        // Test low alpha
+        Color result = ColorUtils.compositeColors(Color.valueOf(0.0f, 1.0f, 0.0f, 0.0001f),
+                Color.valueOf(1.0f, 0.0f, 0.0f, 0.0001f));
+        assertEquals(0.50f, result.red(), 1e-2f);
+        assertEquals(0.50f, result.green(), 1e-2f);
+        assertEquals(0.00f, result.blue(), 1e-2f);
+        assertEquals(2e-4f, result.alpha(), 1e-5f);
+    }
+
     @Test
     public void testColorToHSL() {
         for (TestEntry entry : sEntryList) {
diff --git a/compat/src/androidTest/java/androidx/core/graphics/PathUtilsTest.java b/compat/src/androidTest/java/androidx/core/graphics/PathUtilsTest.java
new file mode 100644
index 0000000..682ac25
--- /dev/null
+++ b/compat/src/androidTest/java/androidx/core/graphics/PathUtilsTest.java
@@ -0,0 +1,93 @@
+/*
+ * 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.core.graphics;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.fail;
+
+import android.graphics.Path;
+import android.graphics.PointF;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@SmallTest
+public final class PathUtilsTest {
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void flattenEmptyPath() {
+        for (PathSegment segment : PathUtils.flatten(new Path())) {
+            fail("An empty path should not have segments: " + segment);
+        }
+    }
+
+    @SdkSuppress(minSdkVersion = 26)
+    @Test public void flatten() {
+        Path p = new Path();
+
+        // Single line
+        p.lineTo(10.0f, 10.0f);
+        assertEquals(
+                new PathSegment(new PointF(), 0.0f, new PointF(10.0f, 10.0f), 1.0f),
+                PathUtils.flatten(p).iterator().next());
+
+        // Only moves
+        p.reset();
+        p.moveTo(10.0f, 10.0f);
+        p.moveTo(20.0f, 20.0f);
+        for (PathSegment segment : PathUtils.flatten(p)) {
+            fail("A path with only moves should not have segments: " + segment);
+        }
+
+        // Mix of moves/lines
+        p.reset();
+        p.moveTo(10.0f, 10.0f);
+        p.lineTo(20.0f, 20.0f);
+        p.lineTo(60.0f, 20.0f);
+
+        int count = 0;
+        for (PathSegment segment : PathUtils.flatten(p)) {
+            count++;
+            assertNotEquals(segment.getStartFraction(), segment.getEndFraction());
+        }
+        assertEquals(2, count);
+
+        // Mix of moves/lines, starts with moves, ends with moves
+        p.reset();
+        // Start with several moves
+        p.moveTo(5.0f, 5.0f);
+        p.moveTo(10.0f, 10.0f);
+        p.lineTo(20.0f, 20.0f);
+        p.lineTo(30.0f, 10.0f);
+        // Several moves in the middle
+        p.moveTo(40.0f, 10.0f);
+        p.moveTo(50.0f, 10.0f);
+        p.lineTo(60.0f, 20.0f);
+        // End with several moves
+        p.moveTo(10.0f, 10.0f);
+        p.moveTo(30.0f, 30.0f);
+
+        count = 0;
+        for (PathSegment segment : PathUtils.flatten(p)) {
+            count++;
+            assertNotEquals(segment.getStartFraction(), segment.getEndFraction());
+        }
+        assertEquals(3, count);
+    }
+}
+
diff --git a/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java b/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
index 219737b..75ad1d5 100644
--- a/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
+++ b/compat/src/androidTest/java/androidx/core/graphics/drawable/IconCompatTest.java
@@ -24,13 +24,17 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
@@ -43,12 +47,19 @@
 import org.junit.runner.RunWith;
 
 import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.Arrays;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IconCompatTest {
 
+    private Context mContext = InstrumentationRegistry.getContext();
+
     private static void verifyClippedCircle(Bitmap bitmap, int fillColor, int size) {
         assertEquals(size, bitmap.getHeight());
         assertEquals(bitmap.getWidth(), bitmap.getHeight());
@@ -87,7 +98,7 @@
         Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
         bitmap.eraseColor(Color.RED);
         Intent intent = new Intent();
-        IconCompat.createWithBitmap(bitmap).addToShortcutIntent(intent, null);
+        IconCompat.createWithBitmap(bitmap).addToShortcutIntent(intent, null, mContext);
         assertEquals(bitmap, intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON));
     }
 
@@ -99,7 +110,7 @@
         Intent intent = new Intent();
 
         Drawable badge = ContextCompat.getDrawable(context, R.drawable.test_drawable_blue);
-        IconCompat.createWithBitmap(bitmap).addToShortcutIntent(intent, badge);
+        IconCompat.createWithBitmap(bitmap).addToShortcutIntent(intent, badge, mContext);
         assertNotSame(bitmap, intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON));
 
         verifyBadgeBitmap(intent, Color.RED, ContextCompat.getColor(context, R.color.test_blue));
@@ -112,14 +123,14 @@
 
         // No badge
         IconCompat.createWithResource(context, R.drawable.test_drawable_green)
-                .addToShortcutIntent(intent, null);
+                .addToShortcutIntent(intent, null, mContext);
         assertNotNull(intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE));
         assertNull(intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON));
 
         intent = new Intent();
         Drawable badge = ContextCompat.getDrawable(context, R.drawable.test_drawable_red);
         IconCompat.createWithResource(context, R.drawable.test_drawable_blue)
-                .addToShortcutIntent(intent, badge);
+                .addToShortcutIntent(intent, badge, mContext);
 
         assertNull(intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE));
         verifyBadgeBitmap(intent, ContextCompat.getColor(context, R.color.test_blue),
@@ -142,7 +153,7 @@
         Bitmap bitmap = Bitmap.createBitmap(200, 200, Bitmap.Config.ARGB_8888);
         bitmap.eraseColor(Color.GREEN);
         Intent intent = new Intent();
-        IconCompat.createWithAdaptiveBitmap(bitmap).addToShortcutIntent(intent, null);
+        IconCompat.createWithAdaptiveBitmap(bitmap).addToShortcutIntent(intent, null, mContext);
 
         Bitmap clipped = intent.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
         verifyClippedCircle(clipped, Color.GREEN, clipped.getWidth());
@@ -209,4 +220,108 @@
         // Drawables behave the same
         assertTrue(orgBitmap.sameAs(compatBitmap));
     }
+
+    @Test
+    public void testBitmapIconCompat() {
+        verifyIconCompatValidity(
+                IconCompat.createWithBitmap(Bitmap.createBitmap(16, 16, Bitmap.Config.ARGB_8888)));
+    }
+
+    @Test
+    public void testDataIconCompat() {
+        byte[] data = new byte[4];
+        data[0] = data[1] = data[2] = data[3] = (byte) 255;
+        verifyIconCompatValidity(IconCompat.createWithData(data, 0, 4));
+    }
+
+    @Test
+    public void testFileIconCompat() throws IOException {
+        File file = new File(mContext.getFilesDir(), "testimage.jpg");
+        try {
+            writeSampleImage(file);
+            assertTrue(file.exists());
+
+            verifyIconCompatValidity(IconCompat.createWithContentUri(Uri.fromFile(file)));
+
+            verifyIconCompatValidity(IconCompat.createWithContentUri(file.toURI().toString()));
+        } finally {
+            file.delete();
+        }
+    }
+
+    @Test
+    public void testResourceIconCompat() {
+        verifyIconCompatValidity(IconCompat.createWithResource(mContext, R.drawable.bmp_test));
+    }
+
+    @Test
+    public void testBitmapIconCompat_getType() {
+        IconCompat icon = IconCompat.createWithBitmap(Bitmap.createBitmap(16, 16,
+                Bitmap.Config.ARGB_8888));
+        assertEquals(IconCompat.TYPE_BITMAP, icon.getType());
+    }
+
+    @Test
+    public void testDataIconCompat_getType() {
+        byte[] data = new byte[4];
+        data[0] = data[1] = data[2] = data[3] = (byte) 255;
+        IconCompat icon = IconCompat.createWithData(data, 0, 4);
+        assertEquals(IconCompat.TYPE_DATA, icon.getType());
+    }
+
+    @Test
+    public void testFileIconCompat_getType() throws IOException {
+        File file = new File(mContext.getFilesDir(), "testimage.jpg");
+        try {
+            writeSampleImage(file);
+            assertTrue(file.exists());
+            String filePath = file.toURI().getPath();
+
+            IconCompat icon = IconCompat.createWithContentUri(Uri.fromFile(file));
+            assertEquals(IconCompat.TYPE_URI, icon.getType());
+            assertEquals(filePath, icon.getUri().getPath());
+
+            icon = IconCompat.createWithContentUri(file.toURI().toString());
+            assertEquals(IconCompat.TYPE_URI, icon.getType());
+            assertEquals(filePath, icon.getUri().getPath());
+        } finally {
+            file.delete();
+        }
+    }
+
+    @Test
+    public void testResourceIconCompat_getType() {
+        IconCompat icon = IconCompat.createWithResource(mContext, R.drawable.bmp_test);
+        assertEquals(IconCompat.TYPE_RESOURCE, icon.getType());
+        assertEquals("androidx.core.test", icon.getResPackage());
+        assertEquals(R.drawable.bmp_test, icon.getResId());
+    }
+
+    private void writeSampleImage(File imagefile) throws IOException {
+        try (InputStream source = mContext.getResources().openRawResource(R.drawable.testimage);
+             OutputStream target = new FileOutputStream(imagefile)) {
+            byte[] buffer = new byte[1024];
+            for (int len = source.read(buffer); len >= 0; len = source.read(buffer)) {
+                target.write(buffer, 0, len);
+            }
+        }
+    }
+
+    // Check if the created icon is valid and doesn't cause crashes for the public methods.
+    private void verifyIconCompatValidity(IconCompat icon) {
+        assertNotNull(icon);
+
+        // tint properties.
+        icon.setTint(Color.BLUE);
+        icon.setTintList(ColorStateList.valueOf(Color.RED));
+        icon.setTintMode(PorterDuff.Mode.XOR);
+
+        // Parcelable methods.
+        Bundle b = icon.toBundle();
+
+        assertNotNull(IconCompat.createFromBundle(b));
+
+        // loading drawable synchronously.
+        assertNotNull(icon.loadDrawable(mContext));
+    }
 }
diff --git a/compat/src/androidTest/java/androidx/core/view/DragStartHelperTest.java b/compat/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
index 268eead..f6e5d30 100644
--- a/compat/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
+++ b/compat/src/androidTest/java/androidx/core/view/DragStartHelperTest.java
@@ -28,11 +28,9 @@
 
 import android.app.Instrumentation;
 import android.graphics.Point;
-import android.os.Build;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.LargeTest;
-import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -42,7 +40,6 @@
 import android.view.ViewConfiguration;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 import androidx.core.test.R;
 
 import org.junit.Before;
@@ -52,7 +49,6 @@
 import org.mockito.ArgumentMatcher;
 import org.mockito.InOrder;
 
-@RequiresApi(13)
 @RunWith(AndroidJUnit4.class)
 public class DragStartHelperTest {
 
@@ -169,7 +165,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseClick() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -184,7 +179,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mousePressWithSecondaryButton() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -201,7 +195,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDrag() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -220,7 +213,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragWithNonprimaryButton() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -240,7 +232,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragUsingTouchListener() throws Throwable {
         final DragStartListener listener = createListener(true);
@@ -266,7 +257,6 @@
     }
 
     @SmallTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseDragWhenListenerReturnsFalse() throws Throwable {
         final DragStartListener listener = createListener(false);
@@ -290,7 +280,6 @@
     }
 
     @LargeTest
-    @SdkSuppress(minSdkVersion = Build.VERSION_CODES.ICE_CREAM_SANDWICH)
     @Test
     public void mouseLongPress() throws Throwable {
         final DragStartListener listener = createListener(true);
diff --git a/compat/src/androidTest/res/drawable/bmp_test.bmp b/compat/src/androidTest/res/drawable/bmp_test.bmp
new file mode 100644
index 0000000..5ec6dd4
--- /dev/null
+++ b/compat/src/androidTest/res/drawable/bmp_test.bmp
Binary files differ
diff --git a/compat/src/androidTest/res/drawable/testimage.jpg b/compat/src/androidTest/res/drawable/testimage.jpg
new file mode 100644
index 0000000..754df0c
--- /dev/null
+++ b/compat/src/androidTest/res/drawable/testimage.jpg
Binary files differ
diff --git a/compat/src/main/java/androidx/core/app/FrameMetricsAggregator.java b/compat/src/main/java/androidx/core/app/FrameMetricsAggregator.java
index 3598684..dd2824a 100644
--- a/compat/src/main/java/androidx/core/app/FrameMetricsAggregator.java
+++ b/compat/src/main/java/androidx/core/app/FrameMetricsAggregator.java
@@ -335,8 +335,8 @@
         private static final int NANOS_PER_MS = 1000000;
         // rounding value adds half a millisecond, for rounding to nearest ms
         private static final int NANOS_ROUNDING_VALUE = NANOS_PER_MS / 2;
-        private int mTrackingFlags;
-        private SparseIntArray[] mMetrics = new SparseIntArray[LAST_INDEX + 1];
+        int mTrackingFlags;
+        SparseIntArray[] mMetrics = new SparseIntArray[LAST_INDEX + 1];
         private ArrayList<WeakReference<Activity>> mActivities = new ArrayList<>();
         private static HandlerThread sHandlerThread = null;
         private static Handler sHandler = null;
diff --git a/compat/src/main/java/androidx/core/app/NotificationCompat.java b/compat/src/main/java/androidx/core/app/NotificationCompat.java
index 32e5ea9..b8b5205 100644
--- a/compat/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/compat/src/main/java/androidx/core/app/NotificationCompat.java
@@ -963,11 +963,37 @@
          * Set the large icon that is shown in the ticker and notification.
          */
         public Builder setLargeIcon(Bitmap icon) {
-            mLargeIcon = icon;
+            mLargeIcon = reduceLargeIconSize(icon);
             return this;
         }
 
         /**
+         * Reduce the size of a notification icon if it's overly large. The framework does
+         * this automatically starting from API 27.
+         */
+        private Bitmap reduceLargeIconSize(Bitmap icon) {
+            if (icon == null || Build.VERSION.SDK_INT >= 27) {
+                return icon;
+            }
+
+            Resources res = mContext.getResources();
+            int maxWidth = res.getDimensionPixelSize(R.dimen.notification_icon_max_width);
+            int maxHeight = res.getDimensionPixelSize(R.dimen.notification_icon_max_height);
+            if (icon.getWidth() <= maxWidth && icon.getHeight() <= maxHeight) {
+                return icon;
+            }
+
+            double scale = Math.min(
+                    maxWidth / (double) Math.max(1, icon.getWidth()),
+                    maxHeight / (double) Math.max(1, icon.getHeight()));
+            return Bitmap.createScaledBitmap(
+                    icon,
+                    (int) Math.ceil(icon.getWidth() * scale),
+                    (int) Math.ceil(icon.getHeight() * scale),
+                    true /* filtered */);
+        }
+
+        /**
          * Set the sound to play.  It will play on the default stream.
          *
          * <p>
@@ -2921,7 +2947,7 @@
         private final RemoteInput[] mDataOnlyRemoteInputs;
 
         private boolean mAllowGeneratedReplies;
-        private boolean mShowsUserInterface = true;
+        boolean mShowsUserInterface = true;
 
         private final @SemanticAction int mSemanticAction;
 
diff --git a/compat/src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java b/compat/src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java
index 5c3a8b8..7eea551 100644
--- a/compat/src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java
+++ b/compat/src/main/java/androidx/core/content/pm/ShortcutInfoCompat.java
@@ -36,18 +36,18 @@
  */
 public class ShortcutInfoCompat {
 
-    private Context mContext;
-    private String mId;
+    Context mContext;
+    String mId;
 
-    private Intent[] mIntents;
-    private ComponentName mActivity;
+    Intent[] mIntents;
+    ComponentName mActivity;
 
-    private CharSequence mLabel;
-    private CharSequence mLongLabel;
-    private CharSequence mDisabledMessage;
+    CharSequence mLabel;
+    CharSequence mLongLabel;
+    CharSequence mDisabledMessage;
 
-    private IconCompat mIcon;
-    private boolean mIsAlwaysBadged;
+    IconCompat mIcon;
+    boolean mIsAlwaysBadged;
 
     private ShortcutInfoCompat() { }
 
@@ -93,7 +93,7 @@
                     badge = mContext.getApplicationInfo().loadIcon(pm);
                 }
             }
-            mIcon.addToShortcutIntent(outIntent, badge);
+            mIcon.addToShortcutIntent(outIntent, badge, mContext);
         }
         return outIntent;
     }
diff --git a/compat/src/main/java/androidx/core/graphics/ColorUtils.java b/compat/src/main/java/androidx/core/graphics/ColorUtils.java
index c36142c..6c1e37f 100644
--- a/compat/src/main/java/androidx/core/graphics/ColorUtils.java
+++ b/compat/src/main/java/androidx/core/graphics/ColorUtils.java
@@ -16,14 +16,18 @@
 
 package androidx.core.graphics;
 
+import android.annotation.SuppressLint;
 import android.graphics.Color;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.FloatRange;
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 import androidx.annotation.VisibleForTesting;
 
+import java.util.Objects;
+
 /**
  * A set of color-related utility methods, building upon those available in {@code Color}.
  */
@@ -60,6 +64,69 @@
         return Color.argb(a, r, g, b);
     }
 
+    /**
+     * Composites two translucent colors together. More specifically, adds two colors using
+     * the {@linkplain android.graphics.PorterDuff.Mode#SRC_OVER source over} blending mode. The
+     * colors must not be pre-multiplied and the result is a non pre-multiplied color.
+     * <p>
+     * If the two colors have different color spaces, the foreground color is converted to the
+     * color space of the background color.
+     * <p>
+     * The following example creates a purple color by blending opaque blue with
+     * semi-translucent red:
+     *
+     * <pre>{@code
+     * Color purple = ColorUtils.compositeColors(
+     *         Color.valueOf(1f, 0f, 0f, 0.5f),
+     *         Color.valueOf(0f, 0f, 1f));
+     * }</pre>
+     *
+     * <em>Note:</em> This method requires API 26 or newer.
+     *
+     * @throws IllegalArgumentException if the
+     * {@linkplain android.graphics.Color#getModel models} of the colors do not match
+     */
+    @RequiresApi(26)
+    @NonNull
+    public static Color compositeColors(@NonNull Color foreground, @NonNull Color background) {
+        if (!Objects.equals(foreground.getModel(), background.getModel())) {
+            throw new IllegalArgumentException(
+                    "Color models must match (" + foreground.getModel() + " vs. "
+                            + background.getModel() + ")");
+        }
+
+        Color s = Objects.equals(background.getColorSpace(), foreground.getColorSpace())
+                ? foreground
+                : foreground.convert(background.getColorSpace());
+
+        float[] src = s.getComponents();
+        float[] dst = background.getComponents();
+
+        float sa = s.alpha();
+        // Destination alpha pre-composited
+        float da = background.alpha() * (1.0f - sa);
+
+        // Index of the alpha component
+        @SuppressLint("Range") // TODO Remove after upgrading Android Gradle Plugin to 3.1 or newer.
+        int ai = background.getComponentCount() - 1;
+
+        // Final alpha: src_alpha + dst_alpha * (1 - src_alpha)
+        dst[ai] = sa + da;
+
+        // Divide by final alpha to return non pre-multiplied color
+        if (dst[ai] > 0) {
+            sa /= dst[ai];
+            da /= dst[ai];
+        }
+
+        // Composite non-alpha components
+        for (int i = 0; i < ai; i++) {
+            dst[i] = src[i] * sa + dst[i] * da;
+        }
+
+        return Color.valueOf(dst, background.getColorSpace());
+    }
+
     private static int compositeAlpha(int foregroundAlpha, int backgroundAlpha) {
         return 0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF);
     }
diff --git a/compat/src/main/java/androidx/core/graphics/PathSegment.java b/compat/src/main/java/androidx/core/graphics/PathSegment.java
new file mode 100644
index 0000000..a5fe5cb
--- /dev/null
+++ b/compat/src/main/java/androidx/core/graphics/PathSegment.java
@@ -0,0 +1,99 @@
+/*
+ * 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.core.graphics;
+
+import static androidx.core.util.Preconditions.checkNotNull;
+
+import android.graphics.Path;
+import android.graphics.PointF;
+
+import androidx.annotation.NonNull;
+
+/**
+ * A line segment that represents an approximate fraction of a {@link Path} after
+ * {@linkplain PathUtils#flatten(Path) flattening}.
+ */
+public final class PathSegment {
+    private final PointF mStart;
+    private final float mStartFraction;
+    private final PointF mEnd;
+    private final float mEndFraction;
+
+    public PathSegment(@NonNull PointF start, float startFraction, @NonNull PointF end,
+            float endFraction) {
+        mStart = checkNotNull(start, "start == null");
+        mStartFraction = startFraction;
+        mEnd = checkNotNull(end, "end == null");
+        mEndFraction = endFraction;
+    }
+
+    /** The start point of the line segment. */
+    @NonNull
+    public PointF getStart() {
+        return mStart;
+    }
+
+    /**
+     * Fraction along the length of the path that the {@linkplain #getStart() start point} resides.
+     */
+    public float getStartFraction() {
+        return mStartFraction;
+    }
+
+    /** The end point of the line segment. */
+    @NonNull
+    public PointF getEnd() {
+        return mEnd;
+    }
+
+    /**
+     * Fraction along the length of the path that the {@linkplain #getEnd() end point} resides.
+     */
+    public float getEndFraction() {
+        return mEndFraction;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof PathSegment)) return false;
+        PathSegment that = (PathSegment) o;
+        return Float.compare(mStartFraction, that.mStartFraction) == 0
+                && Float.compare(mEndFraction, that.mEndFraction) == 0
+                && mStart.equals(that.mStart)
+                && mEnd.equals(that.mEnd);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mStart.hashCode();
+        result = 31 * result + (mStartFraction != +0.0f ? Float.floatToIntBits(mStartFraction) : 0);
+        result = 31 * result + mEnd.hashCode();
+        result = 31 * result + (mEndFraction != +0.0f ? Float.floatToIntBits(mEndFraction) : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PathSegment{"
+                + "start=" + mStart
+                + ", startFraction=" + mStartFraction
+                + ", end=" + mEnd
+                + ", endFraction=" + mEndFraction
+                + '}';
+    }
+}
diff --git a/compat/src/main/java/androidx/core/graphics/PathUtils.java b/compat/src/main/java/androidx/core/graphics/PathUtils.java
new file mode 100644
index 0000000..65e49f6
--- /dev/null
+++ b/compat/src/main/java/androidx/core/graphics/PathUtils.java
@@ -0,0 +1,84 @@
+/*
+ * 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.core.graphics;
+
+import android.graphics.Path;
+import android.graphics.PointF;
+
+import androidx.annotation.FloatRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** A set of path-related utility methods. */
+public final class PathUtils {
+    /**
+     * Flattens (or approximate) a {@link Path} with a series of line segments using a 0.5 pixel
+     * error.
+     *
+     * <em>Note:</em> This method requires API 26 or newer.
+     *
+     * @see #flatten(Path, float)
+     */
+    @RequiresApi(26)
+    @NonNull
+    public static Collection<PathSegment> flatten(@NonNull Path path) {
+        return flatten(path, 0.5f);
+    }
+
+    /**
+     * Flattens (or approximate) a {@link Path} with a series of line segments.
+     *
+     * <em>Note:</em> This method requires API 26 or newer.
+     *
+     * @param error The acceptable error for a line on the Path. Typically this would be
+     *              0.5 so that the error is less than half a pixel.
+     *
+     * @see Path#approximate
+     */
+    @RequiresApi(26)
+    @NonNull
+    public static Collection<PathSegment> flatten(@NonNull final Path path,
+            @FloatRange(from = 0) final float error) {
+        float[] pathData = path.approximate(error);
+        int pointCount = pathData.length / 3;
+        List<PathSegment> segments = new ArrayList<>(pointCount);
+        for (int i = 1; i < pointCount; i++) {
+            int index = i * 3;
+            int prevIndex = (i - 1) * 3;
+
+            float d = pathData[index];
+            float x = pathData[index + 1];
+            float y = pathData[index + 2];
+
+            float pd = pathData[prevIndex];
+            float px = pathData[prevIndex + 1];
+            float py = pathData[prevIndex + 2];
+
+            if (d != pd && (x != px || y != py)) {
+                segments.add(new PathSegment(new PointF(px, py), pd, new PointF(x, y), d));
+            }
+        }
+        return segments;
+    }
+
+    private PathUtils() {
+    }
+}
diff --git a/compat/src/main/java/androidx/core/graphics/TypefaceCompat.java b/compat/src/main/java/androidx/core/graphics/TypefaceCompat.java
index 042068a..746950c 100644
--- a/compat/src/main/java/androidx/core/graphics/TypefaceCompat.java
+++ b/compat/src/main/java/androidx/core/graphics/TypefaceCompat.java
@@ -45,7 +45,7 @@
 public class TypefaceCompat {
     private static final String TAG = "TypefaceCompat";
 
-    private static final TypefaceCompatImpl sTypefaceCompatImpl;
+    private static final TypefaceCompatBaseImpl sTypefaceCompatImpl;
     static {
         if (BuildCompat.isAtLeastP()) {
             sTypefaceCompatImpl = new TypefaceCompatApi28Impl();
@@ -66,20 +66,6 @@
      */
     private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
 
-    interface TypefaceCompatImpl {
-        // Create Typeface from XML which root node is "font-family"
-        Typeface createFromFontFamilyFilesResourceEntry(
-                Context context, FontFamilyFilesResourceEntry entry, Resources resources,
-                int style);
-
-        Typeface createFromFontInfo(Context context,
-                @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts,
-                int style);
-
-        Typeface createFromResourcesFontFile(
-                Context context, Resources resources, int id, String path, int style);
-    }
-
     private TypefaceCompat() {}
 
     /**
diff --git a/compat/src/main/java/androidx/core/graphics/TypefaceCompatBaseImpl.java b/compat/src/main/java/androidx/core/graphics/TypefaceCompatBaseImpl.java
index 3b03cb3..d1cec8a 100644
--- a/compat/src/main/java/androidx/core/graphics/TypefaceCompatBaseImpl.java
+++ b/compat/src/main/java/androidx/core/graphics/TypefaceCompatBaseImpl.java
@@ -25,7 +25,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.content.res.FontResourcesParserCompat.FontFamilyFilesResourceEntry;
 import androidx.core.content.res.FontResourcesParserCompat.FontFileResourceEntry;
@@ -40,8 +39,7 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@RequiresApi(14)
-class TypefaceCompatBaseImpl implements TypefaceCompat.TypefaceCompatImpl {
+class TypefaceCompatBaseImpl {
     private static final String TAG = "TypefaceCompatBaseImpl";
     private static final String CACHE_FILE_PREFIX = "cached_font_";
 
@@ -104,7 +102,6 @@
         }
     }
 
-    @Override
     public Typeface createFromFontInfo(Context context,
             @Nullable CancellationSignal cancellationSignal, @NonNull FontInfo[] fonts, int style) {
         // When we load from file, we can only load one font so just take the first one.
@@ -138,7 +135,6 @@
     }
 
     @Nullable
-    @Override
     public Typeface createFromFontFamilyFilesResourceEntry(Context context,
             FontFamilyFilesResourceEntry entry, Resources resources, int style) {
         FontFileResourceEntry best = findBestEntry(entry, style);
@@ -153,7 +149,6 @@
      * Used by Resources to load a font resource of type font file.
      */
     @Nullable
-    @Override
     public Typeface createFromResourcesFontFile(
             Context context, Resources resources, int id, String path, int style) {
         final File tmpFile = TypefaceCompatUtil.getTempFile(context);
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java b/compat/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
index 1e0e440..ceee4c5 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/DrawableCompat.java
@@ -311,11 +311,6 @@
                 return new WrappedDrawableApi21(drawable);
             }
             return drawable;
-        } else if (Build.VERSION.SDK_INT >= 19) {
-            if (!(drawable instanceof TintAwareDrawable)) {
-                return new WrappedDrawableApi19(drawable);
-            }
-            return drawable;
         } else {
             if (!(drawable instanceof TintAwareDrawable)) {
                 return new WrappedDrawableApi14(drawable);
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
index 1089d94..6dbe266 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/IconCompat.java
@@ -16,36 +16,106 @@
 
 package androidx.core.graphics.drawable;
 
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
 import android.app.ActivityManager;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
+import android.graphics.PorterDuff;
 import android.graphics.Shader;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Log;
 
+import androidx.annotation.ColorInt;
 import androidx.annotation.DrawableRes;
+import androidx.annotation.IdRes;
+import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.core.content.ContextCompat;
+import androidx.core.content.res.ResourcesCompat;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
 
 /**
  * Helper for accessing features in {@link android.graphics.drawable.Icon}.
  */
 public class IconCompat {
 
+    private static final String TAG = "IconCompat";
+
+    /**
+     * Value returned when the type of an {@link Icon} cannot be determined.
+     * @see #getType(Icon)
+     */
+    public static final int TYPE_UNKOWN = -1;
+
+    // TODO: Switch these to the public constants in the beta branch.
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final int TYPE_BITMAP = 1;
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final int TYPE_RESOURCE = 2;
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final int TYPE_DATA = 3;
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final int TYPE_URI = 4;
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public static final int TYPE_ADAPTIVE_BITMAP = 5;
+
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @IntDef({TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface IconType {
+    }
+
     // Ratio of expected size to actual icon size
     private static final float ADAPTIVE_ICON_INSET_FACTOR = 1 / 4f;
     private static final float DEFAULT_VIEW_PORT_SCALE = 1 / (1 + 2 * ADAPTIVE_ICON_INSET_FACTOR);
@@ -56,11 +126,12 @@
     private static final int KEY_SHADOW_ALPHA = 61;
     private static final int AMBIENT_SHADOW_ALPHA = 30;
 
-    private static final int TYPE_BITMAP   = 1;
-    private static final int TYPE_RESOURCE = 2;
-    private static final int TYPE_DATA     = 3;
-    private static final int TYPE_URI      = 4;
-    private static final int TYPE_ADAPTIVE_BITMAP = 5;
+    private static final String EXTRA_TYPE = "type";
+    private static final String EXTRA_OBJ = "obj";
+    private static final String EXTRA_INT1 = "int1";
+    private static final String EXTRA_INT2 = "int2";
+    private static final String EXTRA_TINT_LIST = "tint_list";
+    private static final String EXTRA_TINT_MODE = "tint_mode";
 
     private final int mType;
 
@@ -81,6 +152,10 @@
     // TYPE_DATA: data length
     private int             mInt2;
 
+    private ColorStateList  mTintList = null;
+    static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN; // SRC_IN
+    private PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
+
     /**
      * Create an Icon pointing to a drawable resource.
      * @param context The context for the application whose resources should be used to resolve the
@@ -94,7 +169,7 @@
         }
         final IconCompat rep = new IconCompat(TYPE_RESOURCE);
         rep.mInt1 = resId;
-        rep.mObj1 = context;
+        rep.mObj1 = context.getPackageName();
         return rep;
     }
 
@@ -179,6 +254,104 @@
         this.mType = mType;
     }
 
+
+    /**
+     * Gets the type of the icon provided.
+     * <p>
+     * Note that new types may be added later, so callers should guard against other
+     * types being returned.
+     */
+    @IconType
+    public int getType() {
+        if (mType == TYPE_UNKOWN && Build.VERSION.SDK_INT >= 23) {
+            return getType((Icon) mObj1);
+        }
+        return mType;
+    }
+
+    /**
+     * Gets the package used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_RESOURCE.
+     * Note: This package may not be available if referenced in the future, and it is
+     * up to the caller to ensure safety if this package is re-used and/or persisted.
+     */
+    @NonNull
+    public String getResPackage() {
+        if (mType == TYPE_UNKOWN && Build.VERSION.SDK_INT >= 23) {
+            return getResPackage((Icon) mObj1);
+        }
+        if (mType != TYPE_RESOURCE) {
+            throw new IllegalStateException("called getResPackage() on " + this);
+        }
+        return (String) mObj1;
+    }
+
+    /**
+     * Gets the resource id used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_RESOURCE.
+     * Note: This resource may not be available if the application changes at all, and it is
+     * up to the caller to ensure safety if this resource is re-used and/or persisted.
+     */
+    @IdRes
+    public int getResId() {
+        if (mType == TYPE_UNKOWN && Build.VERSION.SDK_INT >= 23) {
+            return getResId((Icon) mObj1);
+        }
+        if (mType != TYPE_RESOURCE) {
+            throw new IllegalStateException("called getResId() on " + this);
+        }
+        return mInt1;
+    }
+
+    /**
+     * Gets the uri used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_URI.
+     * Note: This uri may not be available in the future, and it is
+     * up to the caller to ensure safety if this uri is re-used and/or persisted.
+     */
+    @NonNull
+    public Uri getUri() {
+        if (mType == TYPE_UNKOWN && Build.VERSION.SDK_INT >= 23) {
+            return getUri((Icon) mObj1);
+        }
+        return Uri.parse((String) mObj1);
+    }
+
+    /**
+     * Store a color to use whenever this Icon is drawn.
+     *
+     * @param tint a color, as in {@link Drawable#setTint(int)}
+     * @return this same object, for use in chained construction
+     */
+    public IconCompat setTint(@ColorInt int tint) {
+        return setTintList(ColorStateList.valueOf(tint));
+    }
+
+    /**
+     * Store a color to use whenever this Icon is drawn.
+     *
+     * @param tintList as in {@link Drawable#setTintList(ColorStateList)}, null to remove tint
+     * @return this same object, for use in chained construction
+     */
+    public IconCompat setTintList(ColorStateList tintList) {
+        mTintList = tintList;
+        return this;
+    }
+
+    /**
+     * Store a blending mode to use whenever this Icon is drawn.
+     *
+     * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null
+     * @return this same object, for use in chained construction
+     */
+    public IconCompat setTintMode(PorterDuff.Mode mode) {
+        mTintMode = mode;
+        return this;
+    }
+
     /**
      * Convert this compat object to {@link Icon} object.
      *
@@ -186,35 +359,141 @@
      */
     @RequiresApi(23)
     public Icon toIcon() {
+        Icon icon;
         switch (mType) {
+            case TYPE_UNKOWN:
+                // When type is unknown we are just wrapping an icon.
+                return (Icon) mObj1;
             case TYPE_BITMAP:
-                return Icon.createWithBitmap((Bitmap) mObj1);
+                icon = Icon.createWithBitmap((Bitmap) mObj1);
+                break;
             case TYPE_ADAPTIVE_BITMAP:
                 if (Build.VERSION.SDK_INT >= 26) {
-                    return Icon.createWithAdaptiveBitmap((Bitmap) mObj1);
+                    icon = Icon.createWithAdaptiveBitmap((Bitmap) mObj1);
                 } else {
-                    return Icon.createWithBitmap(
+                    icon = Icon.createWithBitmap(
                             createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, false));
                 }
+                break;
             case TYPE_RESOURCE:
-                return Icon.createWithResource((Context) mObj1, mInt1);
+                icon = Icon.createWithResource((String) mObj1, mInt1);
+                break;
             case TYPE_DATA:
-                return Icon.createWithData((byte[]) mObj1, mInt1, mInt2);
+                icon = Icon.createWithData((byte[]) mObj1, mInt1, mInt2);
+                break;
             case TYPE_URI:
-                return Icon.createWithContentUri((String) mObj1);
+                icon = Icon.createWithContentUri((String) mObj1);
+                break;
             default:
                 throw new IllegalArgumentException("Unknown type");
         }
+        if (mTintList != null) {
+            icon.setTintList(mTintList);
+        }
+        if (mTintMode != DEFAULT_TINT_MODE) {
+            icon.setTintMode(mTintMode);
+        }
+        return icon;
     }
 
+
+
     /**
-     * Use {@link #addToShortcutIntent(Intent, Drawable)} instead
-     * @hide
+     * Returns a Drawable that can be used to draw the image inside this Icon, constructing it
+     * if necessary.
+     *
+     * @param context {@link android.content.Context Context} in which to load the drawable; used
+     *                to access {@link android.content.res.Resources Resources}, for example.
+     * @return A fresh instance of a drawable for this image, yours to keep.
      */
-    @RestrictTo(LIBRARY_GROUP)
-    @Deprecated
-    public void addToShortcutIntent(@NonNull Intent outIntent) {
-        addToShortcutIntent(outIntent, null);
+    public Drawable loadDrawable(Context context) {
+        if (Build.VERSION.SDK_INT >= 23) {
+            return toIcon().loadDrawable(context);
+        }
+        final Drawable result = loadDrawableInner(context);
+        if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) {
+            result.mutate();
+            DrawableCompat.setTintList(result, mTintList);
+            DrawableCompat.setTintMode(result, mTintMode);
+        }
+        return result;
+    }
+
+
+    /**
+     * Do the heavy lifting of loading the drawable, but stop short of applying any tint.
+     */
+    private Drawable loadDrawableInner(Context context) {
+        switch (mType) {
+            case TYPE_BITMAP:
+                return new BitmapDrawable(context.getResources(), (Bitmap) mObj1);
+            case TYPE_ADAPTIVE_BITMAP:
+                return new BitmapDrawable(context.getResources(),
+                        createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, false));
+            case TYPE_RESOURCE:
+                Resources res;
+                // figure out where to load resources from
+                String resPackage = (String) mObj1;
+                if (TextUtils.isEmpty(resPackage)) {
+                    // if none is specified, try the given context
+                    resPackage = context.getPackageName();
+                }
+                if ("android".equals(resPackage)) {
+                    res = Resources.getSystem();
+                } else {
+                    final PackageManager pm = context.getPackageManager();
+                    try {
+                        ApplicationInfo ai = pm.getApplicationInfo(
+                                resPackage, PackageManager.MATCH_UNINSTALLED_PACKAGES);
+                        if (ai != null) {
+                            res = pm.getResourcesForApplication(ai);
+                        } else {
+                            break;
+                        }
+                    } catch (PackageManager.NameNotFoundException e) {
+                        Log.e(TAG, String.format("Unable to find pkg=%s for icon %s",
+                                resPackage, this), e);
+                        break;
+                    }
+                }
+                try {
+                    return ResourcesCompat.getDrawable(res, mInt1, context.getTheme());
+                } catch (RuntimeException e) {
+                    Log.e(TAG, String.format("Unable to load resource 0x%08x from pkg=%s",
+                            mInt1,
+                            mObj1),
+                            e);
+                }
+                break;
+            case TYPE_DATA:
+                return new BitmapDrawable(context.getResources(),
+                        BitmapFactory.decodeByteArray((byte[]) mObj1, mInt1, mInt2)
+                );
+            case TYPE_URI:
+                final Uri uri = Uri.parse((String) mObj1);
+                final String scheme = uri.getScheme();
+                InputStream is = null;
+                if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+                        || ContentResolver.SCHEME_FILE.equals(scheme)) {
+                    try {
+                        is = context.getContentResolver().openInputStream(uri);
+                    } catch (Exception e) {
+                        Log.w(TAG, "Unable to load image from URI: " + uri, e);
+                    }
+                } else {
+                    try {
+                        is = new FileInputStream(new File((String) mObj1));
+                    } catch (FileNotFoundException e) {
+                        Log.w(TAG, "Unable to load image from path: " + uri, e);
+                    }
+                }
+                if (is != null) {
+                    return new BitmapDrawable(context.getResources(),
+                            BitmapFactory.decodeStream(is));
+                }
+                break;
+        }
+        return null;
     }
 
     /**
@@ -222,7 +501,8 @@
      */
     @RestrictTo(LIBRARY_GROUP)
     @SuppressWarnings("deprecation")
-    public void addToShortcutIntent(@NonNull Intent outIntent, @Nullable Drawable badge) {
+    public void addToShortcutIntent(@NonNull Intent outIntent, @Nullable Drawable badge,
+            @NonNull Context c) {
         Bitmap icon;
         switch (mType) {
             case TYPE_BITMAP:
@@ -236,23 +516,28 @@
                 icon = createLegacyIconFromAdaptiveIcon((Bitmap) mObj1, true);
                 break;
             case TYPE_RESOURCE:
-                if (badge == null) {
-                    outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
-                            Intent.ShortcutIconResource.fromContext((Context) mObj1, mInt1));
-                    return;
-                } else {
-                    Context context = (Context) mObj1;
-                    Drawable dr = ContextCompat.getDrawable(context, mInt1);
-                    if (dr.getIntrinsicWidth() <= 0 || dr.getIntrinsicHeight() <= 0) {
-                        int size = ((ActivityManager) context.getSystemService(
-                                Context.ACTIVITY_SERVICE)).getLauncherLargeIconSize();
-                        icon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+                try {
+                    Context context = c.createPackageContext((String) mObj1, 0);
+                    if (badge == null) {
+                        outIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
+                                Intent.ShortcutIconResource.fromContext(context, mInt1));
+                        return;
                     } else {
-                        icon = Bitmap.createBitmap(dr.getIntrinsicWidth(), dr.getIntrinsicHeight(),
-                                Bitmap.Config.ARGB_8888);
+                        Drawable dr = ContextCompat.getDrawable(context, mInt1);
+                        if (dr.getIntrinsicWidth() <= 0 || dr.getIntrinsicHeight() <= 0) {
+                            int size = ((ActivityManager) context.getSystemService(
+                                    Context.ACTIVITY_SERVICE)).getLauncherLargeIconSize();
+                            icon = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+                        } else {
+                            icon = Bitmap.createBitmap(dr.getIntrinsicWidth(),
+                                    dr.getIntrinsicHeight(),
+                                    Bitmap.Config.ARGB_8888);
+                        }
+                        dr.setBounds(0, 0, icon.getWidth(), icon.getHeight());
+                        dr.draw(new Canvas(icon));
                     }
-                    dr.setBounds(0, 0, icon.getWidth(), icon.getHeight());
-                    dr.draw(new Canvas(icon));
+                } catch (PackageManager.NameNotFoundException e) {
+                    throw new IllegalArgumentException("Can't find package " + mObj1, e);
                 }
                 break;
             default:
@@ -269,6 +554,192 @@
     }
 
     /**
+     * Adds this Icon to a Bundle that can be read back with the same parameters
+     * to {@link #createFromBundle(Bundle)}.
+     */
+    public Bundle toBundle() {
+        Bundle bundle = new Bundle();
+        switch (mType) {
+            case TYPE_BITMAP:
+            case TYPE_ADAPTIVE_BITMAP:
+                bundle.putParcelable(EXTRA_OBJ, (Bitmap) mObj1);
+                break;
+            case TYPE_UNKOWN:
+                // When unknown just wrapping an Icon.
+                bundle.putParcelable(EXTRA_OBJ, (Parcelable) mObj1);
+                break;
+            case TYPE_RESOURCE:
+            case TYPE_URI:
+                bundle.putString(EXTRA_OBJ, (String) mObj1);
+                break;
+            case TYPE_DATA:
+                bundle.putByteArray(EXTRA_OBJ, (byte[]) mObj1);
+                break;
+            default:
+                throw new IllegalArgumentException("Invalid icon");
+        }
+        bundle.putInt(EXTRA_TYPE, mType);
+        bundle.putInt(EXTRA_INT1, mInt1);
+        bundle.putInt(EXTRA_INT2, mInt2);
+        if (mTintList != null) {
+            bundle.putParcelable(EXTRA_TINT_LIST, mTintList);
+        }
+        if (mTintMode != DEFAULT_TINT_MODE) {
+            bundle.putString(EXTRA_TINT_MODE, mTintMode.name());
+        }
+        return bundle;
+    }
+
+    /**
+     * Extracts an icon from a bundle that was added using {@link #toBundle()}.
+     */
+    public static @Nullable IconCompat createFromBundle(@NonNull Bundle bundle) {
+        int type = bundle.getInt(EXTRA_TYPE);
+        IconCompat icon = new IconCompat(type);
+        icon.mInt1 = bundle.getInt(EXTRA_INT1);
+        icon.mInt2 = bundle.getInt(EXTRA_INT2);
+        if (bundle.containsKey(EXTRA_TINT_LIST)) {
+            icon.mTintList = bundle.getParcelable(EXTRA_TINT_LIST);
+        }
+        if (bundle.containsKey(EXTRA_TINT_MODE)) {
+            icon.mTintMode = PorterDuff.Mode.valueOf(
+                    bundle.getString(EXTRA_TINT_MODE));
+        }
+        switch (type) {
+            case TYPE_BITMAP:
+            case TYPE_ADAPTIVE_BITMAP:
+            case TYPE_UNKOWN:
+                icon.mObj1 = bundle.getParcelable(EXTRA_OBJ);
+                break;
+            case TYPE_RESOURCE:
+            case TYPE_URI:
+                icon.mObj1 = bundle.getString(EXTRA_OBJ);
+                break;
+            case TYPE_DATA:
+                icon.mObj1 = bundle.getByteArray(EXTRA_OBJ);
+                break;
+            default:
+                Log.w(TAG, "Unknown type " + type);
+                return null;
+        }
+        return icon;
+    }
+
+    /**
+     * Creates an IconCompat from an Icon.
+     */
+    @RequiresApi(23)
+    @Nullable
+    public static IconCompat createFromIcon(@NonNull Icon icon) {
+        IconCompat iconCompat = new IconCompat(TYPE_UNKOWN);
+        iconCompat.mObj1 = icon;
+        return iconCompat;
+    }
+
+    /**
+     * Gets the type of the icon provided.
+     * <p>
+     * Note that new types may be added later, so callers should guard against other
+     * types being returned. Returns {@link #TYPE_UNKOWN} when the type cannot be
+     * determined.
+     */
+    @IconType
+    @RequiresApi(23)
+    public static int getType(Icon icon) {
+        // TODO: Switch to public APIs on P+ in beta branch.
+        try {
+            return (int) icon.getClass().getMethod("getType").invoke(icon);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Unable to get icon type " + icon, e);
+            return TYPE_UNKOWN;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Unable to get icon type " + icon, e);
+            return TYPE_UNKOWN;
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Unable to get icon type " + icon, e);
+            return TYPE_UNKOWN;
+        }
+    }
+
+    /**
+     * Gets the package used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_RESOURCE.
+     * Note: This package may not be available if referenced in the future, and it is
+     * up to the caller to ensure safety if this package is re-used and/or persisted.
+     * Returns {@code null} when the value cannot be gotten.
+     */
+    @Nullable
+    @RequiresApi(23)
+    public static String getResPackage(Icon icon) {
+        // TODO: Switch to public APIs on P+ in beta branch.
+        try {
+            return (String) icon.getClass().getMethod("getResPackage").invoke(icon);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Unable to get icon package", e);
+            return null;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Unable to get icon package", e);
+            return null;
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Unable to get icon package", e);
+            return null;
+        }
+    }
+
+    /**
+     * Gets the resource used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_RESOURCE.
+     * Note: This resource may not be available if the application changes at all, and it is
+     * up to the caller to ensure safety if this resource is re-used and/or persisted.
+     * Returns {@code 0} if the id cannot be gotten.
+     */
+    @IdRes
+    @RequiresApi(23)
+    public static int getResId(Icon icon) {
+        // TODO: Switch to public APIs on P+ in beta branch.
+        try {
+            return (int) icon.getClass().getMethod("getResId").invoke(icon);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Unable to get icon resource", e);
+            return 0;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Unable to get icon resource", e);
+            return 0;
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Unable to get icon resource", e);
+            return 0;
+        }
+    }
+
+    /**
+     * Gets the uri used to create this icon.
+     * <p>
+     * Only valid for icons of type TYPE_URI.
+     * Note: This uri may not be available in the future, and it is
+     * up to the caller to ensure safety if this uri is re-used and/or persisted.
+     * Returns {@code null} if the uri cannot be gotten.
+     */
+    @Nullable
+    @RequiresApi(23)
+    public Uri getUri(Icon icon) {
+        // TODO: Switch to public APIs on P+ in beta branch.
+        try {
+            return (Uri) icon.getClass().getMethod("getUri").invoke(icon);
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Unable to get icon uri", e);
+            return null;
+        } catch (InvocationTargetException e) {
+            Log.e(TAG, "Unable to get icon uri", e);
+            return null;
+        } catch (NoSuchMethodException e) {
+            Log.e(TAG, "Unable to get icon uri", e);
+            return null;
+        }
+    }
+
+    /**
      * Converts a bitmap following the adaptive icon guide lines, into a bitmap following the
      * shortcut icon guide lines.
      * The returned bitmap will always have same width and height and clipped to a circle.
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/RoundedBitmapDrawable.java b/compat/src/main/java/androidx/core/graphics/drawable/RoundedBitmapDrawable.java
index 19ecb5c..cbee87f 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/RoundedBitmapDrawable.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/RoundedBitmapDrawable.java
@@ -32,7 +32,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 
 /**
  * A Drawable that wraps a bitmap and can be drawn with rounded corners. You can create a
@@ -44,7 +43,6 @@
  * {@link android.graphics.Canvas}.
  * </p>
  */
-@RequiresApi(9)
 public abstract class RoundedBitmapDrawable extends Drawable {
     private static final int DEFAULT_PAINT_FLAGS =
             Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG;
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi14.java b/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi14.java
index 021084c..b57ff37 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi14.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi14.java
@@ -192,6 +192,16 @@
     }
 
     @Override
+    public void setAutoMirrored(boolean mirrored) {
+        mDrawable.setAutoMirrored(mirrored);
+    }
+
+    @Override
+    public boolean isAutoMirrored() {
+        return mDrawable.isAutoMirrored();
+    }
+
+    @Override
     @Nullable
     public ConstantState getConstantState() {
         if (mState != null && mState.canConstantState()) {
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi19.java b/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi19.java
deleted file mode 100644
index 8f615f8..0000000
--- a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi19.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2015 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.core.graphics.drawable;
-
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(19)
-class WrappedDrawableApi19 extends WrappedDrawableApi14 {
-
-    WrappedDrawableApi19(Drawable drawable) {
-        super(drawable);
-    }
-
-    WrappedDrawableApi19(DrawableWrapperState state, Resources resources) {
-        super(state, resources);
-    }
-
-    @Override
-    public void setAutoMirrored(boolean mirrored) {
-        mDrawable.setAutoMirrored(mirrored);
-    }
-
-    @Override
-    public boolean isAutoMirrored() {
-        return mDrawable.isAutoMirrored();
-    }
-
-    @NonNull
-    @Override
-    DrawableWrapperState mutateConstantState() {
-        return new DrawableWrapperStateKitKat(mState, null);
-    }
-
-    private static class DrawableWrapperStateKitKat extends DrawableWrapperState {
-        DrawableWrapperStateKitKat(@Nullable DrawableWrapperState orig,
-                @Nullable Resources res) {
-            super(orig, res);
-        }
-
-        @NonNull
-        @Override
-        public Drawable newDrawable(@Nullable Resources res) {
-            return new WrappedDrawableApi19(this, res);
-        }
-    }
-}
diff --git a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi21.java b/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi21.java
index 3be9595..7a7dd5e 100644
--- a/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi21.java
+++ b/compat/src/main/java/androidx/core/graphics/drawable/WrappedDrawableApi21.java
@@ -36,7 +36,7 @@
 import java.lang.reflect.Method;
 
 @RequiresApi(21)
-class WrappedDrawableApi21 extends WrappedDrawableApi19 {
+class WrappedDrawableApi21 extends WrappedDrawableApi14 {
     private static final String TAG = "WrappedDrawableApi21";
     private static Method sIsProjectedDrawableMethod;
 
diff --git a/compat/src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java b/compat/src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java
index 89a096e..e468635 100644
--- a/compat/src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java
+++ b/compat/src/main/java/androidx/core/hardware/fingerprint/FingerprintManagerCompat.java
@@ -143,7 +143,7 @@
     }
 
     @RequiresApi(23)
-    private static CryptoObject unwrapCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
+    static CryptoObject unwrapCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
         if (cryptoObject == null) {
             return null;
         } else if (cryptoObject.getCipher() != null) {
diff --git a/compat/src/main/java/androidx/core/os/LocaleListHelper.java b/compat/src/main/java/androidx/core/os/LocaleListHelper.java
index dd210bc..0a656bc 100644
--- a/compat/src/main/java/androidx/core/os/LocaleListHelper.java
+++ b/compat/src/main/java/androidx/core/os/LocaleListHelper.java
@@ -24,7 +24,6 @@
 import androidx.annotation.IntRange;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.Size;
 
@@ -40,7 +39,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@RequiresApi(14)
 final class LocaleListHelper {
     private final Locale[] mList;
     // This is a comma-separated list of the locales in the LocaleListHelper created at construction
diff --git a/compat/src/main/java/androidx/core/provider/FontsContractCompat.java b/compat/src/main/java/androidx/core/provider/FontsContractCompat.java
index 60963a9..2429c2b 100644
--- a/compat/src/main/java/androidx/core/provider/FontsContractCompat.java
+++ b/compat/src/main/java/androidx/core/provider/FontsContractCompat.java
@@ -171,7 +171,7 @@
     /* package */ static final int RESULT_CODE_WRONG_CERTIFICATES = -2;
     // Note -3 is used by FontRequestCallback to indicate the font failed to load.
 
-    private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
+    static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
 
     private static final int BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS = 10000;
     private static final SelfDestructiveThread sBackgroundThread =
@@ -179,7 +179,7 @@
                     BACKGROUND_THREAD_KEEP_ALIVE_DURATION_MS);
 
     @NonNull
-    private static TypefaceResult getFontInternal(final Context context, final FontRequest request,
+    static TypefaceResult getFontInternal(final Context context, final FontRequest request,
             int style) {
         FontFamilyResult result;
         try {
@@ -200,9 +200,9 @@
         return new TypefaceResult(null, resultCode);
     }
 
-    private static final Object sLock = new Object();
+    static final Object sLock = new Object();
     @GuardedBy("sLock")
-    private static final SimpleArrayMap<String, ArrayList<ReplyCallback<TypefaceResult>>>
+    static final SimpleArrayMap<String, ArrayList<ReplyCallback<TypefaceResult>>>
             sPendingReplies = new SimpleArrayMap<>();
 
     private static final class TypefaceResult {
diff --git a/compat/src/main/java/androidx/core/provider/SelfDestructiveThread.java b/compat/src/main/java/androidx/core/provider/SelfDestructiveThread.java
index 9a51af1..bf17e31 100644
--- a/compat/src/main/java/androidx/core/provider/SelfDestructiveThread.java
+++ b/compat/src/main/java/androidx/core/provider/SelfDestructiveThread.java
@@ -210,7 +210,7 @@
         }
     }
 
-    private void onInvokeRunnable(Runnable runnable) {
+    void onInvokeRunnable(Runnable runnable) {
         runnable.run();
         synchronized (mLock) {
             mHandler.removeMessages(MSG_DESTRUCTION);
@@ -219,7 +219,7 @@
         }
     }
 
-    private void onDestruction() {
+    void onDestruction() {
         synchronized (mLock) {
             if (mHandler.hasMessages(MSG_INVOKE_RUNNABLE)) {
                 // This happens if post() is called after onDestruction and before synchronization
diff --git a/compat/src/main/java/androidx/core/text/BidiFormatter.java b/compat/src/main/java/androidx/core/text/BidiFormatter.java
index a53d7f6..66d64aa 100644
--- a/compat/src/main/java/androidx/core/text/BidiFormatter.java
+++ b/compat/src/main/java/androidx/core/text/BidiFormatter.java
@@ -82,7 +82,7 @@
     /**
      * The default text direction heuristic.
      */
-    private static final TextDirectionHeuristicCompat DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
+    static final TextDirectionHeuristicCompat DEFAULT_TEXT_DIRECTION_HEURISTIC = FIRSTSTRONG_LTR;
 
     /**
      * Unicode "Left-To-Right Embedding" (LRE) character.
@@ -214,12 +214,12 @@
     private static final int FLAG_STEREO_RESET = 2;
     private static final int DEFAULT_FLAGS = FLAG_STEREO_RESET;
 
-    private static final BidiFormatter DEFAULT_LTR_INSTANCE = new BidiFormatter(
+    static final BidiFormatter DEFAULT_LTR_INSTANCE = new BidiFormatter(
             false /* LTR context */,
             DEFAULT_FLAGS,
             DEFAULT_TEXT_DIRECTION_HEURISTIC);
 
-    private static final BidiFormatter DEFAULT_RTL_INSTANCE = new BidiFormatter(
+    static final BidiFormatter DEFAULT_RTL_INSTANCE = new BidiFormatter(
             true /* RTL context */,
             DEFAULT_FLAGS,
             DEFAULT_TEXT_DIRECTION_HEURISTIC);
@@ -259,7 +259,7 @@
      * @param flags The option flags.
      * @param heuristic The default text direction heuristic.
      */
-    private BidiFormatter(boolean isRtlContext, int flags, TextDirectionHeuristicCompat heuristic) {
+    BidiFormatter(boolean isRtlContext, int flags, TextDirectionHeuristicCompat heuristic) {
         mIsRtlContext = isRtlContext;
         mFlags = flags;
         mDefaultTextDirectionHeuristicCompat = heuristic;
@@ -512,7 +512,7 @@
      * @param locale The Locale whose directionality will be checked to be RTL or LTR
      * @return true if the {@code locale} directionality is RTL. False otherwise.
      */
-    private static boolean isRtlLocale(Locale locale) {
+    static boolean isRtlLocale(Locale locale) {
         return (TextUtilsCompat.getLayoutDirectionFromLocale(locale) == ViewCompat.LAYOUT_DIRECTION_RTL);
     }
 
@@ -956,4 +956,4 @@
             return Character.DIRECTIONALITY_OTHER_NEUTRALS;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/compat/src/main/java/androidx/core/util/Pair.java b/compat/src/main/java/androidx/core/util/Pair.java
index 72407e6..9db1f1f 100644
--- a/compat/src/main/java/androidx/core/util/Pair.java
+++ b/compat/src/main/java/androidx/core/util/Pair.java
@@ -53,11 +53,7 @@
             return false;
         }
         Pair<?, ?> p = (Pair<?, ?>) o;
-        return objectsEqual(p.first, first) && objectsEqual(p.second, second);
-    }
-
-    private static boolean objectsEqual(Object a, Object b) {
-        return a == b || (a != null && a.equals(b));
+        return ObjectsCompat.equals(p.first, first) && ObjectsCompat.equals(p.second, second);
     }
 
     /**
diff --git a/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java b/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
index 4b868f5..f51dff5 100644
--- a/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
+++ b/drawerlayout/src/main/java/androidx/drawerlayout/widget/DrawerLayout.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -35,6 +36,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.Gravity;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
@@ -241,6 +243,9 @@
 
     private final ArrayList<View> mNonDrawerViews;
 
+    private Rect mChildHitRect;
+    private Matrix mChildInvertedMatrix;
+
     /**
      * Listener for monitoring events about drawers.
      */
@@ -751,6 +756,59 @@
     }
 
     /**
+     * Returns true if x and y coord in DrawerLayout's coordinate space are inside the bounds of the
+     * child's coordinate space.
+     */
+    private boolean isInBoundsOfChild(float x, float y, View child) {
+        if (mChildHitRect == null) {
+            mChildHitRect = new Rect();
+        }
+        child.getHitRect(mChildHitRect);
+        return mChildHitRect.contains((int) x, (int) y);
+    }
+
+    /**
+     * Copied from ViewGroup#dispatchTransformedGenericPointerEvent(MotionEvent, View) then modified
+     * in order to make calls that are otherwise too visibility restricted to make.
+     */
+    private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
+        boolean handled;
+        final Matrix childMatrix = child.getMatrix();
+        if (!childMatrix.isIdentity()) {
+            MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
+            handled = child.dispatchGenericMotionEvent(transformedEvent);
+            transformedEvent.recycle();
+        } else {
+            final float offsetX = getScrollX() - child.getLeft();
+            final float offsetY = getScrollY() - child.getTop();
+            event.offsetLocation(offsetX, offsetY);
+            handled = child.dispatchGenericMotionEvent(event);
+            event.offsetLocation(-offsetX, -offsetY);
+        }
+        return handled;
+    }
+
+    /**
+     * Copied from ViewGroup#getTransformedMotionEvent(MotionEvent, View) then  modified in order to
+     * make calls that are otherwise too visibility restricted to make.
+     */
+    private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
+        final float offsetX = getScrollX() - child.getLeft();
+        final float offsetY = getScrollY() - child.getTop();
+        final MotionEvent transformedEvent = MotionEvent.obtain(event);
+        transformedEvent.offsetLocation(offsetX, offsetY);
+        final Matrix childMatrix = child.getMatrix();
+        if (!childMatrix.isIdentity()) {
+            if (mChildInvertedMatrix == null) {
+                mChildInvertedMatrix = new Matrix();
+            }
+            childMatrix.invert(mChildInvertedMatrix);
+            transformedEvent.transform(mChildInvertedMatrix);
+        }
+        return transformedEvent;
+    }
+
+    /**
      * Resolve the shared state of all drawers from the component ViewDragHelpers.
      * Should be called whenever a ViewDragHelper's state changes.
      */
@@ -1472,6 +1530,43 @@
     }
 
     @Override
+    public boolean dispatchGenericMotionEvent(MotionEvent event) {
+
+        // If this is not a pointer event, or if this is an hover exit, or we are not displaying
+        // that the content view can't be interacted with, then don't override and do anything
+        // special.
+        if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) == 0
+                || event.getAction() == MotionEvent.ACTION_HOVER_EXIT
+                || mScrimOpacity <= 0) {
+            return super.dispatchGenericMotionEvent(event);
+        }
+
+        final int childrenCount = getChildCount();
+        if (childrenCount != 0) {
+            final float x = event.getX();
+            final float y = event.getY();
+
+            // Walk through children from top to bottom.
+            for (int i = childrenCount - 1; i >= 0; i--) {
+                final View child = getChildAt(i);
+
+                // If the event is out of bounds or the child is the content view, don't dispatch
+                // to it.
+                if (!isInBoundsOfChild(x, y, child) || isContentView(child)) {
+                    continue;
+                }
+
+                // If a child handles it, return true.
+                if (dispatchTransformedGenericPointerEvent(event, child)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    @Override
     public boolean onTouchEvent(MotionEvent ev) {
         mLeftDragger.processTouchEvent(ev);
         mRightDragger.processTouchEvent(ev);
diff --git a/emoji/core/api/current.txt b/emoji/core/api/current.txt
index 785f44a..7b343a1 100644
--- a/emoji/core/api/current.txt
+++ b/emoji/core/api/current.txt
@@ -9,6 +9,7 @@
     method public boolean hasEmojiGlyph(java.lang.CharSequence);
     method public boolean hasEmojiGlyph(java.lang.CharSequence, int);
     method public static androidx.emoji.text.EmojiCompat init(androidx.emoji.text.EmojiCompat.Config);
+    method public void load();
     method public java.lang.CharSequence process(java.lang.CharSequence);
     method public java.lang.CharSequence process(java.lang.CharSequence, int, int);
     method public java.lang.CharSequence process(java.lang.CharSequence, int, int, int);
@@ -17,9 +18,12 @@
     method public void unregisterInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
     field public static final java.lang.String EDITOR_INFO_METAVERSION_KEY = "android.support.text.emoji.emojiCompat_metadataVersion";
     field public static final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY = "android.support.text.emoji.emojiCompat_replaceAll";
+    field public static final int LOAD_STATE_DEFAULT = 3; // 0x3
     field public static final int LOAD_STATE_FAILED = 2; // 0x2
     field public static final int LOAD_STATE_LOADING = 0; // 0x0
     field public static final int LOAD_STATE_SUCCEEDED = 1; // 0x1
+    field public static final int LOAD_STRATEGY_DEFAULT = 0; // 0x0
+    field public static final int LOAD_STRATEGY_MANUAL = 1; // 0x1
     field public static final int REPLACE_STRATEGY_ALL = 1; // 0x1
     field public static final int REPLACE_STRATEGY_DEFAULT = 0; // 0x0
     field public static final int REPLACE_STRATEGY_NON_EXISTENT = 2; // 0x2
@@ -31,6 +35,7 @@
     method public androidx.emoji.text.EmojiCompat.Config registerInitCallback(androidx.emoji.text.EmojiCompat.InitCallback);
     method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorColor(int);
     method public androidx.emoji.text.EmojiCompat.Config setEmojiSpanIndicatorEnabled(boolean);
+    method public androidx.emoji.text.EmojiCompat.Config setMetadataLoadStrategy(int);
     method public androidx.emoji.text.EmojiCompat.Config setReplaceAll(boolean);
     method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean);
     method public androidx.emoji.text.EmojiCompat.Config setUseEmojiAsDefaultStyle(boolean, java.util.List<java.lang.Integer>);
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java b/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
index 34f31fd..c8d3dad 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/text/ConfigTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
@@ -148,9 +149,25 @@
         assertTrue(emojiCompat.isEmojiSpanIndicatorEnabled());
     }
 
+    @Test
+    public void testBuild_manualLoadStrategy_doesNotCallMetadataLoaderLoad() {
+        final EmojiCompat.MetadataRepoLoader loader = mock(EmojiCompat.MetadataRepoLoader.class);
+        final EmojiCompat.Config config = new ValidTestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+    }
+
     private static class ValidTestConfig extends EmojiCompat.Config {
         ValidTestConfig() {
             super(new TestConfigBuilder.TestEmojiDataLoader());
         }
+
+        ValidTestConfig(EmojiCompat.MetadataRepoLoader loader) {
+            super(loader);
+        }
     }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java b/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
index dd8f3b9..fd9df56 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/text/EmojiCompatTest.java
@@ -53,6 +53,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
@@ -691,6 +692,97 @@
         metadataLoader.getLoaderLatch().countDown();
     }
 
+    @Test(expected = IllegalStateException.class)
+    public void testLoad_throwsException_whenLoadStrategyDefault() {
+        final EmojiCompat.MetadataRepoLoader loader = mock(EmojiCompat.MetadataRepoLoader.class);
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader);
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().load();
+    }
+
+    @Test
+    @SdkSuppress(maxSdkVersion = 18)
+    public void testLoad_pre19() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+
+        EmojiCompat.get().load();
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_startsLoading() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_DEFAULT, EmojiCompat.get().getLoadState());
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_onceSuccessDoesNotStartLoading() {
+        final EmojiCompat.MetadataRepoLoader loader = spy(new TestConfigBuilder
+                .TestEmojiDataLoader());
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+
+        reset(loader);
+        EmojiCompat.get().load();
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.LOAD_STATE_SUCCEEDED, EmojiCompat.get().getLoadState());
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 19)
+    public void testLoad_onceLoadingDoesNotStartLoading() throws InterruptedException {
+        final TestConfigBuilder.WaitingDataLoader loader = spy(
+                new TestConfigBuilder.WaitingDataLoader(true /*success*/));
+        final EmojiCompat.Config config = new TestConfigBuilder.TestConfig(loader)
+                .setMetadataLoadStrategy(EmojiCompat.LOAD_STRATEGY_MANUAL);
+
+        EmojiCompat.reset(config);
+
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+
+        EmojiCompat.get().load();
+        verify(loader, times(1)).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_LOADING);
+
+        reset(loader);
+
+        EmojiCompat.get().load();
+        verify(loader, never()).load(any(EmojiCompat.MetadataRepoLoaderCallback.class));
+
+        loader.getLoaderLatch().countDown();
+        loader.getTestLatch().await();
+
+        assertEquals(EmojiCompat.get().getLoadState(), EmojiCompat.LOAD_STATE_SUCCEEDED);
+    }
+
     @Test
     @SdkSuppress(maxSdkVersion = 18)
     public void testGetAssetSignature() {
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
index 27ea7c6..2882858 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiInputFilterTest.java
@@ -114,4 +114,16 @@
         verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
         verify(mEmojiCompat, times(0)).registerInitCallback(any(EmojiCompat.InitCallback.class));
     }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        final CharSequence result = mInputFilter.filter(testString, 0, 1, null, 0, 1);
+
+        assertNotNull(result);
+        verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
+        verify(mEmojiCompat, times(1)).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
index fade6f7..b8f0154 100644
--- a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTextWatcherTest.java
@@ -109,4 +109,15 @@
         verify(mEmojiCompat, times(1)).process(any(Spannable.class), anyInt(), anyInt(), anyInt(),
                 eq(EmojiCompat.REPLACE_STRATEGY_ALL));
     }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        final Spannable testString = new SpannableString("abc");
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        mTextWatcher.onTextChanged(testString, 0, 0, 1);
+
+        verify(mEmojiCompat, times(0)).process(any(Spannable.class), anyInt(), anyInt());
+        verify(mEmojiCompat, times(1)).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
 }
diff --git a/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java
new file mode 100644
index 0000000..cf74331
--- /dev/null
+++ b/emoji/core/src/androidTest/java/androidx/emoji/widget/EmojiTransformationMethodTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.emoji.widget;
+
+import static junit.framework.TestCase.assertSame;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import static androidx.emoji.util.EmojiMatcher.sameCharSequence;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.method.TransformationMethod;
+import android.view.View;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import androidx.emoji.text.EmojiCompat;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EmojiTransformationMethodTest {
+
+    private EmojiTransformationMethod mTransformationMethod;
+    private TransformationMethod mWrappedTransformationMethod;
+    private View mView;
+    private EmojiCompat mEmojiCompat;
+    private final String mTestString = "abc";
+
+    @Before
+    public void setup() {
+        mEmojiCompat = mock(EmojiCompat.class);
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_SUCCEEDED);
+        when(mEmojiCompat.process(any(CharSequence.class))).thenAnswer(new Answer<CharSequence>() {
+            @Override
+            public CharSequence answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                return new SpannableString((String) args[0]);
+            }
+        });
+        EmojiCompat.reset(mEmojiCompat);
+
+        mView = mock(View.class);
+        when(mView.isInEditMode()).thenReturn(false);
+
+        mWrappedTransformationMethod = mock(TransformationMethod.class);
+        when(mWrappedTransformationMethod.getTransformation(any(CharSequence.class),
+                any(View.class))).thenAnswer(new Answer<CharSequence>() {
+            @Override
+            public CharSequence answer(InvocationOnMock invocation) {
+                Object[] args = invocation.getArguments();
+                return (String) args[0];
+            }
+        });
+
+        mTransformationMethod = new EmojiTransformationMethod(mWrappedTransformationMethod);
+    }
+
+    @Test
+    public void testFilter_withNullSource() {
+        assertNull(mTransformationMethod.getTransformation(null, mView));
+        verify(mEmojiCompat, never()).process(any(CharSequence.class));
+    }
+
+    @Test(expected = NullPointerException.class)
+    public void testFilter_withNullView() {
+        mTransformationMethod.getTransformation("", null);
+    }
+
+    @Test
+    public void testFilter_withNullTransformationMethod() {
+        mTransformationMethod = new EmojiTransformationMethod(null);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertTrue(TextUtils.equals(new SpannableString(mTestString), result));
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(mTestString));
+    }
+
+    @Test
+    public void testFilter() {
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertTrue(TextUtils.equals(new SpannableString(mTestString), result));
+        assertTrue(result instanceof Spannable);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, times(1)).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_whenEmojiCompatLoading() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_LOADING);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_whenEmojiCompatLoadFailed() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_FAILED);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+
+    @Test
+    public void testFilter_withManualLoadStrategy() {
+        when(mEmojiCompat.getLoadState()).thenReturn(EmojiCompat.LOAD_STATE_DEFAULT);
+
+        final CharSequence result = mTransformationMethod.getTransformation(mTestString, mView);
+
+        assertSame(mTestString, result);
+        verify(mWrappedTransformationMethod, times(1)).getTransformation(
+                sameCharSequence(mTestString), same(mView));
+        verify(mEmojiCompat, never()).process(sameCharSequence(mTestString));
+        verify(mEmojiCompat, never()).registerInitCallback(any(EmojiCompat.InitCallback.class));
+    }
+}
diff --git a/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java b/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
index e7226ff..572606f 100644
--- a/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
+++ b/emoji/core/src/main/java/androidx/emoji/text/EmojiCompat.java
@@ -98,6 +98,11 @@
             "android.support.text.emoji.emojiCompat_replaceAll";
 
     /**
+     * EmojiCompat instance is constructed, however the initialization did not start yet.
+     */
+    public static final int LOAD_STATE_DEFAULT = 3;
+
+    /**
      * EmojiCompat is initializing.
      */
     public static final int LOAD_STATE_LOADING = 0;
@@ -117,7 +122,7 @@
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
-    @IntDef({LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, LOAD_STATE_FAILED})
+    @IntDef({LOAD_STATE_DEFAULT, LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, LOAD_STATE_FAILED})
     @Retention(RetentionPolicy.SOURCE)
     public @interface LoadState {
     }
@@ -147,6 +152,26 @@
     }
 
     /**
+     * {@link EmojiCompat} will start loading metadata when {@link #init(Config)} is called.
+     */
+    public static final int LOAD_STRATEGY_DEFAULT = 0;
+
+    /**
+     * {@link EmojiCompat} will wait for {@link #load()} to be called by developer in order to
+     * start loading metadata.
+     */
+    public static final int LOAD_STRATEGY_MANUAL = 1;
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY_GROUP)
+    @IntDef({LOAD_STRATEGY_DEFAULT, LOAD_STRATEGY_MANUAL})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LoadStrategy {
+    }
+
+    /**
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
@@ -207,18 +232,25 @@
     private final int mEmojiSpanIndicatorColor;
 
     /**
+     * @see Config#setMetadataLoadStrategy(int)
+     */
+    @LoadStrategy private final int mMetadataLoadStrategy;
+
+    /**
      * Private constructor for singleton instance.
      *
      * @see #init(Config)
      */
     private EmojiCompat(@NonNull final Config config) {
         mInitLock = new ReentrantReadWriteLock();
+        mLoadState = LOAD_STATE_DEFAULT;
         mReplaceAll = config.mReplaceAll;
         mUseEmojiAsDefaultStyle = config.mUseEmojiAsDefaultStyle;
         mEmojiAsDefaultStyleExceptions = config.mEmojiAsDefaultStyleExceptions;
         mEmojiSpanIndicatorEnabled = config.mEmojiSpanIndicatorEnabled;
         mEmojiSpanIndicatorColor = config.mEmojiSpanIndicatorColor;
         mMetadataLoader = config.mMetadataLoader;
+        mMetadataLoadStrategy = config.mMetadataLoadStrategy;
         mMainHandler = new Handler(Looper.getMainLooper());
         mInitCallbacks = new ArraySet<>();
         if (config.mInitCallbacks != null && !config.mInitCallbacks.isEmpty()) {
@@ -308,9 +340,30 @@
         }
     }
 
-    private void loadMetadata() {
+    /**
+     * When {@link Config#setMetadataLoadStrategy(int)} is set to {@link #LOAD_STRATEGY_MANUAL},
+     * this function starts loading the metadata. Calling the function when
+     * {@link Config#setMetadataLoadStrategy(int)} is {@code not} set to
+     * {@link #LOAD_STRATEGY_MANUAL} will throw an exception. The load will {@code not} start if:
+     * <ul>
+     *     <li>the metadata is already loaded successfully and {@link #getLoadState()} is
+     *     {@link #LOAD_STATE_SUCCEEDED}.
+     *     </li>
+     *      <li>a previous load attempt is not finished yet and {@link #getLoadState()} is
+     *     {@link #LOAD_STATE_LOADING}.</li>
+     * </ul>
+     *
+     * @throws IllegalStateException when {@link Config#setMetadataLoadStrategy(int)} is not set
+     * to {@link #LOAD_STRATEGY_MANUAL}
+     */
+    public void load() {
+        Preconditions.checkState(mMetadataLoadStrategy == LOAD_STRATEGY_MANUAL,
+                "Set metadataLoadStrategy to LOAD_STRATEGY_MANUAL to execute manual loading");
+        if (isInitialized()) return;
+
         mInitLock.writeLock().lock();
         try {
+            if (mLoadState == LOAD_STATE_LOADING) return;
             mLoadState = LOAD_STATE_LOADING;
         } finally {
             mInitLock.writeLock().unlock();
@@ -319,6 +372,21 @@
         mHelper.loadMetadata();
     }
 
+    private void loadMetadata() {
+        mInitLock.writeLock().lock();
+        try {
+            if (mMetadataLoadStrategy == LOAD_STRATEGY_DEFAULT) {
+                mLoadState = LOAD_STATE_LOADING;
+            }
+        } finally {
+            mInitLock.writeLock().unlock();
+        }
+
+        if (getLoadState() == LOAD_STATE_LOADING) {
+            mHelper.loadMetadata();
+        }
+    }
+
     private void onMetadataLoadSuccess() {
         final Collection<InitCallback> initCallbacks = new ArrayList<>();
         mInitLock.writeLock().lock();
@@ -393,8 +461,8 @@
      * Returns loading state of the EmojiCompat instance. When used on devices running API 18 or
      * below always returns {@link #LOAD_STATE_SUCCEEDED}.
      *
-     * @return one of {@link #LOAD_STATE_LOADING}, {@link #LOAD_STATE_SUCCEEDED},
-     * {@link #LOAD_STATE_FAILED}
+     * @return one of {@link #LOAD_STATE_DEFAULT}, {@link #LOAD_STATE_LOADING},
+     * {@link #LOAD_STATE_SUCCEEDED}, {@link #LOAD_STATE_FAILED}
      */
     public @LoadState int getLoadState() {
         mInitLock.readLock().lock();
@@ -809,6 +877,7 @@
         private Set<InitCallback> mInitCallbacks;
         private boolean mEmojiSpanIndicatorEnabled;
         private int mEmojiSpanIndicatorColor = Color.GREEN;
+        @LoadStrategy private int mMetadataLoadStrategy = LOAD_STRATEGY_DEFAULT;
 
         /**
          * Default constructor.
@@ -942,6 +1011,21 @@
         }
 
         /**
+         * Determines the strategy to start loading the metadata. By default {@link EmojiCompat}
+         * will start loading the metadata during {@link EmojiCompat#init(Config)}. When set to
+         * {@link EmojiCompat#LOAD_STRATEGY_MANUAL}, you should call {@link EmojiCompat#load()} to
+         * initiate metadata loading.
+         *
+         * @param strategy one of {@link EmojiCompat#LOAD_STRATEGY_DEFAULT},
+         *                  {@link EmojiCompat#LOAD_STRATEGY_MANUAL}
+         *
+         */
+        public Config setMetadataLoadStrategy(@LoadStrategy int strategy) {
+            mMetadataLoadStrategy = strategy;
+            return this;
+        }
+
+        /**
          * Returns the {@link MetadataRepoLoader}.
          */
         protected final MetadataRepoLoader getMetadataRepoLoader() {
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
index 22837a6..b44e859 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiInputFilter.java
@@ -79,6 +79,7 @@
 
                 return source;
             case EmojiCompat.LOAD_STATE_LOADING:
+            case EmojiCompat.LOAD_STATE_DEFAULT:
                 EmojiCompat.get().registerInitCallback(getInitCallback());
                 return source;
 
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
index 5d0e552..2197aff 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTextWatcher.java
@@ -80,6 +80,7 @@
                             mEmojiReplaceStrategy);
                     break;
                 case EmojiCompat.LOAD_STATE_LOADING:
+                case EmojiCompat.LOAD_STATE_DEFAULT:
                     EmojiCompat.get().registerInitCallback(getInitCallback());
                     break;
                 case EmojiCompat.LOAD_STATE_FAILED:
diff --git a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
index c082c83..81fe615 100644
--- a/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
+++ b/emoji/core/src/main/java/androidx/emoji/widget/EmojiTransformationMethod.java
@@ -57,6 +57,7 @@
                     return EmojiCompat.get().process(source);
                 case EmojiCompat.LOAD_STATE_LOADING:
                 case EmojiCompat.LOAD_STATE_FAILED:
+                case EmojiCompat.LOAD_STATE_DEFAULT:
                 default:
                     break;
             }
diff --git a/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java b/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
index b4da25b..3011a62 100644
--- a/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
+++ b/fragment/src/main/java/androidx/fragment/app/BackStackRecord.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.view.View;
 
+import androidx.annotation.Nullable;
 import androidx.core.util.LogWriter;
 import androidx.core.view.ViewCompat;
 
@@ -214,7 +215,7 @@
     int mTransitionStyle;
     boolean mAddToBackStack;
     boolean mAllowAddToBackStack = true;
-    String mName;
+    @Nullable String mName;
     boolean mCommitted;
     int mIndex = -1;
 
@@ -348,6 +349,7 @@
     }
 
     @Override
+    @Nullable
     public CharSequence getBreadCrumbTitle() {
         if (mBreadCrumbTitleRes != 0) {
             return mManager.mHost.getContext().getText(mBreadCrumbTitleRes);
@@ -356,6 +358,7 @@
     }
 
     @Override
+    @Nullable
     public CharSequence getBreadCrumbShortTitle() {
         if (mBreadCrumbShortTitleRes != 0) {
             return mManager.mHost.getContext().getText(mBreadCrumbShortTitleRes);
@@ -372,7 +375,7 @@
     }
 
     @Override
-    public FragmentTransaction add(Fragment fragment, String tag) {
+    public FragmentTransaction add(Fragment fragment, @Nullable String tag) {
         doAddOp(0, fragment, tag, OP_ADD);
         return this;
     }
@@ -384,12 +387,12 @@
     }
 
     @Override
-    public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
+    public FragmentTransaction add(int containerViewId, Fragment fragment, @Nullable String tag) {
         doAddOp(containerViewId, fragment, tag, OP_ADD);
         return this;
     }
 
-    private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
+    private void doAddOp(int containerViewId, Fragment fragment, @Nullable String tag, int opcmd) {
         final Class fragmentClass = fragment.getClass();
         final int modifiers = fragmentClass.getModifiers();
         if (fragmentClass.isAnonymousClass() || !Modifier.isPublic(modifiers)
@@ -432,7 +435,8 @@
     }
 
     @Override
-    public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {
+    public FragmentTransaction replace(int containerViewId, Fragment fragment,
+            @Nullable String tag) {
         if (containerViewId == 0) {
             throw new IllegalArgumentException("Must use non-zero containerViewId");
         }
@@ -477,7 +481,7 @@
     }
 
     @Override
-    public FragmentTransaction setPrimaryNavigationFragment(Fragment fragment) {
+    public FragmentTransaction setPrimaryNavigationFragment(@Nullable Fragment fragment) {
         addOp(new Op(OP_SET_PRIMARY_NAV, fragment));
 
         return this;
@@ -536,7 +540,7 @@
     }
 
     @Override
-    public FragmentTransaction addToBackStack(String name) {
+    public FragmentTransaction addToBackStack(@Nullable String name) {
         if (!mAllowAddToBackStack) {
             throw new IllegalStateException(
                     "This FragmentTransaction is not allowed to be added to the back stack.");
@@ -569,7 +573,7 @@
     }
 
     @Override
-    public FragmentTransaction setBreadCrumbTitle(CharSequence text) {
+    public FragmentTransaction setBreadCrumbTitle(@Nullable CharSequence text) {
         mBreadCrumbTitleRes = 0;
         mBreadCrumbTitleText = text;
         return this;
@@ -583,7 +587,7 @@
     }
 
     @Override
-    public FragmentTransaction setBreadCrumbShortTitle(CharSequence text) {
+    public FragmentTransaction setBreadCrumbShortTitle(@Nullable CharSequence text) {
         mBreadCrumbShortTitleRes = 0;
         mBreadCrumbShortTitleText = text;
         return this;
@@ -1008,6 +1012,7 @@
     }
 
     @Override
+    @Nullable
     public String getName() {
         return mName;
     }
diff --git a/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/src/main/java/androidx/fragment/app/Fragment.java
index 90728c1..fc34d9e 100644
--- a/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -98,6 +98,9 @@
     // When instantiated from saved state, this is the saved state.
     Bundle mSavedFragmentState;
     SparseArray<Parcelable> mSavedViewState;
+    // If the userVisibleHint is changed before the state is set,
+    // it is stored here
+    @Nullable Boolean mSavedUserVisibleHint;
 
     // Index into active fragment array.
     int mIndex = -1;
@@ -959,8 +962,7 @@
         if (mSavedFragmentState != null) {
             // Ensure that if the user visible hint is set before the Fragment has
             // restored its state that we don't lose the new value
-            mSavedFragmentState.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG,
-                    mUserVisibleHint);
+            mSavedUserVisibleHint = isVisibleToUser;
         }
     }
 
diff --git a/fragment/src/main/java/androidx/fragment/app/FragmentController.java b/fragment/src/main/java/androidx/fragment/app/FragmentController.java
index 97c4b87..69a2b52 100644
--- a/fragment/src/main/java/androidx/fragment/app/FragmentController.java
+++ b/fragment/src/main/java/androidx/fragment/app/FragmentController.java
@@ -63,11 +63,15 @@
     /**
      * Returns a {@link LoaderManager}.
      *
-     * @deprecated Loaders are managed separately from FragmentController
+     * @deprecated Loaders are managed separately from FragmentController and this now throws an
+     * {@link UnsupportedOperationException}. Use {@link LoaderManager#getInstance} to obtain a
+     * LoaderManager.
+     * @see LoaderManager#getInstance
      */
     @Deprecated
     public LoaderManager getSupportLoaderManager() {
-        return null;
+        throw new UnsupportedOperationException("Loaders are managed separately from "
+                + "FragmentController, use LoaderManager.getInstance() to obtain a LoaderManager.");
     }
 
     /**
diff --git a/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java b/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
index 8d37cf1..3190604 100644
--- a/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
+++ b/fragment/src/main/java/androidx/fragment/app/FragmentHostCallback.java
@@ -28,6 +28,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.core.app.ActivityCompat;
+import androidx.core.util.Preconditions;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -40,26 +41,27 @@
  * applicable to the host.
  */
 public abstract class FragmentHostCallback<E> extends FragmentContainer {
-    private final Activity mActivity;
-    final Context mContext;
-    private final Handler mHandler;
-    final int mWindowAnimations;
+    @Nullable private final Activity mActivity;
+    @NonNull private final Context mContext;
+    @NonNull private final Handler mHandler;
+    private final int mWindowAnimations;
     final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
 
-    public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
+    public FragmentHostCallback(@NonNull Context context, @NonNull Handler handler,
+            int windowAnimations) {
         this(context instanceof Activity ? (Activity) context : null, context, handler,
                 windowAnimations);
     }
 
-    FragmentHostCallback(FragmentActivity activity) {
+    FragmentHostCallback(@NonNull FragmentActivity activity) {
         this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
     }
 
-    FragmentHostCallback(Activity activity, Context context, Handler handler,
-            int windowAnimations) {
+    FragmentHostCallback(@Nullable Activity activity, @NonNull Context context,
+            @NonNull Handler handler, int windowAnimations) {
         mActivity = activity;
-        mContext = context;
-        mHandler = handler;
+        mContext = Preconditions.checkNotNull(context, "context == null");
+        mHandler = Preconditions.checkNotNull(handler, "handler == null");
         mWindowAnimations = windowAnimations;
     }
 
@@ -183,14 +185,17 @@
         return true;
     }
 
+    @Nullable
     Activity getActivity() {
         return mActivity;
     }
 
+    @NonNull
     Context getContext() {
         return mContext;
     }
 
+    @NonNull
     Handler getHandler() {
         return mHandler;
     }
diff --git a/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index beb07f8..37c480d 100644
--- a/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -56,12 +56,12 @@
 import androidx.annotation.CallSuper;
 import androidx.annotation.IdRes;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.StringRes;
 import androidx.collection.ArraySet;
 import androidx.core.util.DebugUtils;
 import androidx.core.util.LogWriter;
-import androidx.core.util.Pair;
 import androidx.core.view.ViewCompat;
 import androidx.lifecycle.ViewModelStore;
 
@@ -110,6 +110,7 @@
          * {@link FragmentTransaction#addToBackStack(String)
          * FragmentTransaction.addToBackStack(String)} when creating this entry.
          */
+        @Nullable
         public String getName();
 
         /**
@@ -130,12 +131,14 @@
          * Return the full bread crumb title for the entry, or null if it
          * does not have one.
          */
+        @Nullable
         public CharSequence getBreadCrumbTitle();
 
         /**
          * Return the short bread crumb title for the entry, or null if it
          * does not have one.
          */
+        @Nullable
         public CharSequence getBreadCrumbShortTitle();
     }
 
@@ -162,6 +165,7 @@
      * in the state, and if changes are made after the state is saved then they
      * will be lost.</p>
      */
+    @NonNull
     public abstract FragmentTransaction beginTransaction();
 
     /**
@@ -205,6 +209,7 @@
      * on the back stack associated with this ID are searched.
      * @return The fragment if found or null otherwise.
      */
+    @Nullable
     public abstract Fragment findFragmentById(@IdRes int id);
 
     /**
@@ -215,7 +220,8 @@
      * on the back stack are searched.
      * @return The fragment if found or null otherwise.
      */
-    public abstract Fragment findFragmentByTag(String tag);
+    @Nullable
+    public abstract Fragment findFragmentByTag(@Nullable String tag);
 
     /**
      * Flag for {@link #popBackStack(String, int)}
@@ -256,7 +262,7 @@
      * the named state itself is popped. If null, only the top state is popped.
      * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
      */
-    public abstract void popBackStack(String name, int flags);
+    public abstract void popBackStack(@Nullable String name, int flags);
 
     /**
      * Like {@link #popBackStack(String, int)}, but performs the operation immediately
@@ -264,7 +270,7 @@
      * afterwards without forcing the start of postponed Transactions.
      * @return Returns true if there was something popped, else false.
      */
-    public abstract boolean popBackStackImmediate(String name, int flags);
+    public abstract boolean popBackStackImmediate(@Nullable String name, int flags);
 
     /**
      * Pop all back stack states up to the one with the given identifier.
@@ -299,18 +305,21 @@
      * Return the BackStackEntry at index <var>index</var> in the back stack;
      * entries start index 0 being the bottom of the stack.
      */
+    @NonNull
     public abstract BackStackEntry getBackStackEntryAt(int index);
 
     /**
      * Add a new listener for changes to the fragment back stack.
      */
-    public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
+    public abstract void addOnBackStackChangedListener(
+            @NonNull OnBackStackChangedListener listener);
 
     /**
      * Remove a listener that was previously added with
      * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
      */
-    public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
+    public abstract void removeOnBackStackChangedListener(
+            @NonNull OnBackStackChangedListener listener);
 
     /**
      * Put a reference to a fragment in a Bundle.  This Bundle can be
@@ -322,7 +331,8 @@
      * @param key The name of the entry in the bundle.
      * @param fragment The Fragment whose reference is to be stored.
      */
-    public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
+    public abstract void putFragment(@NonNull Bundle bundle, @NonNull String key,
+            @NonNull Fragment fragment);
 
     /**
      * Retrieve the current Fragment instance for a reference previously
@@ -333,7 +343,8 @@
      * @return Returns the current Fragment instance that is associated with
      * the given reference.
      */
-    public abstract Fragment getFragment(Bundle bundle, String key);
+    @Nullable
+    public abstract Fragment getFragment(@NonNull Bundle bundle, @NonNull String key);
 
     /**
      * Get a list of all fragments that are currently added to the FragmentManager.
@@ -346,6 +357,7 @@
      *
      * @return A list of all fragments that are added to the FragmentManager.
      */
+    @NonNull
     public abstract List<Fragment> getFragments();
 
     /**
@@ -370,6 +382,7 @@
      * @return The generated state.  This will be null if there was no
      * interesting state created by the fragment.
      */
+    @Nullable
     public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
 
     /**
@@ -386,7 +399,7 @@
      * @param cb Callbacks to register
      * @param recursive true to automatically register this callback for all child FragmentManagers
      */
-    public abstract void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
+    public abstract void registerFragmentLifecycleCallbacks(@NonNull FragmentLifecycleCallbacks cb,
             boolean recursive);
 
     /**
@@ -396,7 +409,8 @@
      *
      * @param cb Callbacks to unregister
      */
-    public abstract void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb);
+    public abstract void unregisterFragmentLifecycleCallbacks(
+            @NonNull FragmentLifecycleCallbacks cb);
 
     /**
      * Return the currently active primary navigation fragment for this FragmentManager.
@@ -410,6 +424,7 @@
      *
      * @return the fragment designated as the primary navigation fragment
      */
+    @Nullable
     public abstract Fragment getPrimaryNavigationFragment();
 
     /**
@@ -458,7 +473,8 @@
          * @param f Fragment changing state
          * @param context Context that the Fragment is being attached to
          */
-        public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {}
+        public void onFragmentPreAttached(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @NonNull Context context) {}
 
         /**
          * Called after the fragment has been attached to its host. Its host will have had
@@ -468,7 +484,8 @@
          * @param f Fragment changing state
          * @param context Context that the Fragment was attached to
          */
-        public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {}
+        public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @NonNull Context context) {}
 
         /**
          * Called right before the fragment's {@link Fragment#onCreate(Bundle)} method is called.
@@ -479,8 +496,8 @@
          * @param f Fragment changing state
          * @param savedInstanceState Saved instance bundle from a previous instance
          */
-        public void onFragmentPreCreated(FragmentManager fm, Fragment f,
-                Bundle savedInstanceState) {}
+        public void onFragmentPreCreated(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @Nullable Bundle savedInstanceState) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -491,7 +508,8 @@
          * @param f Fragment changing state
          * @param savedInstanceState Saved instance bundle from a previous instance
          */
-        public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {}
+        public void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @Nullable Bundle savedInstanceState) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -502,8 +520,8 @@
          * @param f Fragment changing state
          * @param savedInstanceState Saved instance bundle from a previous instance
          */
-        public void onFragmentActivityCreated(FragmentManager fm, Fragment f,
-                Bundle savedInstanceState) {}
+        public void onFragmentActivityCreated(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @Nullable Bundle savedInstanceState) {}
 
         /**
          * Called after the fragment has returned a non-null view from the FragmentManager's
@@ -514,8 +532,8 @@
          * @param v View returned by the fragment
          * @param savedInstanceState Saved instance bundle from a previous instance
          */
-        public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
-                Bundle savedInstanceState) {}
+        public void onFragmentViewCreated(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @NonNull View v, @Nullable Bundle savedInstanceState) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -524,7 +542,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentStarted(FragmentManager fm, Fragment f) {}
+        public void onFragmentStarted(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -533,7 +551,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentResumed(FragmentManager fm, Fragment f) {}
+        public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -542,7 +560,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentPaused(FragmentManager fm, Fragment f) {}
+        public void onFragmentPaused(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -551,7 +569,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentStopped(FragmentManager fm, Fragment f) {}
+        public void onFragmentStopped(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -561,7 +579,8 @@
          * @param f Fragment changing state
          * @param outState Saved state bundle for the fragment
          */
-        public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {}
+        public void onFragmentSaveInstanceState(@NonNull FragmentManager fm, @NonNull Fragment f,
+                @NonNull Bundle outState) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -570,7 +589,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {}
+        public void onFragmentViewDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -579,7 +598,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentDestroyed(FragmentManager fm, Fragment f) {}
+        public void onFragmentDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) {}
 
         /**
          * Called after the fragment has returned from the FragmentManager's call to
@@ -588,7 +607,7 @@
          * @param fm Host FragmentManager
          * @param f Fragment changing state
          */
-        public void onFragmentDetached(FragmentManager fm, Fragment f) {}
+        public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) {}
     }
 }
 
@@ -650,6 +669,16 @@
     static final String VIEW_STATE_TAG = "android:view_state";
     static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
 
+    private static final class FragmentLifecycleCallbacksHolder {
+        final FragmentLifecycleCallbacks mCallback;
+        final boolean mRecursive;
+
+        FragmentLifecycleCallbacksHolder(FragmentLifecycleCallbacks callback, boolean recursive) {
+            mCallback = callback;
+            mRecursive = recursive;
+        }
+    }
+
     ArrayList<OpGenerator> mPendingActions;
     boolean mExecutingActions;
 
@@ -665,14 +694,14 @@
     ArrayList<Integer> mAvailBackStackIndices;
 
     ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
-    private final CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>>
+    private final CopyOnWriteArrayList<FragmentLifecycleCallbacksHolder>
             mLifecycleCallbacks = new CopyOnWriteArrayList<>();
 
     int mCurState = Fragment.INITIALIZING;
     FragmentHostCallback mHost;
     FragmentContainer mContainer;
     Fragment mParent;
-    Fragment mPrimaryNav;
+    @Nullable Fragment mPrimaryNav;
 
     static Field sAnimationListenerField = null;
 
@@ -799,12 +828,12 @@
     }
 
     @Override
-    public void popBackStack(final String name, final int flags) {
+    public void popBackStack(@Nullable final String name, final int flags) {
         enqueueAction(new PopBackStackState(name, -1, flags), false);
     }
 
     @Override
-    public boolean popBackStackImmediate(String name, int flags) {
+    public boolean popBackStackImmediate(@Nullable String name, int flags) {
         checkStateLoss();
         return popBackStackImmediate(name, -1, flags);
     }
@@ -898,6 +927,7 @@
     }
 
     @Override
+    @Nullable
     public Fragment getFragment(Bundle bundle, String key) {
         int index = bundle.getInt(key, -1);
         if (index == -1) {
@@ -952,6 +982,7 @@
     }
 
     @Override
+    @Nullable
     public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
         if (fragment.mIndex < 0) {
             throwException( new IllegalStateException("Fragment " + fragment
@@ -1335,8 +1366,13 @@
                                 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
                                         FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
                             }
-                            f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
-                                    FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
+                            if (f.mSavedUserVisibleHint != null) {
+                                f.mUserVisibleHint = f.mSavedUserVisibleHint;
+                                f.mSavedUserVisibleHint = null;
+                            } else {
+                                f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
+                                        FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
+                            }
                             if (!f.mUserVisibleHint) {
                                 f.mDeferStart = true;
                                 if (newState > Fragment.STOPPED) {
@@ -1989,6 +2025,7 @@
     }
 
     @Override
+    @Nullable
     public Fragment findFragmentById(int id) {
         // First look through added fragments.
         for (int i = mAdded.size() - 1; i >= 0; i--) {
@@ -2010,7 +2047,8 @@
     }
 
     @Override
-    public Fragment findFragmentByTag(String tag) {
+    @Nullable
+    public Fragment findFragmentByTag(@Nullable String tag) {
         if (tag != null) {
             // First look through added fragments.
             for (int i=mAdded.size()-1; i>=0; i--) {
@@ -3382,6 +3420,7 @@
     }
 
     @Override
+    @Nullable
     public Fragment getPrimaryNavigationFragment() {
         return mPrimaryNav;
     }
@@ -3389,14 +3428,14 @@
     @Override
     public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
             boolean recursive) {
-        mLifecycleCallbacks.add(new Pair<>(cb, recursive));
+        mLifecycleCallbacks.add(new FragmentLifecycleCallbacksHolder(cb, recursive));
     }
 
     @Override
     public void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb) {
         synchronized (mLifecycleCallbacks) {
             for (int i = 0, N = mLifecycleCallbacks.size(); i < N; i++) {
-                if (mLifecycleCallbacks.get(i).first == cb) {
+                if (mLifecycleCallbacks.get(i).mCallback == cb) {
                     mLifecycleCallbacks.remove(i);
                     break;
                 }
@@ -3404,7 +3443,8 @@
         }
     }
 
-    void dispatchOnFragmentPreAttached(Fragment f, Context context, boolean onlyRecursive) {
+    void dispatchOnFragmentPreAttached(@NonNull Fragment f, @NonNull Context context,
+            boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3412,14 +3452,15 @@
                         .dispatchOnFragmentPreAttached(f, context, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentPreAttached(this, f, context);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentPreAttached(this, f, context);
             }
         }
     }
 
-    void dispatchOnFragmentAttached(Fragment f, Context context, boolean onlyRecursive) {
+    void dispatchOnFragmentAttached(@NonNull Fragment f, @NonNull Context context,
+            boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3427,14 +3468,14 @@
                         .dispatchOnFragmentAttached(f, context, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentAttached(this, f, context);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentAttached(this, f, context);
             }
         }
     }
 
-    void dispatchOnFragmentPreCreated(Fragment f, Bundle savedInstanceState,
+    void dispatchOnFragmentPreCreated(@NonNull Fragment f, @Nullable Bundle savedInstanceState,
             boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
@@ -3443,14 +3484,15 @@
                         .dispatchOnFragmentPreCreated(f, savedInstanceState, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentPreCreated(this, f, savedInstanceState);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentPreCreated(this, f, savedInstanceState);
             }
         }
     }
 
-    void dispatchOnFragmentCreated(Fragment f, Bundle savedInstanceState, boolean onlyRecursive) {
+    void dispatchOnFragmentCreated(@NonNull Fragment f, @Nullable Bundle savedInstanceState,
+            boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3458,14 +3500,14 @@
                         .dispatchOnFragmentCreated(f, savedInstanceState, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentCreated(this, f, savedInstanceState);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentCreated(this, f, savedInstanceState);
             }
         }
     }
 
-    void dispatchOnFragmentActivityCreated(Fragment f, Bundle savedInstanceState,
+    void dispatchOnFragmentActivityCreated(@NonNull Fragment f, @Nullable Bundle savedInstanceState,
             boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
@@ -3474,15 +3516,15 @@
                         .dispatchOnFragmentActivityCreated(f, savedInstanceState, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentActivityCreated(this, f, savedInstanceState);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentActivityCreated(this, f, savedInstanceState);
             }
         }
     }
 
-    void dispatchOnFragmentViewCreated(Fragment f, View v, Bundle savedInstanceState,
-            boolean onlyRecursive) {
+    void dispatchOnFragmentViewCreated(@NonNull Fragment f, @NonNull View v,
+            @Nullable Bundle savedInstanceState, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3490,14 +3532,14 @@
                         .dispatchOnFragmentViewCreated(f, v, savedInstanceState, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentViewCreated(this, f, v, savedInstanceState);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentViewCreated(this, f, v, savedInstanceState);
             }
         }
     }
 
-    void dispatchOnFragmentStarted(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentStarted(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3505,14 +3547,14 @@
                         .dispatchOnFragmentStarted(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentStarted(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentStarted(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentResumed(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentResumed(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3520,14 +3562,14 @@
                         .dispatchOnFragmentResumed(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentResumed(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentResumed(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentPaused(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentPaused(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3535,14 +3577,14 @@
                         .dispatchOnFragmentPaused(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentPaused(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentPaused(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentStopped(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentStopped(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3550,14 +3592,15 @@
                         .dispatchOnFragmentStopped(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentStopped(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentStopped(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentSaveInstanceState(Fragment f, Bundle outState, boolean onlyRecursive) {
+    void dispatchOnFragmentSaveInstanceState(@NonNull Fragment f, @NonNull Bundle outState,
+            boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3565,14 +3608,14 @@
                         .dispatchOnFragmentSaveInstanceState(f, outState, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentSaveInstanceState(this, f, outState);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentSaveInstanceState(this, f, outState);
             }
         }
     }
 
-    void dispatchOnFragmentViewDestroyed(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentViewDestroyed(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3580,14 +3623,14 @@
                         .dispatchOnFragmentViewDestroyed(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentViewDestroyed(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentViewDestroyed(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentDestroyed(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentDestroyed(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3595,14 +3638,14 @@
                         .dispatchOnFragmentDestroyed(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentDestroyed(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentDestroyed(this, f);
             }
         }
     }
 
-    void dispatchOnFragmentDetached(Fragment f, boolean onlyRecursive) {
+    void dispatchOnFragmentDetached(@NonNull Fragment f, boolean onlyRecursive) {
         if (mParent != null) {
             FragmentManager parentManager = mParent.getFragmentManager();
             if (parentManager instanceof FragmentManagerImpl) {
@@ -3610,9 +3653,9 @@
                         .dispatchOnFragmentDetached(f, true);
             }
         }
-        for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
-            if (!onlyRecursive || p.second) {
-                p.first.onFragmentDetached(this, f);
+        for (FragmentLifecycleCallbacksHolder holder : mLifecycleCallbacks) {
+            if (!onlyRecursive || holder.mRecursive) {
+                holder.mCallback.onFragmentDetached(this, f);
             }
         }
     }
diff --git a/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java b/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
index 4182258..be51ea4 100644
--- a/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
+++ b/fragment/src/main/java/androidx/fragment/app/FragmentTransaction.java
@@ -25,6 +25,7 @@
 import androidx.annotation.AnimatorRes;
 import androidx.annotation.IdRes;
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.StringRes;
@@ -44,12 +45,14 @@
     /**
      * Calls {@link #add(int, Fragment, String)} with a 0 containerViewId.
      */
-    public abstract FragmentTransaction add(Fragment fragment, String tag);
+    @NonNull
+    public abstract FragmentTransaction add(@NonNull Fragment fragment, @Nullable String tag);
 
     /**
      * Calls {@link #add(int, Fragment, String)} with a null tag.
      */
-    public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment);
 
     /**
      * Add a fragment to the activity state.  This fragment may optionally
@@ -66,13 +69,16 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction add(@IdRes int containerViewId, Fragment fragment,
+    @NonNull
+    public abstract FragmentTransaction add(@IdRes int containerViewId, @NonNull Fragment fragment,
             @Nullable String tag);
 
     /**
      * Calls {@link #replace(int, Fragment, String)} with a null tag.
      */
-    public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction replace(@IdRes int containerViewId,
+            @NonNull Fragment fragment);
 
     /**
      * Replace an existing fragment that was added to a container.  This is
@@ -90,8 +96,9 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction replace(@IdRes int containerViewId, Fragment fragment,
-            @Nullable String tag);
+    @NonNull
+    public abstract FragmentTransaction replace(@IdRes int containerViewId,
+            @NonNull Fragment fragment, @Nullable String tag);
 
     /**
      * Remove an existing fragment.  If it was added to a container, its view
@@ -101,7 +108,8 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction remove(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction remove(@NonNull Fragment fragment);
 
     /**
      * Hides an existing fragment.  This is only relevant for fragments whose
@@ -112,7 +120,8 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction hide(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction hide(@NonNull Fragment fragment);
 
     /**
      * Shows a previously hidden fragment.  This is only relevant for fragments whose
@@ -123,7 +132,8 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction show(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction show(@NonNull Fragment fragment);
 
     /**
      * Detach the given fragment from the UI.  This is the same state as
@@ -136,7 +146,8 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction detach(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction detach(@NonNull Fragment fragment);
 
     /**
      * Re-attach a fragment after it had previously been detached from
@@ -148,7 +159,8 @@
      *
      * @return Returns the same FragmentTransaction instance.
      */
-    public abstract FragmentTransaction attach(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction attach(@NonNull Fragment fragment);
 
     /**
      * Set a currently active fragment in this FragmentManager as the primary navigation fragment.
@@ -166,7 +178,8 @@
      * @param fragment the fragment to set as the primary navigation fragment
      * @return the same FragmentTransaction instance
      */
-    public abstract FragmentTransaction setPrimaryNavigationFragment(Fragment fragment);
+    @NonNull
+    public abstract FragmentTransaction setPrimaryNavigationFragment(@Nullable Fragment fragment);
 
     /**
      * @return <code>true</code> if this transaction contains no operations,
@@ -212,6 +225,7 @@
      * @param exit An animation or animator resource ID used for the exit animation on the
      *             view of the fragment being removed or detached.
      */
+    @NonNull
     public abstract FragmentTransaction setCustomAnimations(@AnimatorRes @AnimRes int enter,
             @AnimatorRes @AnimRes int exit);
 
@@ -232,6 +246,7 @@
      *                view of the fragment being removed or detached caused by
      *                {@link FragmentManager#popBackStack()} or similar methods.
      */
+    @NonNull
     public abstract FragmentTransaction setCustomAnimations(@AnimatorRes @AnimRes int enter,
             @AnimatorRes @AnimRes int exit, @AnimatorRes @AnimRes int popEnter,
             @AnimatorRes @AnimRes int popExit);
@@ -248,19 +263,23 @@
      * @see Fragment#setSharedElementReturnTransition(Object)
      * @see Fragment#setSharedElementEnterTransition(Object)
      */
-    public abstract FragmentTransaction addSharedElement(View sharedElement, String name);
+    @NonNull
+    public abstract FragmentTransaction addSharedElement(@NonNull View sharedElement,
+            @NonNull String name);
 
     /**
      * Select a standard transition animation for this transaction.  May be
      * one of {@link #TRANSIT_NONE}, {@link #TRANSIT_FRAGMENT_OPEN},
      * {@link #TRANSIT_FRAGMENT_CLOSE}, or {@link #TRANSIT_FRAGMENT_FADE}.
      */
+    @NonNull
     public abstract FragmentTransaction setTransition(@Transit int transit);
 
     /**
      * Set a custom style resource that will be used for resolving transit
      * animations.
      */
+    @NonNull
     public abstract FragmentTransaction setTransitionStyle(@StyleRes int styleRes);
 
     /**
@@ -270,6 +289,7 @@
      *
      * @param name An optional name for this back stack state, or null.
      */
+    @NonNull
     public abstract FragmentTransaction addToBackStack(@Nullable String name);
 
     /**
@@ -286,6 +306,7 @@
      * addToBackStack will throw {@link IllegalStateException}. If addToBackStack
      * has already been called, this method will throw IllegalStateException.
      */
+    @NonNull
     public abstract FragmentTransaction disallowAddToBackStack();
 
     /**
@@ -294,6 +315,7 @@
      *
      * @param res A string resource containing the title.
      */
+    @NonNull
     public abstract FragmentTransaction setBreadCrumbTitle(@StringRes int res);
 
     /**
@@ -301,7 +323,8 @@
      * method is <em>not</em> recommended, as the string can not be changed
      * later if the locale changes.
      */
-    public abstract FragmentTransaction setBreadCrumbTitle(CharSequence text);
+    @NonNull
+    public abstract FragmentTransaction setBreadCrumbTitle(@Nullable CharSequence text);
 
     /**
      * Set the short title to show as a bread crumb when this transaction
@@ -309,6 +332,7 @@
      *
      * @param res A string resource containing the title.
      */
+    @NonNull
     public abstract FragmentTransaction setBreadCrumbShortTitle(@StringRes int res);
 
     /**
@@ -316,7 +340,8 @@
      * method is <em>not</em> recommended, as the string can not be changed
      * later if the locale changes.
      */
-    public abstract FragmentTransaction setBreadCrumbShortTitle(CharSequence text);
+    @NonNull
+    public abstract FragmentTransaction setBreadCrumbShortTitle(@Nullable CharSequence text);
 
     /**
      * Sets whether or not to allow optimizing operations within and across
@@ -346,6 +371,7 @@
      *                          or {@code false} to disable optimizing out redundant
      *                          operations on this transaction.
      */
+    @NonNull
     public abstract FragmentTransaction setReorderingAllowed(boolean reorderingAllowed);
 
     /**
@@ -375,7 +401,8 @@
      * @return this FragmentTransaction
      * @throws IllegalStateException if {@link #addToBackStack(String)} has been called
      */
-    public abstract FragmentTransaction runOnCommit(Runnable runnable);
+    @NonNull
+    public abstract FragmentTransaction runOnCommit(@NonNull Runnable runnable);
 
     /**
      * Schedules a commit of this transaction.  The commit does
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/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java b/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
index 99f47d2..d5b339a 100644
--- a/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
+++ b/heifwriter/src/androidTest/java/androidx/heifwriter/HeifWriterTest.java
@@ -18,12 +18,6 @@
 
 import static android.support.test.InstrumentationRegistry.getContext;
 
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
-import static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
 import android.graphics.Bitmap;
 import android.graphics.ImageFormat;
 import android.media.MediaExtractor;
@@ -34,13 +28,21 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.support.test.filters.LargeTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.util.Log;
+
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP;
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER;
+import static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.heifwriter.test.R;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -555,8 +557,12 @@
             MediaFormat format = extractor.getTrackFormat(0);
             int gridWidth = format.getInteger(MediaFormat.KEY_GRID_WIDTH);
             int gridHeight = format.getInteger(MediaFormat.KEY_GRID_HEIGHT);
-            assertEquals("Wrong grid width", 512, gridWidth);
-            assertEquals("Wrong grid height", 512, gridHeight);
+            int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS);
+            int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLS);
+            assertTrue("Wrong grid width or cols",
+                    ((width + gridWidth - 1) / gridWidth) == gridCols);
+            assertTrue("Wrong grid height or rows",
+                    ((height + gridHeight - 1) / gridHeight) == gridRows);
             extractor.release();
         }
     }
diff --git a/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java b/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
index 85aa925..3020b96 100644
--- a/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
+++ b/heifwriter/src/main/java/androidx/heifwriter/HeifEncoder.java
@@ -17,14 +17,9 @@
 package androidx.heifwriter;
 
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
-import android.opengl.GLES20;
-import android.opengl.GLUtils;
-import android.os.Looper;
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodec.BufferInfo;
@@ -32,13 +27,19 @@
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecCapabilities;
 import android.media.MediaFormat;
+import android.opengl.GLES20;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.Process;
 import android.util.Log;
 import android.util.Range;
 import android.view.Surface;
 
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -179,25 +180,14 @@
             throw new IllegalArgumentException("invalid encoder inputs");
         }
 
-        mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
-
-        mWidth = width;
-        mHeight = height;
-
-        if (useGrid) {
-            mGridWidth = GRID_WIDTH;
-            mGridHeight = GRID_HEIGHT;
-            mGridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
-            mGridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
-        } else {
-            mGridWidth = mWidth;
-            mGridHeight = mHeight;
-            mGridRows = 1;
-            mGridCols = 1;
+        boolean useHeicEncoder = false;
+        try {
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+            useHeicEncoder = true;
+        } catch (Exception e) {
+            mEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_HEVC);
         }
 
-        mNumTiles = mGridRows * mGridCols;
-
         mInputMode = inputMode;
 
         mCallback = cb;
@@ -218,13 +208,61 @@
                 CodecCapabilities.COLOR_FormatYUV420Flexible;
 
         // TODO: determine how to set bitrate and framerate, or use constant quality
-        MediaFormat codecFormat = MediaFormat.createVideoFormat(
-                MediaFormat.MIMETYPE_VIDEO_HEVC, mGridWidth, mGridHeight);
+        mWidth = width;
+        mHeight = height;
+
+        int gridWidth, gridHeight, gridRows, gridCols;
+
+        useGrid = useGrid && (width > GRID_WIDTH || height > GRID_HEIGHT);
+
+        if (useGrid) {
+            gridWidth = GRID_WIDTH;
+            gridHeight = GRID_HEIGHT;
+            gridRows = (height + GRID_HEIGHT - 1) / GRID_HEIGHT;
+            gridCols = (width + GRID_WIDTH - 1) / GRID_WIDTH;
+        } else {
+            gridWidth = mWidth;
+            gridHeight = mHeight;
+            gridRows = 1;
+            gridCols = 1;
+        }
+
+        MediaFormat codecFormat;
+        if (useHeicEncoder) {
+            codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC, mWidth, mHeight);
+        } else {
+            codecFormat = MediaFormat.createVideoFormat(
+                    MediaFormat.MIMETYPE_VIDEO_HEVC, gridWidth, gridHeight);
+        }
+
+        if (useGrid) {
+            codecFormat.setInteger(MediaFormat.KEY_GRID_WIDTH, gridWidth);
+            codecFormat.setInteger(MediaFormat.KEY_GRID_HEIGHT, gridHeight);
+            codecFormat.setInteger(MediaFormat.KEY_GRID_COLS, gridCols);
+            codecFormat.setInteger(MediaFormat.KEY_GRID_ROWS, gridRows);
+        }
+
+        if (useHeicEncoder) {
+            mGridWidth = width;
+            mGridHeight = height;
+            mGridRows = 1;
+            mGridCols = 1;
+        } else {
+            mGridWidth = gridWidth;
+            mGridHeight = gridHeight;
+            mGridRows = gridRows;
+            mGridCols = gridCols;
+        }
+        mNumTiles = mGridRows * mGridCols;
+
         codecFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 0);
         codecFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
 
         MediaCodecInfo.CodecCapabilities caps =
-                mEncoder.getCodecInfo().getCapabilitiesForType(MediaFormat.MIMETYPE_VIDEO_HEVC);
+                mEncoder.getCodecInfo().getCapabilitiesForType(useHeicEncoder
+                        ? MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC
+                        : MediaFormat.MIMETYPE_VIDEO_HEVC);
         MediaCodecInfo.EncoderCapabilities encoderCaps = caps.getEncoderCapabilities();
 
         codecFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mNumTiles);
@@ -262,34 +300,36 @@
         if (useSurfaceInternally) {
             mEncoderSurface = mEncoder.createInputSurface();
 
-            boolean useGLCopy = (mNumTiles > 1) || (inputMode == INPUT_MODE_BITMAP);
-            mEOSTracker = new SurfaceEOSTracker(useGLCopy);
+            boolean copyTiles = (mNumTiles > 1);
+            mEOSTracker = new SurfaceEOSTracker(copyTiles);
 
-            if (useGLCopy) {
-                mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
-                mEncoderEglSurface.makeCurrent();
+            if (inputMode == INPUT_MODE_SURFACE) {
+                if (copyTiles) {
+                    mEncoderEglSurface = new EglWindowSurface(mEncoderSurface);
+                    mEncoderEglSurface.makeCurrent();
 
-                mRectBlt = new EglRectBlt(
-                        new Texture2dProgram((inputMode == INPUT_MODE_BITMAP) ?
-                                Texture2dProgram.TEXTURE_2D :
-                                Texture2dProgram.TEXTURE_EXT),
-                        mWidth, mHeight);
+                    mRectBlt = new EglRectBlt(
+                            new Texture2dProgram((inputMode == INPUT_MODE_BITMAP)
+                                    ? Texture2dProgram.TEXTURE_2D
+                                    : Texture2dProgram.TEXTURE_EXT),
+                            mWidth, mHeight);
 
-                mTextureId = mRectBlt.createTextureObject();
+                    mTextureId = mRectBlt.createTextureObject();
 
-                if (inputMode == INPUT_MODE_SURFACE) {
-                    // use single buffer mode to block on input
-                    mInputTexture = new SurfaceTexture(mTextureId, true);
-                    mInputTexture.setOnFrameAvailableListener(this);
-                    mInputTexture.setDefaultBufferSize(mWidth, mHeight);
-                    mInputSurface = new Surface(mInputTexture);
+                    if (inputMode == INPUT_MODE_SURFACE) {
+                        // use single buffer mode to block on input
+                        mInputTexture = new SurfaceTexture(mTextureId, true);
+                        mInputTexture.setOnFrameAvailableListener(this);
+                        mInputTexture.setDefaultBufferSize(mWidth, mHeight);
+                        mInputSurface = new Surface(mInputTexture);
+                    }
+
+                    // make uncurrent since onFrameAvailable could be called on arbituray thread.
+                    // making the context current on a different thread will cause error.
+                    mEncoderEglSurface.makeUnCurrent();
+                } else {
+                    mInputSurface = mEncoderSurface;
                 }
-
-                // make uncurrent since the onFrameAvailable could be called on arbituray thread.
-                // making the context current on a different thread will cause error.
-                mEncoderEglSurface.makeUnCurrent();
-            } else {
-                mInputSurface = mEncoderSurface;
             }
         } else {
             for (int i = 0; i < INPUT_BUFFER_POOL_SIZE; i++) {
@@ -321,7 +361,20 @@
                     computePresentationTime(mInputIndex + mNumTiles - 1));
 
             if (takeFrame) {
-                copyTilesGL(mTmpMatrix);
+                // Copies from surface texture to encoder inputs using GL.
+                GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
+
+                for (int row = 0; row < mGridRows; row++) {
+                    for (int col = 0; col < mGridCols; col++) {
+                        int left = col * mGridWidth;
+                        int top = row * mGridHeight;
+                        mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                        mRectBlt.copyRect(mTextureId, mTmpMatrix, mSrcRect);
+                        mEncoderEglSurface.setPresentationTime(
+                                1000 * computePresentationTime(mInputIndex++));
+                        mEncoderEglSurface.swapBuffers();
+                    }
+                }
             }
 
             surfaceTexture.releaseTexImage();
@@ -407,21 +460,16 @@
         if (!takeFrame) return;
 
         synchronized (this) {
-            if (mEncoderEglSurface == null) {
-                return;
+            for (int row = 0; row < mGridRows; row++) {
+                for (int col = 0; col < mGridCols; col++) {
+                    int left = col * mGridWidth;
+                    int top = row * mGridHeight;
+                    mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
+                    Canvas canvas = mEncoderSurface.lockCanvas(null);
+                    canvas.drawBitmap(bitmap, mSrcRect, mDstRect, null);
+                    mEncoderSurface.unlockCanvasAndPost(canvas);
+                }
             }
-
-            mEncoderEglSurface.makeCurrent();
-
-            // load the bitmap to texture
-            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureId);
-            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
-
-            copyTilesGL(Texture2dProgram.V_FLIP_MATRIX);
-
-            // make uncurrent since the onFrameAvailable could be called on arbituray thread.
-            // making the context current on a different thread will cause error.
-            mEncoderEglSurface.makeUnCurrent();
         }
     }
 
@@ -594,28 +642,6 @@
     }
 
     /**
-     * Copies from source frame to encoder inputs using GL. The source could be either
-     * client's input surface, or the input bitmap loaded to texture.
-     *
-     * @param texMatrix The texture matrix to use. See the shader program in
-     * {@link Texture2dProgram} as well as {@link SurfaceTexture} for more details.
-     */
-    private void copyTilesGL(float[] texMatrix) {
-        GLES20.glViewport(0, 0, mGridWidth, mGridHeight);
-
-        for (int row = 0; row < mGridRows; row++) {
-            for (int col = 0; col < mGridCols; col++) {
-                int left = col * mGridWidth;
-                int top = row * mGridHeight;
-                mSrcRect.set(left, top, left + mGridWidth, top + mGridHeight);
-                mRectBlt.copyRect(mTextureId, texMatrix, mSrcRect);
-                mEncoderEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex++));
-                mEncoderEglSurface.swapBuffers();
-            }
-        }
-    }
-
-    /**
      * Routine to release all resources. Must be run on the same looper that
      * handles the MediaCodec callbacks.
      */
@@ -677,7 +703,7 @@
     private class SurfaceEOSTracker {
         private static final boolean DEBUG_EOS = false;
 
-        final boolean mUseGLCopy;
+        final boolean mCopyTiles;
         long mInputEOSTimeNs = -1;
         long mLastInputTimeNs = -1;
         long mEncoderEOSTimeUs = -1;
@@ -685,14 +711,14 @@
         long mLastOutputTimeUs = -1;
         boolean mSignaled;
 
-        SurfaceEOSTracker(boolean useGLCopy) {
-            mUseGLCopy = useGLCopy;
+        SurfaceEOSTracker(boolean copyTiles) {
+            mCopyTiles = copyTiles;
         }
 
         synchronized void updateInputEOSTime(long timestampNs) {
             if (DEBUG_EOS) Log.d(TAG, "updateInputEOSTime: " + timestampNs);
 
-            if (mUseGLCopy) {
+            if (mCopyTiles) {
                 if (mInputEOSTimeNs < 0) {
                     mInputEOSTimeNs = timestampNs;
                 }
@@ -773,15 +799,18 @@
 
             if (DEBUG) Log.d(TAG, "onOutputFormatChanged: " + format);
 
-            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
-            format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
-            format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
+            if (!MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC.equals(
+                    format.getString(MediaFormat.KEY_MIME))) {
+                format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_IMAGE_ANDROID_HEIC);
+                format.setInteger(MediaFormat.KEY_WIDTH, mWidth);
+                format.setInteger(MediaFormat.KEY_HEIGHT, mHeight);
 
-            if (mNumTiles > 1) {
-                format.setInteger(MediaFormat.KEY_GRID_WIDTH, mGridWidth);
-                format.setInteger(MediaFormat.KEY_GRID_HEIGHT, mGridHeight);
-                format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
-                format.setInteger(MediaFormat.KEY_GRID_COLS, mGridCols);
+                if (mNumTiles > 1) {
+                    format.setInteger(MediaFormat.KEY_GRID_WIDTH, mGridWidth);
+                    format.setInteger(MediaFormat.KEY_GRID_HEIGHT, mGridHeight);
+                    format.setInteger(MediaFormat.KEY_GRID_ROWS, mGridRows);
+                    format.setInteger(MediaFormat.KEY_GRID_COLS, mGridCols);
+                }
             }
 
             mCallback.onOutputFormatChanged(HeifEncoder.this, format);
@@ -800,8 +829,12 @@
         public void onOutputBufferAvailable(MediaCodec codec, int index, BufferInfo info) {
             if (codec != mEncoder || mOutputEOS) return;
 
-            if (DEBUG) Log.d(TAG, "onInputBufferAvailable: " + index + ", time "
-                    + info.presentationTimeUs + ", size " + info.size + ", flags " + info.flags);
+            if (DEBUG) {
+                Log.d(TAG, "onOutputBufferAvailable: " + index
+                        + ", time " + info.presentationTimeUs
+                        + ", size " + info.size
+                        + ", flags " + info.flags);
+            }
 
             if ((info.size > 0) && ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0)) {
                 ByteBuffer outputBuffer = codec.getOutputBuffer(index);
diff --git a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt
index 448c1b8..23888d3 100644
--- a/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt
+++ b/jetifier/jetifier/core/src/main/kotlin/android/support/tools/jetifier/core/transform/PackageMap.kt
@@ -244,6 +244,66 @@
             PackageRule(
                 from = "androidx/slice/builders",
                 to = "androidx/slice/builders"
+            ),
+            PackageRule(
+                from = "android/arch/paging/runtime",
+                to = "androidx/paging/runtime"
+            ),
+            PackageRule(
+                from = "android/arch/core/testing",
+                to = "androidx/arch/core/testing"
+            ),
+            PackageRule(
+                from = "android/arch/core",
+                to = "androidx/arch/core"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/db/framework",
+                to = "androidx/sqlite/db/framework"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/db",
+                to = "androidx/sqlite/db"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/room/rxjava2",
+                to = "androidx/room/rxjava2"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/room/guava",
+                to = "androidx/room/guava"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/room/testing",
+                to = "androidx/room/testing"
+            ),
+            PackageRule(
+                from = "android/arch/persistence/room",
+                to = "androidx/room"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle/extensions",
+                to = "androidx/lifecycle/extensions"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle/livedata/core",
+                to = "androidx/lifecycle/livedata/core"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle",
+                to = "androidx/lifecycle"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle/viewmodel",
+                to = "androidx/lifecycle/viewmodel"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle/livedata",
+                to = "androidx/lifecycle/livedata"
+            ),
+            PackageRule(
+                from = "android/arch/lifecycle/reactivestreams",
+                to = "androidx/lifecycle/reactivestreams"
             )
         )
 
diff --git a/jetifier/jetifier/core/src/main/resources/default.config b/jetifier/jetifier/core/src/main/resources/default.config
index 748aa8f..4dc5fda 100644
--- a/jetifier/jetifier/core/src/main/resources/default.config
+++ b/jetifier/jetifier/core/src/main/resources/default.config
@@ -14,1094 +14,1122 @@
 
 {
     # Skip packages that don't match the following regex
-    restrictToPackagePrefixes: [
+    "restrictToPackagePrefixes": [
         "android/support/",
-        "androix/temp",
-        # "android/arch/", - skip arch for now
+        "android/arch/",
+        "android/databinding/"
     ],
-    rules: [
+    "rules": [
         # Ignore
         {
-            from: "(.*)BuildConfig",
-            to: "ignoreInPreprocessorOnly"
+            "from": "(.*)BuildConfig",
+            "to": "ignoreInPreprocessorOnly"
         },
         {
-            from: "(.*)/package-info",
-            to: "ignoreInPreprocessorOnly"
+            "from": "(.*)/package-info",
+            "to": "ignoreInPreprocessorOnly"
         },
         {
-            from: "android/support/design/internal/(.*)",
-            to: "ignore"
+            "from": "android/support/design/internal/(.*)",
+            "to": "ignore"
         },
         {
-            from: "android/support/test/(.*)",
-            to: "ignore"
+            "from": "android/support/test/(.*)",
+            "to": "ignore"
         },
         {
-            from: "android/support/exifinterface/test/R(.*)",
-            to: "ignore"
+            "from": "android/support/exifinterface/test/R(.*)",
+            "to": "ignore"
         },
 
         #Resources
         {
-            from: "android/support/compat/R(.*)",
-            to: "androidx/core/R{0}"
+            "from": "android/support/compat/R(.*)",
+            "to": "androidx/core/R{0}"
         },
         {
-            from: "android/support/mediacompat/R(.*)",
-            to: "androidx/media/R{0}"
+            "from": "android/support/mediacompat/R(.*)",
+            "to": "androidx/media/R{0}"
         },
         {
-            from: "android/support/v7/cardview/R(.*)",
-            to: "androidx/cardview/R{0}"
+            "from": "android/support/v7/cardview/R(.*)",
+            "to": "androidx/cardview/R{0}"
         },
         {
-            from: "android/support/percent/R(.*)",
-            to: "androidx/percentlayout/R{0}"
+            "from": "android/support/percent/R(.*)",
+            "to": "androidx/percentlayout/R{0}"
         },
         {
-            from: "android/support/coordinatorlayout/R(.*)",
-            to: "androidx/coordinatorlayout/R{0}"
+            "from": "android/support/coordinatorlayout/R(.*)",
+            "to": "androidx/coordinatorlayout/R{0}"
         },
         {
-            from: "android/support/text/emoji/R(.*)",
-            to: "androidx/emoji/R{0}"
+            "from": "android/support/text/emoji/R(.*)",
+            "to": "androidx/emoji/R{0}"
         },
         {
-            from: "android/support/v7/recyclerview/R(.*)",
-            to: "androidx/recyclerview/R{0}"
+            "from": "android/support/v7/recyclerview/R(.*)",
+            "to": "androidx/recyclerview/R{0}"
         },
         {
-            from: "android/support/v7/gridlayout/R(.*)",
-            to: "androidx/gridlayout/R{0}"
+            "from": "android/support/v7/gridlayout/R(.*)",
+            "to": "androidx/gridlayout/R{0}"
         },
         {
-            from: "android/support/v7/appcompat/R(.*)",
-            to: "androidx/appcompat/R{0}"
+            "from": "android/support/v7/appcompat/R(.*)",
+            "to": "androidx/appcompat/R{0}"
         },
         {
-            from: "android/support/customtabs/R(.*)",
-            to: "androidx/browser/R{0}"
+            "from": "android/support/customtabs/R(.*)",
+            "to": "androidx/browser/R{0}"
         },
         {
-            from: "android/support/v7/mediarouter/R(.*)",
-            to: "androidx/mediarouter/R{0}"
+            "from": "android/support/v7/mediarouter/R(.*)",
+            "to": "androidx/mediarouter/R{0}"
         },
 
         # Legacy
         {
-            from: "android/support/v4/app/ActionBarDrawerToggle(.*)",
-            to: "androidx/legacy/app/ActionBarDrawerToggle{0}"
+            "from": "android/support/v4/app/ActionBarDrawerToggle(.*)",
+            "to": "androidx/legacy/app/ActionBarDrawerToggle{0}"
         },
         {
-            from: "android/support/v4/widget/Space(.*)",
-            to: "androidx/legacy/widget/Space{0}"
+            "from": "android/support/v4/widget/Space(.*)",
+            "to": "androidx/legacy/widget/Space{0}"
         },
         {
-            from: "android/support/v4/content/WakefulBroadcastReceiver(.*)",
-            to: "androidx/legacy/content/WakefulBroadcastReceiver{0}"
+            "from": "android/support/v4/content/WakefulBroadcastReceiver(.*)",
+            "to": "androidx/legacy/content/WakefulBroadcastReceiver{0}"
         },
         {
-            from: "android/support/v13/view/ViewCompat(.*)",
-            to: "androidx/legacy/view/ViewCompat{0}"
+            "from": "android/support/v13/view/ViewCompat(.*)",
+            "to": "androidx/legacy/view/ViewCompat{0}"
         },
         {
-            from: "android/support/v13/app/ActivityCompat(.*)",
-            to: "androidx/legacy/app/ActivityCompat{0}"
+            "from": "android/support/v13/app/ActivityCompat(.*)",
+            "to": "androidx/legacy/app/ActivityCompat{0}"
         },
         {
-            from: "android/support/v13/app/FragmentCompat(.*)",
-            to: "androidx/legacy/app/FragmentCompat{0}"
+            "from": "android/support/v13/app/FragmentCompat(.*)",
+            "to": "androidx/legacy/app/FragmentCompat{0}"
         },
         {
-            from: "android/support/v13/app/FragmentPagerAdapter(.*)",
-            to: "androidx/legacy/app/FragmentPagerAdapter{0}"
+            "from": "android/support/v13/app/FragmentPagerAdapter(.*)",
+            "to": "androidx/legacy/app/FragmentPagerAdapter{0}"
         },
         {
-            from: "android/support/v13/app/FragmentStatePagerAdapter(.*)",
-            to: "androidx/legacy/app/FragmentStatePagerAdapter{0}"
+            "from": "android/support/v13/app/FragmentStatePagerAdapter(.*)",
+            "to": "androidx/legacy/app/FragmentStatePagerAdapter{0}"
         },
         {
-            from: "android/support/v13/app/FragmentTabHost(.*)",
-            to: "androidx/legacy/app/FragmentTabHost{0}"
+            "from": "android/support/v13/app/FragmentTabHost(.*)",
+            "to": "androidx/legacy/app/FragmentTabHost{0}"
         },
 
         # Re-map Recycler view
         {
-            from: "android/support/v7/widget/AdapterHelper(.*)",
-            to: "androidx/recyclerview/widget/AdapterHelper{0}"
+            "from": "android/support/v7/widget/AdapterHelper(.*)",
+            "to": "androidx/recyclerview/widget/AdapterHelper{0}"
         },
         {
-            from: "android/support/v7/widget/ChildHelper(.*)",
-            to: "androidx/recyclerview/widget/ChildHelper{0}"
+            "from": "android/support/v7/widget/ChildHelper(.*)",
+            "to": "androidx/recyclerview/widget/ChildHelper{0}"
         },
         {
-            from: "android/support/v7/widget/DefaultItemAnimator(.*)",
-            to: "androidx/recyclerview/widget/DefaultItemAnimator{0}"
+            "from": "android/support/v7/widget/DefaultItemAnimator(.*)",
+            "to": "androidx/recyclerview/widget/DefaultItemAnimator{0}"
         },
         {
-            from: "android/support/v7/widget/DividerItemDecoration(.*)",
-            to: "androidx/recyclerview/widget/DividerItemDecoration{0}"
+            "from": "android/support/v7/widget/DividerItemDecoration(.*)",
+            "to": "androidx/recyclerview/widget/DividerItemDecoration{0}"
         },
         {
-            from: "android/support/v7/widget/FastScroller(.*)",
-            to: "androidx/recyclerview/widget/FastScroller{0}"
+            "from": "android/support/v7/widget/FastScroller(.*)",
+            "to": "androidx/recyclerview/widget/FastScroller{0}"
         },
         {
-            from: "android/support/v7/widget/GapWorker(.*)",
-            to: "androidx/recyclerview/widget/GapWorker{0}"
+            "from": "android/support/v7/widget/GapWorker(.*)",
+            "to": "androidx/recyclerview/widget/GapWorker{0}"
         },
         {
-            from: "android/support/v7/widget/GridLayoutManager(.*)",
-            to: "androidx/recyclerview/widget/GridLayoutManager{0}"
+            "from": "android/support/v7/widget/GridLayoutManager(.*)",
+            "to": "androidx/recyclerview/widget/GridLayoutManager{0}"
         },
         {
-            from: "android/support/v7/widget/LayoutState(.*)",
-            to: "androidx/recyclerview/widget/LayoutState{0}"
+            "from": "android/support/v7/widget/LayoutState(.*)",
+            "to": "androidx/recyclerview/widget/LayoutState{0}"
         },
         {
-            from: "android/support/v7/widget/LinearLayoutManager(.*)",
-            to: "androidx/recyclerview/widget/LinearLayoutManager{0}"
+            "from": "android/support/v7/widget/LinearLayoutManager(.*)",
+            "to": "androidx/recyclerview/widget/LinearLayoutManager{0}"
         },
         {
-            from: "android/support/v7/widget/LinearSmoothScroller(.*)",
-            to: "androidx/recyclerview/widget/LinearSmoothScroller{0}"
+            "from": "android/support/v7/widget/LinearSmoothScroller(.*)",
+            "to": "androidx/recyclerview/widget/LinearSmoothScroller{0}"
         },
         {
-            from: "android/support/v7/widget/LinearSnapHelper(.*)",
-            to: "androidx/recyclerview/widget/LinearSnapHelper{0}"
+            "from": "android/support/v7/widget/LinearSnapHelper(.*)",
+            "to": "androidx/recyclerview/widget/LinearSnapHelper{0}"
         },
         {
-            from: "android/support/v7/widget/OpReorderer(.*)",
-            to: "androidx/recyclerview/widget/OpReorderer{0}"
+            "from": "android/support/v7/widget/OpReorderer(.*)",
+            "to": "androidx/recyclerview/widget/OpReorderer{0}"
         },
         {
-            from: "android/support/v7/widget/OrientationHelper(.*)",
-            to: "androidx/recyclerview/widget/OrientationHelper{0}"
+            "from": "android/support/v7/widget/OrientationHelper(.*)",
+            "to": "androidx/recyclerview/widget/OrientationHelper{0}"
         },
         {
-            from: "android/support/v7/widget/PagerSnapHelper(.*)",
-            to: "androidx/recyclerview/widget/PagerSnapHelper{0}"
+            "from": "android/support/v7/widget/PagerSnapHelper(.*)",
+            "to": "androidx/recyclerview/widget/PagerSnapHelper{0}"
         },
         {
-            from: "android/support/v7/widget/PositionMap(.*)",
-            to: "androidx/recyclerview/widget/PositionMap{0}"
+            "from": "android/support/v7/widget/PositionMap(.*)",
+            "to": "androidx/recyclerview/widget/PositionMap{0}"
         },
         {
-            from: "android/support/v7/widget/RecyclerViewAccessibilityDelegate(.*)",
-            to: "androidx/recyclerview/widget/RecyclerViewAccessibilityDelegate{0}"
+            "from": "android/support/v7/widget/RecyclerViewAccessibilityDelegate(.*)",
+            "to": "androidx/recyclerview/widget/RecyclerViewAccessibilityDelegate{0}"
         },
         {
-            from: "android/support/v7/widget/RecyclerView(.*)",
-            to: "androidx/recyclerview/widget/RecyclerView{0}"
+            "from": "android/support/v7/widget/RecyclerView(.*)",
+            "to": "androidx/recyclerview/widget/RecyclerView{0}"
         },
         {
-            from: "android/support/v7/widget/ScrollbarHelper(.*)",
-            to: "androidx/recyclerview/widget/ScrollbarHelper{0}"
+            "from": "android/support/v7/widget/ScrollbarHelper(.*)",
+            "to": "androidx/recyclerview/widget/ScrollbarHelper{0}"
         },
         {
-            from: "android/support/v7/widget/SimpleItemAnimator(.*)",
-            to: "androidx/recyclerview/widget/SimpleItemAnimator{0}"
+            "from": "android/support/v7/widget/SimpleItemAnimator(.*)",
+            "to": "androidx/recyclerview/widget/SimpleItemAnimator{0}"
         },
         {
-            from: "android/support/v7/widget/SnapHelper(.*)",
-            to: "androidx/recyclerview/widget/SnapHelper{0}"
+            "from": "android/support/v7/widget/SnapHelper(.*)",
+            "to": "androidx/recyclerview/widget/SnapHelper{0}"
         },
         {
-            from: "android/support/v7/widget/StaggeredGridLayoutManager(.*)",
-            to: "androidx/recyclerview/widget/StaggeredGridLayoutManager{0}"
+            "from": "android/support/v7/widget/StaggeredGridLayoutManager(.*)",
+            "to": "androidx/recyclerview/widget/StaggeredGridLayoutManager{0}"
         },
         {
-            from: "android/support/v7/widget/ViewBoundsCheck(.*)",
-            to: "androidx/recyclerview/widget/ViewBoundsCheck{0}"
+            "from": "android/support/v7/widget/ViewBoundsCheck(.*)",
+            "to": "androidx/recyclerview/widget/ViewBoundsCheck{0}"
         },
         {
-            from: "android/support/v7/widget/ViewInfoStore(.*)",
-            to: "androidx/recyclerview/widget/ViewInfoStore{0}"
+            "from": "android/support/v7/widget/ViewInfoStore(.*)",
+            "to": "androidx/recyclerview/widget/ViewInfoStore{0}"
         },
         {
-            from: "android/support/v7/recyclerview/extensions/(.*)",
-            to: "androidx/recyclerview/widget/{0}"
+            "from": "android/support/v7/recyclerview/extensions/(.*)",
+            "to": "androidx/recyclerview/widget/{0}"
         },
         {
-            from: "android/support/v7/util/(.*)",
-            to: "androidx/recyclerview/widget/{0}"
+            "from": "android/support/v7/util/(.*)",
+            "to": "androidx/recyclerview/widget/{0}"
         },
         {
-            from: "android/support/v7/widget/helper/(.*)",
-            to: "androidx/recyclerview/widget/{0}"
+            "from": "android/support/v7/widget/helper/(.*)",
+            "to": "androidx/recyclerview/widget/{0}"
         },
         {
-            from: "android/support/v7/widget/util/(.*)",
-            to: "androidx/recyclerview/widget/{0}"
+            "from": "android/support/v7/widget/util/(.*)",
+            "to": "androidx/recyclerview/widget/{0}"
         },
 
         # Re-map
         {
-            from: "android/support/wear/(.*)",
-            to: "androidx/wear/{0}"
+            "from": "android/support/wear/(.*)",
+            "to": "androidx/wear/{0}"
         },
         {
-            from: "android/support/v7/preference/(.*)",
-            to: "androidx/preference/{0}"
+            "from": "android/support/v7/preference/(.*)",
+            "to": "androidx/preference/{0}"
         },
         {
-            from: "android/support/v7/internal/widget/PreferenceImageView(.*)",
-            to: "androidx/preference/internal/PreferenceImageView{0}"
+            "from": "android/support/v7/internal/widget/PreferenceImageView(.*)",
+            "to": "androidx/preference/internal/PreferenceImageView{0}"
         },
         {
-            from: "android/support/v14/preference/(.*)",
-            to: "androidx/preference/{0}"
+            "from": "android/support/v14/preference/(.*)",
+            "to": "androidx/preference/{0}"
         },
         {
-            from: "android/support/v7/graphics/ColorCutQuantizer(.*)",
-            to: "androidx/palette/graphics/ColorCutQuantizer{0}"
+            "from": "android/support/v7/graphics/ColorCutQuantizer(.*)",
+            "to": "androidx/palette/graphics/ColorCutQuantizer{0}"
         },
         {
-            from: "android/support/v7/graphics/Palette(.*)",
-            to: "androidx/palette/graphics/Palette{0}"
+            "from": "android/support/v7/graphics/Palette(.*)",
+            "to": "androidx/palette/graphics/Palette{0}"
         },
         {
-            from: "android/support/v7/graphics/Target(.*)",
-            to: "androidx/palette/graphics/Target{0}"
+            "from": "android/support/v7/graphics/Target(.*)",
+            "to": "androidx/palette/graphics/Target{0}"
         },
         {
-            from: "android/support/v7/app/MediaRoute(.*)",
-            to: "androidx/mediarouter/app/MediaRoute{0}"
+            "from": "android/support/v7/app/MediaRoute(.*)",
+            "to": "androidx/mediarouter/app/MediaRoute{0}"
         },
         {
-            from: "android/support/v7/app/OverlayListView(.*)",
-            to: "androidx/mediarouter/app/OverlayListView{0}"
+            "from": "android/support/v7/app/OverlayListView(.*)",
+            "to": "androidx/mediarouter/app/OverlayListView{0}"
         },
         {
-            from: "android/support/v7/media/(.*)",
-            to: "androidx/mediarouter/media/{0}"
+            "from": "android/support/v7/media/(.*)",
+            "to": "androidx/mediarouter/media/{0}"
         },
         {
-            from: "android/support/v7/widget/CardView(.*)",
-            to: "androidx/cardview/widget/CardView{0}"
+            "from": "android/support/v7/widget/CardView(.*)",
+            "to": "androidx/cardview/widget/CardView{0}"
         },
         {
-            from: "android/support/v7/widget/RoundRectDrawable(.*)",
-            to: "androidx/cardview/widget/RoundRectDrawable{0}"
+            "from": "android/support/v7/widget/RoundRectDrawable(.*)",
+            "to": "androidx/cardview/widget/RoundRectDrawable{0}"
         },
         {
-            from: "android/support/v7/widget/RoundRectDrawableWithShadow(.*)",
-            to: "androidx/cardview/widget/RoundRectDrawableWithShadow{0}"
+            "from": "android/support/v7/widget/RoundRectDrawableWithShadow(.*)",
+            "to": "androidx/cardview/widget/RoundRectDrawableWithShadow{0}"
         },
         {
-            from: "android/support/v7/widget/GridLayout(.*)",
-            to: "androidx/gridlayout/widget/GridLayout{0}"
+            "from": "android/support/v7/widget/GridLayout(.*)",
+            "to": "androidx/gridlayout/widget/GridLayout{0}"
         },
         {
-            from: "android/support/v7/(.*)",
-            to: "androidx/appcompat/{0}"
+            "from": "android/support/v7/(.*)",
+            "to": "androidx/appcompat/{0}"
         },
         {
-            from: "android/support/graphics/drawable/(.*)",
-            to: "androidx/vectordrawable/graphics/drawable/{0}"
+            "from": "android/support/graphics/drawable/(.*)",
+            "to": "androidx/vectordrawable/graphics/drawable/{0}"
         },
         {
-            from: "android/support/customtabs/ICustomTabsCallback(.*)",
-            to: "android/support/customtabs/ICustomTabsCallback/{0}"
+            "from": "android/support/customtabs/ICustomTabsCallback(.*)",
+            "to": "android/support/customtabs/ICustomTabsCallback/{0}"
         },
         {
-            from: "android/support/customtabs/ICustomTabsService(.*)",
-            to: "android/support/customtabs/ICustomTabsService/{0}"
+            "from": "android/support/customtabs/ICustomTabsService(.*)",
+            "to": "android/support/customtabs/ICustomTabsService/{0}"
         },
         {
-            from: "android/support/customtabs/IPostMessageService(.*)",
-            to: "android/support/customtabs/IPostMessageService/{0}"
+            "from": "android/support/customtabs/IPostMessageService(.*)",
+            "to": "android/support/customtabs/IPostMessageService/{0}"
         },
         {
-            from: "android/support/customtabs/(.*)",
-            to: "androidx/browser/customtabs/{0}"
+            "from": "android/support/customtabs/(.*)",
+            "to": "androidx/browser/customtabs/{0}"
         },
         {
-            from: "android/support/media/tv/(.*)",
-            to: "androidx/tvprovider/media/tv/{0}"
+            "from": "android/support/media/tv/(.*)",
+            "to": "androidx/tvprovider/media/tv/{0}"
         },
         {
-            from: "android/support/media/ExifInterface(.*)",
-            to: "androidx/exifinterface/media/ExifInterface{0}"
+            "from": "android/support/media/ExifInterface(.*)",
+            "to": "androidx/exifinterface/media/ExifInterface{0}"
         },
         {
-            from: "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout(.*)",
-            to: "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout{0}"
+            "from": "android/support/v17/internal/widget/OutlineOnlyWithChildrenFrameLayout(.*)",
+            "to": "androidx/leanback/preference/internal/OutlineOnlyWithChildrenFrameLayout{0}"
         },
         {
-            from: "android/support/v17/preference/(.*)",
-            to: "androidx/leanback/preference/{0}"
+            "from": "android/support/v17/preference/(.*)",
+            "to": "androidx/leanback/preference/{0}"
         },
         {
-            from: "android/support/v17/leanback/(.*)",
-            to: "androidx/leanback/{0}"
+            "from": "android/support/v17/leanback/(.*)",
+            "to": "androidx/leanback/{0}"
         },
         {
-            from: "android/support/percent/(.*)",
-            to: "androidx/percentlayout/widget/{0}"
+            "from": "android/support/percent/(.*)",
+            "to": "androidx/percentlayout/widget/{0}"
         },
         {
-            from: "android/support/app/recommendation/(.*)",
-            to: "androidx/recommendation/app/{0}"
+            "from": "android/support/app/recommendation/(.*)",
+            "to": "androidx/recommendation/app/{0}"
         },
         {
-            from: "android/support/annotation/(.*)",
-            to: "androidx/annotation/{0}"
+            "from": "android/support/annotation/(.*)",
+            "to": "androidx/annotation/{0}"
         },
         {
-            from: "android/support/transition/(.*)",
-            to: "androidx/transition/{0}"
+            "from": "android/support/transition/(.*)",
+            "to": "androidx/transition/{0}"
         },
         {
-            from: "android/support/text/emoji/bundled/BundledEmojiCompatConfig(.*)",
-            to: "androidx/emoji/bundled/BundledEmojiCompatConfig{0}"
+            "from": "android/support/text/emoji/bundled/BundledEmojiCompatConfig(.*)",
+            "to": "androidx/emoji/bundled/BundledEmojiCompatConfig{0}"
         },
         {
-            from: "android/support/text/emoji/widget/(.*)",
-            to: "androidx/emoji/widget/{0}"
+            "from": "android/support/text/emoji/widget/(.*)",
+            "to": "androidx/emoji/widget/{0}"
         },
         {
-            from: "android/support/text/emoji/(.*)",
-            to: "androidx/emoji/text/{0}"
+            "from": "android/support/text/emoji/(.*)",
+            "to": "androidx/emoji/text/{0}"
         },
         {
-            from: "android/support/content/(.*)",
-            to: "androidx/contentpager/content/{0}"
+            "from": "android/support/content/(.*)",
+            "to": "androidx/contentpager/content/{0}"
         },
         {
-            from: "android/support/v4/view/animation/PathInterpolatorApi14(.*)",
-            to: "androidx/core/view/animation/PathInterpolatorApi14{0}"
+            "from": "android/support/v4/view/animation/PathInterpolatorApi14(.*)",
+            "to": "androidx/core/view/animation/PathInterpolatorApi14{0}"
         },
         {
-            from: "android/support/v4/view/animation/PathInterpolatorCompat(.*)",
-            to: "androidx/core/view/animation/PathInterpolatorCompat{0}"
+            "from": "android/support/v4/view/animation/PathInterpolatorCompat(.*)",
+            "to": "androidx/core/view/animation/PathInterpolatorCompat{0}"
         },
         {
-            from: "android/support/animation/(.*)",
-            to: "androidx/dynamicanimation/animation/{0}"
+            "from": "android/support/animation/(.*)",
+            "to": "androidx/dynamicanimation/animation/{0}"
         },
         {
-            from: "android/support/v4/app/Fragment(.*)",
-            to: "androidx/fragment/app/Fragment{0}"
+            "from": "android/support/v4/app/Fragment(.*)",
+            "to": "androidx/fragment/app/Fragment{0}"
         },
         {
-            from: "android/support/v4/app/BaseFragment(.*)",
-            to: "androidx/fragment/app/BaseFragment{0}"
+            "from": "android/support/v4/app/BaseFragment(.*)",
+            "to": "androidx/fragment/app/BaseFragment{0}"
         },
         {
-            from: "android/support/v4/app/BackStack(.*)",
-            to: "androidx/fragment/app/BackStack{0}"
+            "from": "android/support/v4/app/BackStack(.*)",
+            "to": "androidx/fragment/app/BackStack{0}"
         },
         {
-            from: "android/support/v4/app/DialogFragment(.*)",
-            to: "androidx/fragment/app/DialogFragment{0}"
+            "from": "android/support/v4/app/DialogFragment(.*)",
+            "to": "androidx/fragment/app/DialogFragment{0}"
         },
         {
-            from: "android/support/v4/app/ListFragment(.*)",
-            to: "androidx/fragment/app/ListFragment{0}"
+            "from": "android/support/v4/app/ListFragment(.*)",
+            "to": "androidx/fragment/app/ListFragment{0}"
         },
         {
-            from: "android/support/v4/app/OneShotPreDrawListener(.*)",
-            to: "androidx/fragment/app/OneShotPreDrawListener{0}"
+            "from": "android/support/v4/app/OneShotPreDrawListener(.*)",
+            "to": "androidx/fragment/app/OneShotPreDrawListener{0}"
         },
         {
-            from: "android/support/v4/app/SuperNotCalledException(.*)",
-            to: "androidx/fragment/app/SuperNotCalledException{0}"
+            "from": "android/support/v4/app/SuperNotCalledException(.*)",
+            "to": "androidx/fragment/app/SuperNotCalledException{0}"
         },
 
         # Media
         {
-            from: "android/support/v4/media/app/NotificationCompat(.*)",
-            to: "androidx/media/app/NotificationCompat{0}"
+            "from": "android/support/v4/media/app/NotificationCompat(.*)",
+            "to": "androidx/media/app/NotificationCompat{0}"
         },
         {
-            from: "android/support/v4/media/AudioAttributesCompat(.*)",
-            to: "androidx/media/AudioAttributesCompat{0}"
+            "from": "android/support/v4/media/AudioAttributesCompat(.*)",
+            "to": "androidx/media/AudioAttributesCompat{0}"
         },
         {
-            from: "android/support/v4/media/MediaBrowserCompatUtils(.*)",
-            to: "androidx/media/MediaBrowserCompatUtils{0}"
+            "from": "android/support/v4/media/MediaBrowserCompatUtils(.*)",
+            "to": "androidx/media/MediaBrowserCompatUtils{0}"
         },
         {
-            from: "android/support/v4/media/MediaBrowserProtocol(.*)",
-            to: "androidx/media/MediaBrowserProtocol{0}"
+            "from": "android/support/v4/media/MediaBrowserProtocol(.*)",
+            "to": "androidx/media/MediaBrowserProtocol{0}"
         },
         {
-            from: "android/support/v4/media/MediaBrowserServiceCompat(.*)",
-            to: "androidx/media/MediaBrowserServiceCompat{0}"
+            "from": "android/support/v4/media/MediaBrowserServiceCompat(.*)",
+            "to": "androidx/media/MediaBrowserServiceCompat{0}"
         },
         {
-            from: "android/support/v4/media/VolumeProviderCompat(.*)",
-            to: "androidx/media/VolumeProviderCompat{0}"
+            "from": "android/support/v4/media/VolumeProviderCompat(.*)",
+            "to": "androidx/media/VolumeProviderCompat{0}"
         },
         {
-            from: "android/support/v4/media/session/MediaButtonReceiver(.*)",
-            to: "androidx/media/session/MediaButtonReceiver{0}"
+            "from": "android/support/v4/media/session/MediaButtonReceiver(.*)",
+            "to": "androidx/media/session/MediaButtonReceiver{0}"
         },
         {
-            from: "android/support/v4/media/(.*)",
-            to: "android/support/v4/media/{0}"
+            "from": "android/support/v4/media/(.*)",
+            "to": "android/support/v4/media/{0}"
         },
 
         # Rules involving libraries split
         {
-            from: "android/support/v4/widget/CursorAdapter(.*)",
-            to: "androidx/cursoradapter/widget/CursorAdapter{0}"
+            "from": "android/support/v4/widget/CursorAdapter(.*)",
+            "to": "androidx/cursoradapter/widget/CursorAdapter{0}"
         },
         {
-            from: "android/support/v4/widget/CursorFilter(.*)",
-            to: "androidx/cursoradapter/widget/CursorFilter{0}"
+            "from": "android/support/v4/widget/CursorFilter(.*)",
+            "to": "androidx/cursoradapter/widget/CursorFilter{0}"
         },
         {
-            from: "android/support/v4/widget/ResourceCursorAdapter(.*)",
-            to: "androidx/cursoradapter/widget/ResourceCursorAdapter{0}"
+            "from": "android/support/v4/widget/ResourceCursorAdapter(.*)",
+            "to": "androidx/cursoradapter/widget/ResourceCursorAdapter{0}"
         },
         {
-            from: "android/support/v4/widget/SimpleCursorAdapter(.*)",
-            to: "androidx/cursoradapter/widget/SimpleCursorAdapter{0}"
+            "from": "android/support/v4/widget/SimpleCursorAdapter(.*)",
+            "to": "androidx/cursoradapter/widget/SimpleCursorAdapter{0}"
         },
         {
-            from: "android/support/v4/app/LoaderManager(.*)",
-            to: "androidx/loader/app/LoaderManager{0}"
+            "from": "android/support/v4/app/LoaderManager(.*)",
+            "to": "androidx/loader/app/LoaderManager{0}"
         },
         {
-            from: "android/support/v4/content/Loader(.*)",
-            to: "androidx/loader/content/Loader{0}"
+            "from": "android/support/v4/content/Loader(.*)",
+            "to": "androidx/loader/content/Loader{0}"
         },
         {
-            from: "android/support/v4/content/CursorLoader(.*)",
-            to: "androidx/loader/content/CursorLoader{0}"
+            "from": "android/support/v4/content/CursorLoader(.*)",
+            "to": "androidx/loader/content/CursorLoader{0}"
         },
         {
-            from: "android/support/v4/content/AsyncTaskLoader(.*)",
-            to: "androidx/loader/content/AsyncTaskLoader{0}"
+            "from": "android/support/v4/content/AsyncTaskLoader(.*)",
+            "to": "androidx/loader/content/AsyncTaskLoader{0}"
         },
         {
-            from: "android/support/v4/content/ModernAsyncTask(.*)",
-            to: "androidx/loader/content/ModernAsyncTask{0}"
+            "from": "android/support/v4/content/ModernAsyncTask(.*)",
+            "to": "androidx/loader/content/ModernAsyncTask{0}"
         },
         {
-            from: "android/support/design/widget/CoordinatorLayout(.*)",
-            to: "androidx/coordinatorlayout/widget/CoordinatorLayout{0}"
+            "from": "android/support/design/widget/CoordinatorLayout(.*)",
+            "to": "androidx/coordinatorlayout/widget/CoordinatorLayout{0}"
         },
         {
-            from: "android/support/v4/widget/DirectedAcyclicGraph(.*)",
-            to: "androidx/coordinatorlayout/widget/DirectedAcyclicGraph{0}"
+            "from": "android/support/v4/widget/DirectedAcyclicGraph(.*)",
+            "to": "androidx/coordinatorlayout/widget/DirectedAcyclicGraph{0}"
         },
         {
-            from: "android/support/v4/widget/ViewGroupUtils(.*)",
-            to: "androidx/coordinatorlayout/widget/ViewGroupUtils{0}"
+            "from": "android/support/v4/widget/ViewGroupUtils(.*)",
+            "to": "androidx/coordinatorlayout/widget/ViewGroupUtils{0}"
         },
         {
-            from: "android/support/v4/view/ViewPager(.*)",
-            to: "androidx/viewpager/widget/ViewPager{0}"
+            "from": "android/support/v4/view/ViewPager(.*)",
+            "to": "androidx/viewpager/widget/ViewPager{0}"
         },
         {
-            from: "android/support/v4/view/PagerAdapter(.*)",
-            to: "androidx/viewpager/widget/PagerAdapter{0}"
+            "from": "android/support/v4/view/PagerAdapter(.*)",
+            "to": "androidx/viewpager/widget/PagerAdapter{0}"
         },
         {
-            from: "android/support/v4/view/PagerTabStrip(.*)",
-            to: "androidx/viewpager/widget/PagerTabStrip{0}"
+            "from": "android/support/v4/view/PagerTabStrip(.*)",
+            "to": "androidx/viewpager/widget/PagerTabStrip{0}"
         },
         {
-            from: "android/support/v4/view/PagerTitleStrip(.*)",
-            to: "androidx/viewpager/widget/PagerTitleStrip{0}"
+            "from": "android/support/v4/view/PagerTitleStrip(.*)",
+            "to": "androidx/viewpager/widget/PagerTitleStrip{0}"
         },
         {
-            from: "android/support/v4/view/AbsSavedState(.*)",
-            to: "androidx/customview/view/AbsSavedState{0}"
+            "from": "android/support/v4/view/AbsSavedState(.*)",
+            "to": "androidx/customview/view/AbsSavedState{0}"
         },
         {
-            from: "android/support/v4/widget/ExploreByTouchHelper(.*)",
-            to: "androidx/customview/widget/ExploreByTouchHelper{0}"
+            "from": "android/support/v4/widget/ExploreByTouchHelper(.*)",
+            "to": "androidx/customview/widget/ExploreByTouchHelper{0}"
         },
         {
-            from: "android/support/v4/widget/FocusStrategy(.*)",
-            to: "androidx/customview/widget/FocusStrategy{0}"
+            "from": "android/support/v4/widget/FocusStrategy(.*)",
+            "to": "androidx/customview/widget/FocusStrategy{0}"
         },
         {
-            from: "android/support/v4/widget/ViewDragHelper(.*)",
-            to: "androidx/customview/widget/ViewDragHelper{0}"
+            "from": "android/support/v4/widget/ViewDragHelper(.*)",
+            "to": "androidx/customview/widget/ViewDragHelper{0}"
         },
         {
-            from: "android/support/v4/view/animation/(.*)",
-            to: "androidx/interpolator/view/animation/{0}"
+            "from": "android/support/v4/view/animation/(.*)",
+            "to": "androidx/interpolator/view/animation/{0}"
         },
         {
-            from: "android/support/v4/widget/DrawerLayout(.*)",
-            to: "androidx/drawerlayout/widget/DrawerLayout{0}"
+            "from": "android/support/v4/widget/DrawerLayout(.*)",
+            "to": "androidx/drawerlayout/widget/DrawerLayout{0}"
         },
         {
-            from: "android/support/v4/widget/SlidingPaneLayout(.*)",
-            to: "androidx/slidingpanelayout/widget/SlidingPaneLayout{0}"
+            "from": "android/support/v4/widget/SlidingPaneLayout(.*)",
+            "to": "androidx/slidingpanelayout/widget/SlidingPaneLayout{0}"
         },
         {
-            from: "android/support/v4/view/AsyncLayoutInflater(.*)",
-            to: "androidx/asynclayoutinflater/view/AsyncLayoutInflater{0}"
+            "from": "android/support/v4/view/AsyncLayoutInflater(.*)",
+            "to": "androidx/asynclayoutinflater/view/AsyncLayoutInflater{0}"
         },
         {
-            from: "android/support/v4/widget/SwipeRefreshLayout(.*)",
-            to: "androidx/swiperefreshlayout/widget/SwipeRefreshLayout{0}"
+            "from": "android/support/v4/widget/SwipeRefreshLayout(.*)",
+            "to": "androidx/swiperefreshlayout/widget/SwipeRefreshLayout{0}"
         },
         {
-            from: "android/support/v4/widget/CircularProgressDrawable(.*)",
-            to: "androidx/swiperefreshlayout/widget/CircularProgressDrawable{0}"
+            "from": "android/support/v4/widget/CircularProgressDrawable(.*)",
+            "to": "androidx/swiperefreshlayout/widget/CircularProgressDrawable{0}"
         },
         {
-            from: "android/support/v4/widget/CircleImageView(.*)",
-            to: "androidx/swiperefreshlayout/widget/CircleImageView{0}"
+            "from": "android/support/v4/widget/CircleImageView(.*)",
+            "to": "androidx/swiperefreshlayout/widget/CircleImageView{0}"
         },
         {
-            from: "android/support/v4/util/ArrayMap(.*)",
-            to: "androidx/collection/ArrayMap{0}"
+            "from": "android/support/v4/util/ArrayMap(.*)",
+            "to": "androidx/collection/ArrayMap{0}"
         },
         {
-            from: "android/support/v4/util/ArraySet(.*)",
-            to: "androidx/collection/ArraySet{0}"
+            "from": "android/support/v4/util/ArraySet(.*)",
+            "to": "androidx/collection/ArraySet{0}"
         },
         {
-            from: "android/support/v4/util/CircularArray(.*)",
-            to: "androidx/collection/CircularArray{0}"
+            "from": "android/support/v4/util/CircularArray(.*)",
+            "to": "androidx/collection/CircularArray{0}"
         },
         {
-            from: "android/support/v4/util/CircularIntArray(.*)",
-            to: "androidx/collection/CircularIntArray{0}"
+            "from": "android/support/v4/util/CircularIntArray(.*)",
+            "to": "androidx/collection/CircularIntArray{0}"
         },
         {
-            from: "android/support/v4/util/ContainerHelpers(.*)",
-            to: "androidx/collection/ContainerHelpers{0}"
+            "from": "android/support/v4/util/ContainerHelpers(.*)",
+            "to": "androidx/collection/ContainerHelpers{0}"
         },
         {
-            from: "android/support/v4/util/LongSparseArray(.*)",
-            to: "androidx/collection/LongSparseArray{0}"
+            "from": "android/support/v4/util/LongSparseArray(.*)",
+            "to": "androidx/collection/LongSparseArray{0}"
         },
         {
-            from: "android/support/v4/util/LruCache(.*)",
-            to: "androidx/collection/LruCache{0}"
+            "from": "android/support/v4/util/LruCache(.*)",
+            "to": "androidx/collection/LruCache{0}"
         },
         {
-            from: "android/support/v4/util/MapCollections(.*)",
-            to: "androidx/collection/MapCollections{0}"
+            "from": "android/support/v4/util/MapCollections(.*)",
+            "to": "androidx/collection/MapCollections{0}"
         },
         {
-            from: "android/support/v4/util/SimpleArrayMap(.*)",
-            to: "androidx/collection/SimpleArrayMap{0}"
+            "from": "android/support/v4/util/SimpleArrayMap(.*)",
+            "to": "androidx/collection/SimpleArrayMap{0}"
         },
         {
-            from: "android/support/v4/util/SparseArrayCompat(.*)",
-            to: "androidx/collection/SparseArrayCompat{0}"
+            "from": "android/support/v4/util/SparseArrayCompat(.*)",
+            "to": "androidx/collection/SparseArrayCompat{0}"
         },
         {
-            from: "android/support/v4/provider/DocumentFile(.*)",
-            to: "androidx/documentfile/provider/DocumentFile{0}"
+            "from": "android/support/v4/provider/DocumentFile(.*)",
+            "to": "androidx/documentfile/provider/DocumentFile{0}"
         },
         {
-            from: "android/support/v4/provider/DocumentsContractApi19(.*)",
-            to: "androidx/documentfile/provider/DocumentsContractApi19{0}"
+            "from": "android/support/v4/provider/DocumentsContractApi19(.*)",
+            "to": "androidx/documentfile/provider/DocumentsContractApi19{0}"
         },
         {
-            from: "android/support/v4/provider/RawDocumentFile(.*)",
-            to: "androidx/documentfile/provider/RawDocumentFile{0}"
+            "from": "android/support/v4/provider/RawDocumentFile(.*)",
+            "to": "androidx/documentfile/provider/RawDocumentFile{0}"
         },
         {
-            from: "android/support/v4/provider/SingleDocumentFile(.*)",
-            to: "androidx/documentfile/provider/SingleDocumentFile{0}"
+            "from": "android/support/v4/provider/SingleDocumentFile(.*)",
+            "to": "androidx/documentfile/provider/SingleDocumentFile{0}"
         },
         {
-            from: "android/support/v4/provider/TreeDocumentFile(.*)",
-            to: "androidx/documentfile/provider/TreeDocumentFile{0}"
+            "from": "android/support/v4/provider/TreeDocumentFile(.*)",
+            "to": "androidx/documentfile/provider/TreeDocumentFile{0}"
         },
         {
-            from: "android/support/v4/content/LocalBroadcastManager(.*)",
-            to: "androidx/localbroadcastmanager/content/LocalBroadcastManager{0}"
+            "from": "android/support/v4/content/LocalBroadcastManager(.*)",
+            "to": "androidx/localbroadcastmanager/content/LocalBroadcastManager{0}"
         },
         {
-            from: "android/support/v4/print/(.*)",
-            to: "androidx/print/{0}"
+            "from": "android/support/v4/print/(.*)",
+            "to": "androidx/print/{0}"
         },
 
         # Catch all for v4
         {
-            from: "android/support/v4/(.*)",
-            to: "androidx/core/{0}"
+            "from": "android/support/v4/(.*)",
+            "to": "androidx/core/{0}"
         },
         {
-            from: "android/support/v13/(.*)",
-            to: "androidx/core/{0}"
+            "from": "android/support/v13/(.*)",
+            "to": "androidx/core/{0}"
         },
 
         # Design lib
         {
-            from: "android/support/design/(.*)",
-            to: "android/support/design/{0}"
+            "from": "android/support/design/(.*)",
+            "to": "android/support/design/{0}"
+        },
+
+        # Arch
+        {
+            "from": "android/arch/core/(.*)",
+            "to": "androidx/arch/core/{0}"
+        },
+        {
+            "from": "android/arch/lifecycle/(.*)",
+            "to": "androidx/lifecycle/{0}"
+        },
+        {
+            "from": "android/arch/paging/(.*)",
+            "to": "androidx/paging/{0}"
+        },
+        {
+            "from": "android/arch/persistence/room/(.*)",
+            "to": "androidx/room/{0}"
+        },
+        {
+            "from": "android/arch/persistence/(.*)",
+            "to": "androidx/sqlite/{0}"
+        },
+
+        #Binding
+        {
+            "from": "android/databinding/(.*)",
+            "to": "androidx/databinding/{0}"
         },
     ],
-    slRules: [
+    "slRules": [
         # Ignore
         {
-            from: "(.*)/package-info",
-            to: "ignore"
+            "from": "(.*)/package-info",
+            "to": "ignore"
         },
         {
-            from: "androidx/text/emoji/flatbuffer/(.*)",
-            to: "ignore"
+            "from": "androidx/text/emoji/flatbuffer/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/browser/browseractions/(.*)",
-            to: "ignore"
+            "from": "androidx/browser/browseractions/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/heifwriter/(.*)",
-            to: "ignore"
+            "from": "androidx/heifwriter/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/webkit/(.*)",
-            to: "ignore"
+            "from": "androidx/webkit/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/slice/(.*)",
-            to: "ignore"
+            "from": "androidx/slice/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/recyclerview/selection/(.*)",
-            to: "ignore"
+            "from": "androidx/recyclerview/selection/(.*)",
+            "to": "ignore"
         },
         {
-            from: "androidx/textclassifier/(.*)",
-            to: "ignore"
+            "from": "androidx/textclassifier/(.*)",
+            "to": "ignore"
         },
     ],
-    pomRules: [
+    "pomRules": [
         {
-            from: { groupId: "com.android.support", artifactId: "animated-vector-drawable", version: "28.0.0" },
-            to: [{ groupId: "androidx.vectordrawable", artifactId: "vectordrawable-animated", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "animated-vector-drawable", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.vectordrawable", "artifactId": "vectordrawable-animated", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "appcompat-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.appcompat", artifactId: "appcompat", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "appcompat-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.appcompat", "artifactId": "appcompat", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "cardview-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.cardview", artifactId: "cardview", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "cardview-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.cardview", "artifactId": "cardview", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "customtabs", version: "28.0.0" },
-            to: [{ groupId: "androidx.browser", artifactId: "browser", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "customtabs", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.browser", "artifactId": "browser", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "design", version: "28.0.0" },
-            to: [{ groupId: "com.google.android.material", artifactId: "material", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "design", "version": "28.0.0" },
+            "to": [{ "groupId": "com.google.android.material", "artifactId": "material", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "exifinterface", version: "28.0.0" },
-            to: [{ groupId: "androidx.exifinterface", artifactId: "exifinterface", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "exifinterface", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.exifinterface", "artifactId": "exifinterface", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "gridlayout-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.gridlayout", artifactId: "gridlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "gridlayout-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.gridlayout", "artifactId": "gridlayout", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "leanback-v17", version: "28.0.0" },
-            to: [{ groupId: "androidx.leanback", artifactId: "leanback", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "leanback-v17", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.leanback", "artifactId": "leanback", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "mediarouter-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.mediarouter", artifactId: "mediarouter", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "mediarouter-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.mediarouter", "artifactId": "mediarouter", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "multidex", version: "28.0.0" },
-            to: [{ groupId: "androidx.multidex", artifactId: "multidex", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "multidex", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.multidex", "artifactId": "multidex", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "multidex-instrumentation", version: "28.0.0" },
-            to: [{ groupId: "androidx.multidex", artifactId: "multidex-instrumentation", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "multidex-instrumentation", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.multidex", "artifactId": "multidex-instrumentation", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "palette-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.palette", artifactId: "palette", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "palette-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.palette", "artifactId": "palette", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "percent", version: "28.0.0" },
-            to: [{ groupId: "androidx.percentlayout", artifactId: "percentlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "percent", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.percentlayout", "artifactId": "percentlayout", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "preference-leanback-v17", version: "28.0.0" },
-            to: [{ groupId: "androidx.leanback", artifactId: "leanback-preference", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "preference-leanback-v17", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.leanback", "artifactId": "leanback-preference", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "preference-v14", version: "28.0.0" },
-            to: [{ groupId: "androidx.legacy", artifactId: "legacy-preference-v14", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "preference-v14", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.legacy", "artifactId": "legacy-preference-v14", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "preference-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.preference", artifactId: "preference", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "preference-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.preference", "artifactId": "preference", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "recommendation", version: "28.0.0" },
-            to: [{ groupId: "androidx.recommendation", artifactId: "recommendation", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "recommendation", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.recommendation", "artifactId": "recommendation", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "recyclerview-v7", version: "28.0.0" },
-            to: [{ groupId: "androidx.recyclerview", artifactId: "recyclerview", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "recyclerview-v7", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.recyclerview", "artifactId": "recyclerview", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-annotations", version: "28.0.0" },
-            to: [{ groupId: "androidx.annotation", artifactId: "annotation", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-annotations", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.annotation", "artifactId": "annotation", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-compat", version: "28.0.0" },
-            to: [{ groupId: "androidx.core", artifactId: "core", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-compat", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.core", "artifactId": "core", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-content", version: "28.0.0" },
-            to: [{ groupId: "androidx.contentpaging", artifactId: "contentpaging", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-content", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.contentpaging", "artifactId": "contentpaging", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-core-ui", version: "28.0.0" },
-            to: [{ groupId: "androidx.legacy", artifactId: "legacy-support-core-ui", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-core-ui", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.legacy", "artifactId": "legacy-support-core-ui", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-core-utils", version: "28.0.0" },
-            to: [{ groupId: "androidx.legacy", artifactId: "legacy-support-core-utils", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-core-utils", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.legacy", "artifactId": "legacy-support-core-utils", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-dynamic-animation", version: "28.0.0" },
-            to: [{ groupId: "androidx.dynamicanimation", artifactId: "dynamicanimation", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-dynamic-animation", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.dynamicanimation", "artifactId": "dynamicanimation", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-emoji", version: "28.0.0" },
-            to: [{ groupId: "androidx.emoji", artifactId: "emoji", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-emoji", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.emoji", "artifactId": "emoji", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-emoji-appcompat", version: "28.0.0" },
-            to: [{ groupId: "androidx.emoji", artifactId: "emoji-appcompat", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-emoji-appcompat", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.emoji", "artifactId": "emoji-appcompat", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-emoji-bundled", version: "28.0.0" },
-            to: [{ groupId: "androidx.emoji", artifactId: "emoji-bundled", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-emoji-bundled", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.emoji", "artifactId": "emoji-bundled", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-fragment", version: "28.0.0" },
-            to: [{ groupId: "androidx.fragment", artifactId: "fragment", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-fragment", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.fragment", "artifactId": "fragment", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-media-compat", version: "28.0.0" },
-            to: [{ groupId: "androidx.media", artifactId: "media", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-media-compat", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.media", "artifactId": "media", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-tv-provider", version: "28.0.0" },
-            to: [{ groupId: "androidx.tvprovider", artifactId: "tvprovider", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-tv-provider", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.tvprovider", "artifactId": "tvprovider", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-v13", version: "28.0.0" },
-            to: [{ groupId: "androidx.legacy", artifactId: "legacy-support-v13", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-v13", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.legacy", "artifactId": "legacy-support-v13", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-v4", version: "28.0.0" },
-            to: [{ groupId: "androidx.legacy", artifactId: "legacy-support-v4", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-v4", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.legacy", "artifactId": "legacy-support-v4", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "support-vector-drawable", version: "28.0.0" },
-            to: [{ groupId: "androidx.vectordrawable", artifactId: "vectordrawable", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "support-vector-drawable", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.vectordrawable", "artifactId": "vectordrawable", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "textclassifier", version: "28.0.0" },
-            to: [{ groupId: "androidx.textclassifier", artifactId: "textclassifier", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "textclassifier", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.textclassifier", "artifactId": "textclassifier", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "transition", version: "28.0.0" },
-            to: [{ groupId: "androidx.transition", artifactId: "transition", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "transition", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.transition", "artifactId": "transition", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "wear", version: "28.0.0" },
-            to: [{ groupId: "androidx.wear", artifactId: "wear", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "wear", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.wear", "artifactId": "wear", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "asynclayoutinflater", version: "28.0.0" },
-            to: [{ groupId: "androidx.asynclayoutinflater", artifactId: "asynclayoutinflater", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "asynclayoutinflater", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.asynclayoutinflater", "artifactId": "asynclayoutinflater", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "collections", version: "28.0.0" },
-            to: [{ groupId: "androidx.collection", artifactId: "collection", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "collections", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.collection", "artifactId": "collection", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "coordinatorlayout", version: "28.0.0" },
-            to: [{ groupId: "androidx.coordinatorlayout", artifactId: "coordinatorlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "coordinatorlayout", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.coordinatorlayout", "artifactId": "coordinatorlayout", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "cursoradapter", version: "28.0.0" },
-            to: [{ groupId: "androidx.cursoradapter", artifactId: "cursoradapter", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "cursoradapter", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.cursoradapter", "artifactId": "cursoradapter", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "customview", version: "28.0.0" },
-            to: [{ groupId: "androidx.customview", artifactId: "customview", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "customview", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.customview", "artifactId": "customview", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "documentfile", version: "28.0.0" },
-            to: [{ groupId: "androidx.documentfile", artifactId: "documentfile", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "documentfile", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.documentfile", "artifactId": "documentfile", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "drawerlayout", version: "28.0.0" },
-            to: [{ groupId: "androidx.drawerlayout", artifactId: "drawerlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "drawerlayout", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.drawerlayout", "artifactId": "drawerlayout", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "interpolator", version: "28.0.0" },
-            to: [{ groupId: "androidx.interpolator", artifactId: "interpolator", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "interpolator", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.interpolator", "artifactId": "interpolator", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "loader", version: "28.0.0" },
-            to: [{ groupId: "androidx.loader", artifactId: "loader", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "loader", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.loader", "artifactId": "loader", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "localbroadcastmanager", version: "28.0.0" },
-            to: [{ groupId: "androidx.localbroadcastmanager", artifactId: "localbroadcastmanager", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "localbroadcastmanager", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.localbroadcastmanager", "artifactId": "localbroadcastmanager", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "print", version: "28.0.0" },
-            to: [{ groupId: "androidx.print", artifactId: "print", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support", "artifactId": "print", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.print", "artifactId": "print", "version": "1.0.0" }]
+        },
+        {
+            "from": { "groupId": "com.android.support", "artifactId": "slidingpanelayout", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.slidingpanelayout", "artifactId": "slidingpanelayout", "version": "1.0.0" }]
+        },
+        {
+            "from": { "groupId": "com.android.support", "artifactId": "swiperefreshlayout", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.swiperefreshlayout", "artifactId": "swiperefreshlayout", "version": "1.0.0" }]
+        },
+        {
+            "from": { "groupId": "com.android.support", "artifactId": "viewpager", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.viewpager", "artifactId": "viewpager", "version": "1.0.0" }]
+        },
+        {
+            "from": { "groupId": "com.android.databinding", "artifactId": "adapters", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.databinding", "artifactId": "databinding-adapters", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "slidingpanelayout", version: "28.0.0" },
-            to: [{ groupId: "androidx.slidingpanelayout", artifactId: "slidingpanelayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.databinding", "artifactId": "baseLibrary", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.databinding", "artifactId": "databinding-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "swiperefreshlayout", version: "28.0.0" },
-            to: [{ groupId: "androidx.swiperefreshlayout", artifactId: "swiperefreshlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.databinding", "artifactId": "compiler", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.databinding", "artifactId": "databinding-compiler", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support", artifactId: "viewpager", version: "28.0.0" },
-            to: [{ groupId: "androidx.viewpager", artifactId: "viewpager", version: "1.0.0" }]
+            "from": { "groupId": "com.android.databinding", "artifactId": "compilerCommon", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.databinding", "artifactId": "databinding-compiler-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.databinding", artifactId: "adapters", version: "28.0.0" },
-            to: [{ groupId: "androidx.databinding", artifactId: "databinding-adapters", version: "1.0.0" }]
+            "from": { "groupId": "com.android.databinding", "artifactId": "library", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.databinding", "artifactId": "databinding-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.databinding", artifactId: "baseLibrary", version: "28.0.0" },
-            to: [{ groupId: "androidx.databinding", artifactId: "databinding-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.background.workmanager", "artifactId": "workmanager", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.work", "artifactId": "runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.databinding", artifactId: "compiler", version: "28.0.0" },
-            to: [{ groupId: "androidx.databinding", artifactId: "databinding-compiler", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.background.workmanager", "artifactId": "workmanager-firebase", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.work", "artifactId": "runtime-firebase", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.databinding", artifactId: "compilerCommon", version: "28.0.0" },
-            to: [{ groupId: "androidx.databinding", artifactId: "databinding-compiler-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.navigation", "artifactId": "runtime", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.navigation", "artifactId": "navigation-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.databinding", artifactId: "library", version: "28.0.0" },
-            to: [{ groupId: "androidx.databinding", artifactId: "databinding-runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.navigation", "artifactId": "fragment", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.navigation", "artifactId": "navigation-fragment", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.background.workmanager", artifactId: "workmanager", version: "28.0.0" },
-            to: [{ groupId: "androidx.work", artifactId: "runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.core", "artifactId": "common", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.arch.core", "artifactId": "core-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.background.workmanager", artifactId: "workmanager-firebase", version: "28.0.0" },
-            to: [{ groupId: "androidx.work", artifactId: "runtime-firebase", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.core", "artifactId": "core", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.arch.core", "artifactId": "core", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.navigation", artifactId: "runtime", version: "28.0.0" },
-            to: [{ groupId: "androidx.navigation", artifactId: "navigation-runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.core", "artifactId": "core-testing", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.arch.core", "artifactId": "core-testing", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.navigation", artifactId: "fragment", version: "28.0.0" },
-            to: [{ groupId: "androidx.navigation", artifactId: "navigation-fragment", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.core", "artifactId": "runtime", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.arch.core", "artifactId": "core-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.core", artifactId: "common", version: "28.0.0" },
-            to: [{ groupId: "androidx.arch.core", artifactId: "core-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "common", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.core", artifactId: "core", version: "28.0.0" },
-            to: [{ groupId: "androidx.arch.core", artifactId: "core", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "common-java8", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-common-java8", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.core", artifactId: "core-testing", version: "28.0.0" },
-            to: [{ groupId: "androidx.arch.core", artifactId: "core-testing", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "compiler", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-compiler", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.core", artifactId: "runtime", version: "28.0.0" },
-            to: [{ groupId: "androidx.arch.core", artifactId: "core-runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "extensions", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-extensions", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.lifecycle", artifactId: "common", version: "28.0.0" },
-            to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "reactivestreams", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-reactivestreams", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.lifecycle", artifactId: "common-java8", version: "28.0.0" },
-            to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-common-java8", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "runtime", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.lifecycle", artifactId: "compiler", version: "28.0.0" },
-            to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-compiler", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "viewmodel", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-viewmodel", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.lifecycle", artifactId: "extensions", version: "28.0.0" },
-            to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-extensions", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "livedata", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-livedata", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.lifecycle", artifactId: "reactivestreams", version: "28.0.0" },
-            to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-reactivestreams", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.lifecycle", "artifactId": "livedata-core", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.lifecycle", "artifactId": "lifecycle-livedata-core", "version": "1.0.0" }]
         },
-        #{
-        #    from: { groupId: "android.arch.lifecycle", artifactId: "runtime", version: "28.0.0" },
-        #    to: [{ groupId: "androidx.lifecycle", artifactId: "lifecycle-runtime", version: "1.0.0" }]
-        #},
         {
-            from: { groupId: "android.arch.paging", artifactId: "common", version: "28.0.0" },
-            to: [{ groupId: "androidx.paging", artifactId: "paging-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.paging", "artifactId": "common", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.paging", "artifactId": "paging-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.paging", artifactId: "runtime", version: "28.0.0" },
-            to: [{ groupId: "androidx.paging", artifactId: "paging-runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.paging", "artifactId": "runtime", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.paging", "artifactId": "paging-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence", artifactId: "db", version: "28.0.0" },
-            to: [{ groupId: "androidx.sqlite", artifactId: "sqlite", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence", "artifactId": "db", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.sqlite", "artifactId": "sqlite", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence", artifactId: "db-framework", version: "28.0.0" },
-            to: [{ groupId: "androidx.sqlite", artifactId: "sqlite-framework", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence", "artifactId": "db-framework", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.sqlite", "artifactId": "sqlite-framework", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "common", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-common", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "common", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-common", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "compiler", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-compiler", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "compiler", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-compiler", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "migration", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-migration", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "migration", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-migration", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "runtime", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-runtime", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "runtime", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-runtime", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "rxjava2", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-rxjava2", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "rxjava2", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-rxjava2", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "testing", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-testing", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "testing", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-testing", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "android.arch.persistence.room", artifactId: "guava", version: "28.0.0" },
-            to: [{ groupId: "androidx.room", artifactId: "room-guava", version: "1.0.0" }]
+            "from": { "groupId": "android.arch.persistence.room", "artifactId": "guava", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.room", "artifactId": "room-guava", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.constraint", artifactId: "constraint-layout", version: "28.0.0" },
-            to: [{ groupId: "androidx.constraintlayout", artifactId: "constraintlayout", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.constraint", "artifactId": "constraint-layout", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.constraintlayout", "artifactId": "constraintlayout", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.constraint", artifactId: "constraint-layout-solver", version: "28.0.0" },
-            to: [{ groupId: "androidx.constraintlayout", artifactId: "constraintlayout-solver", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.constraint", "artifactId": "constraint-layout-solver", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.constraintlayout", "artifactId": "constraintlayout-solver", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test", artifactId: "exposed-instrumentation-api-publish", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test-exposed-instrumentation-api-publish", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test", "artifactId": "exposed-instrumentation-api-publish", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test-exposed-instrumentation-api-publish", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test", artifactId: "orchestrator", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test-orchestrator", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test", "artifactId": "orchestrator", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test-orchestrator", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test", artifactId: "rules", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test-rules", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test", "artifactId": "rules", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test-rules", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test", artifactId: "runner", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test-runner", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test", "artifactId": "runner", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test-runner", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test", artifactId: "testing-support-lib", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test", "artifactId": "testing-support-lib", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-accessibility", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-accessibility", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-accessibility", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-accessibility", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-contrib", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-contrib", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-contrib", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-contrib", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-core", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-core", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-core", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-core", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-idling-resource", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-idling-resource", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-idling-resource", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-idling-resource", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-intents", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-intents", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-intents", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-intents", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso", artifactId: "espresso-web", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso", artifactId: "espresso-web", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso", "artifactId": "espresso-web", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso", "artifactId": "espresso-web", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso.idling", artifactId: "idling-concurrent", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso.idling", artifactId: "idling-concurrent", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso.idling", "artifactId": "idling-concurrent", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso.idling", "artifactId": "idling-concurrent", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.espresso.idling", artifactId: "idling-net", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.espresso.idling", artifactId: "idling-net", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.espresso.idling", "artifactId": "idling-net", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.espresso.idling", "artifactId": "idling-net", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.janktesthelper", artifactId: "janktesthelper-v23", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.jank", artifactId: "jank", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.janktesthelper", "artifactId": "janktesthelper-v23", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.jank", "artifactId": "jank", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.services", artifactId: "test-services", version: "28.0.0" },
-            to: [{ groupId: "androidx.test", artifactId: "test-services", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.services", "artifactId": "test-services", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test", "artifactId": "test-services", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "com.android.support.test.uiautomator", artifactId: "uiautomator-v18", version: "28.0.0" },
-            to: [{ groupId: "androidx.test.uiautomator", artifactId: "uiautomator", version: "1.0.0" }]
+            "from": { "groupId": "com.android.support.test.uiautomator", "artifactId": "uiautomator-v18", "version": "28.0.0" },
+            "to": [{ "groupId": "androidx.test.uiautomator", "artifactId": "uiautomator", "version": "1.0.0" }]
         },
         # Keep it same
         {
-            from: { groupId: "androidx.slice", artifactId: "slices-core", version: "1.0.0" },
-            to: [{ groupId: "androidx.slice", artifactId: "slices-core", version: "1.0.0" }]
+            "from": { "groupId": "androidx.slice", "artifactId": "slices-core", "version": "1.0.0" },
+            "to": [{ "groupId": "androidx.slice", "artifactId": "slices-core", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "androidx.slice", artifactId: "slices-builders", version: "1.0.0" },
-            to: [{ groupId: "androidx.slice", artifactId: "slices-builders", version: "1.0.0" }]
+            "from": { "groupId": "androidx.slice", "artifactId": "slices-builders", "version": "1.0.0" },
+            "to": [{ "groupId": "androidx.slice", "artifactId": "slices-builders", "version": "1.0.0" }]
         },
         {
-            from: { groupId: "androidx.slice", artifactId: "slices-view", version: "1.0.0" },
-            to: [{ groupId: "androidx.slice", artifactId: "slices-view", version: "1.0.0" }]
-        },
-        # Temporary
-        {
-            from: { groupId: "android.arch.lifecycle", artifactId: "runtime", version: "1.1.0" },
-            to: [{ groupId: "androidx.temp.arch.lifecycle", artifactId: "runtime", version: "2.0.0" }]
-        },
-        {
-            from: { groupId: "android.arch.lifecycle", artifactId: "livedata-core", version: "1.1.0" },
-            to: [{ groupId: "androidx.temp.arch.lifecycle", artifactId: "livedata-core", version: "2.0.0" }]
-        },
-        {
-            from: { groupId: "android.arch.lifecycle", artifactId: "viewmodel", version: "1.1.0" },
-            to: [{ groupId: "androidx.temp.arch.lifecycle", artifactId: "viewmodel", version: "2.0.0" }]
+            "from": { "groupId": "androidx.slice", "artifactId": "slices-view", "version": "1.0.0" },
+            "to": [{ "groupId": "androidx.slice", "artifactId": "slices-view", "version": "1.0.0" }]
         }
     ],
-    map: {
+    "map": {
         # Types added in 28.0.0 (missing in 27.1.0)
-        types: {
+        "types": {
         }
     },
-    proGuardMap: {
-        rules: {
+    "proGuardMap": {
+        "rules": {
             "android/support/transition/ChangeBounds$*": "androidx/transition/ChangeBounds$*",
-            "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat$*"
+            "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat$*",
+            "android/arch/persistence/room/paging/**": "androidx/room/paging/**"
         }
     }
 }
diff --git a/jetifier/jetifier/core/src/main/resources/default.generated.config b/jetifier/jetifier/core/src/main/resources/default.generated.config
index 2fd93ad..ca86505 100644
--- a/jetifier/jetifier/core/src/main/resources/default.generated.config
+++ b/jetifier/jetifier/core/src/main/resources/default.generated.config
@@ -19,7 +19,8 @@
 {
   "restrictToPackagePrefixes": [
     "android/support/",
-    "androix/temp"
+    "android/arch/",
+    "android/databinding/"
   ],
   "rules": [
     {
@@ -411,10 +412,6 @@
       "to": "androidx/media/AudioAttributesCompat{0}"
     },
     {
-      "from": "android/support/v4/media/MediaBrowserCompat(.*)",
-      "to": "androidx/media/MediaBrowserCompat{0}"
-    },
-    {
       "from": "android/support/v4/media/MediaBrowserCompatUtils(.*)",
       "to": "androidx/media/MediaBrowserCompatUtils{0}"
     },
@@ -435,10 +432,6 @@
       "to": "androidx/media/session/MediaButtonReceiver{0}"
     },
     {
-      "from": "android/support/v4/media/session/MediaControllerCompat(.*)",
-      "to": "androidx/media/session/MediaControllerCompat{0}"
-    },
-    {
       "from": "android/support/v4/media/(.*)",
       "to": "android/support/v4/media/{0}"
     },
@@ -629,6 +622,30 @@
     {
       "from": "android/support/design/(.*)",
       "to": "android/support/design/{0}"
+    },
+    {
+      "from": "android/arch/core/(.*)",
+      "to": "androidx/arch/core/{0}"
+    },
+    {
+      "from": "android/arch/lifecycle/(.*)",
+      "to": "androidx/lifecycle/{0}"
+    },
+    {
+      "from": "android/arch/paging/(.*)",
+      "to": "androidx/paging/{0}"
+    },
+    {
+      "from": "android/arch/persistence/room/(.*)",
+      "to": "androidx/room/{0}"
+    },
+    {
+      "from": "android/arch/persistence/(.*)",
+      "to": "androidx/sqlite/{0}"
+    },
+    {
+      "from": "android/databinding/(.*)",
+      "to": "androidx/databinding/{0}"
     }
   ],
   "slRules": [
@@ -1620,6 +1637,62 @@
     },
     {
       "from": {
+        "groupId": "android.arch.lifecycle",
+        "artifactId": "runtime",
+        "version": "28.0.0"
+      },
+      "to": [
+        {
+          "groupId": "androidx.lifecycle",
+          "artifactId": "lifecycle-runtime",
+          "version": "1.0.0"
+        }
+      ]
+    },
+    {
+      "from": {
+        "groupId": "android.arch.lifecycle",
+        "artifactId": "viewmodel",
+        "version": "28.0.0"
+      },
+      "to": [
+        {
+          "groupId": "androidx.lifecycle",
+          "artifactId": "lifecycle-viewmodel",
+          "version": "1.0.0"
+        }
+      ]
+    },
+    {
+      "from": {
+        "groupId": "android.arch.lifecycle",
+        "artifactId": "livedata",
+        "version": "28.0.0"
+      },
+      "to": [
+        {
+          "groupId": "androidx.lifecycle",
+          "artifactId": "lifecycle-livedata",
+          "version": "1.0.0"
+        }
+      ]
+    },
+    {
+      "from": {
+        "groupId": "android.arch.lifecycle",
+        "artifactId": "livedata-core",
+        "version": "28.0.0"
+      },
+      "to": [
+        {
+          "groupId": "androidx.lifecycle",
+          "artifactId": "lifecycle-livedata-core",
+          "version": "1.0.0"
+        }
+      ]
+    },
+    {
+      "from": {
         "groupId": "android.arch.paging",
         "artifactId": "common",
         "version": "28.0.0"
@@ -2065,48 +2138,6 @@
           "version": "1.0.0"
         }
       ]
-    },
-    {
-      "from": {
-        "groupId": "android.arch.lifecycle",
-        "artifactId": "runtime",
-        "version": "1.1.0"
-      },
-      "to": [
-        {
-          "groupId": "androidx.temp.arch.lifecycle",
-          "artifactId": "runtime",
-          "version": "2.0.0"
-        }
-      ]
-    },
-    {
-      "from": {
-        "groupId": "android.arch.lifecycle",
-        "artifactId": "livedata-core",
-        "version": "1.1.0"
-      },
-      "to": [
-        {
-          "groupId": "androidx.temp.arch.lifecycle",
-          "artifactId": "livedata-core",
-          "version": "2.0.0"
-        }
-      ]
-    },
-    {
-      "from": {
-        "groupId": "android.arch.lifecycle",
-        "artifactId": "viewmodel",
-        "version": "1.1.0"
-      },
-      "to": [
-        {
-          "groupId": "androidx.temp.arch.lifecycle",
-          "artifactId": "viewmodel",
-          "version": "2.0.0"
-        }
-      ]
     }
   ],
   "map": {
@@ -2119,22 +2150,61 @@
       "android/support/annotation/ColorInt": "androidx/annotation/ColorInt",
       "android/support/v7/widget/RecyclerView": "androidx/recyclerview/widget/RecyclerView",
       "android/support/v7/widget/LinearLayoutManager": "androidx/recyclerview/widget/LinearLayoutManager",
+      "android/arch/lifecycle/LiveData": "androidx/lifecycle/LiveData",
+      "android/arch/lifecycle/Observer": "androidx/lifecycle/Observer",
       "android/support/annotation/AttrRes": "androidx/annotation/AttrRes",
+      "android/databinding/BindingAdapter": "androidx/databinding/BindingAdapter",
+      "android/databinding/BindingMethod": "androidx/databinding/BindingMethod",
+      "android/databinding/ObservableMap": "androidx/databinding/ObservableMap",
+      "android/databinding/BindingBuildInfo": "androidx/databinding/BindingBuildInfo",
+      "android/databinding/Observable": "androidx/databinding/Observable",
+      "android/databinding/Untaggable": "androidx/databinding/Untaggable",
+      "android/databinding/InverseBindingMethod": "androidx/databinding/InverseBindingMethod",
+      "android/databinding/CallbackRegistry": "androidx/databinding/CallbackRegistry",
+      "android/databinding/BindingMethods": "androidx/databinding/BindingMethods",
+      "android/databinding/InverseBindingListener": "androidx/databinding/InverseBindingListener",
+      "android/databinding/BindingConversion": "androidx/databinding/BindingConversion",
+      "android/databinding/ObservableList": "androidx/databinding/ObservableList",
+      "android/databinding/InverseBindingMethods": "androidx/databinding/InverseBindingMethods",
+      "android/databinding/InverseMethod": "androidx/databinding/InverseMethod",
+      "android/databinding/Bindable": "androidx/databinding/Bindable",
+      "android/databinding/InverseBindingAdapter": "androidx/databinding/InverseBindingAdapter",
       "android/support/design/drawable/DrawableUtils": "android/support/design/drawable/DrawableUtils",
       "android/support/app/recommendation/ContentRecommendation": "androidx/recommendation/app/ContentRecommendation",
       "android/support/annotation/DrawableRes": "androidx/annotation/DrawableRes",
       "android/support/app/recommendation/RecommendationExtender": "androidx/recommendation/app/RecommendationExtender",
+      "android/arch/lifecycle/ErrorMessages": "androidx/lifecycle/ErrorMessages",
+      "android/arch/lifecycle/model/EventMethod": "androidx/lifecycle/model/EventMethod",
+      "android/arch/lifecycle/Elements_extKt": "androidx/lifecycle/Elements_extKt",
+      "android/arch/lifecycle/WriterKt": "androidx/lifecycle/WriterKt",
+      "android/arch/lifecycle/ObserversCollector": "androidx/lifecycle/ObserversCollector",
+      "android/arch/lifecycle/Validator": "androidx/lifecycle/Validator",
+      "android/arch/lifecycle/model/LifecycleObserverInfo": "androidx/lifecycle/model/LifecycleObserverInfo",
+      "android/arch/lifecycle/model/AdapterClassKt": "androidx/lifecycle/model/AdapterClassKt",
+      "android/arch/lifecycle/OnLifecycleEvent": "androidx/lifecycle/OnLifecycleEvent",
+      "android/arch/lifecycle/Lifecycle": "androidx/lifecycle/Lifecycle",
+      "android/arch/lifecycle/LifecycleObserver": "androidx/lifecycle/LifecycleObserver",
+      "android/arch/lifecycle/model/EventMethodCall": "androidx/lifecycle/model/EventMethodCall",
+      "android/arch/lifecycle/model/AdapterClass": "androidx/lifecycle/model/AdapterClass",
+      "android/arch/lifecycle/model/InputModel": "androidx/lifecycle/model/InputModel",
+      "android/arch/lifecycle/Lifecycling": "androidx/lifecycle/Lifecycling",
+      "android/arch/lifecycle/LifecycleProcessor": "androidx/lifecycle/LifecycleProcessor",
+      "android/arch/lifecycle/Input_collectorKt": "androidx/lifecycle/Input_collectorKt",
+      "android/arch/lifecycle/TransformationKt": "androidx/lifecycle/TransformationKt",
+      "android/arch/lifecycle/GeneratedAdapter": "androidx/lifecycle/GeneratedAdapter",
+      "android/arch/lifecycle/LifecycleOwner": "androidx/lifecycle/LifecycleOwner",
+      "android/arch/lifecycle/MethodCallsLogger": "androidx/lifecycle/MethodCallsLogger",
       "android/support/v4/media/AudioAttributesCompat": "androidx/media/AudioAttributesCompat",
       "android/support/v4/media/AudioAttributesCompatApi21": "androidx/media/AudioAttributesCompatApi21",
-      "android/support/v4/media/MediaBrowserCompat": "androidx/media/MediaBrowserCompat",
+      "android/support/v4/media/MediaBrowserCompat": "android/support/v4/media/MediaBrowserCompat",
       "android/support/v4/media/session/MediaSessionCompat": "android/support/v4/media/session/MediaSessionCompat",
-      "android/support/v4/media/MediaBrowserCompatApi21": "androidx/media/MediaBrowserCompatApi21",
+      "android/support/v4/media/MediaBrowserCompatApi21": "android/support/v4/media/MediaBrowserCompatApi21",
       "android/support/v4/os/ResultReceiver": "androidx/core/os/ResultReceiver",
-      "android/support/v4/media/MediaBrowserCompatApi23": "androidx/media/MediaBrowserCompatApi23",
+      "android/support/v4/media/MediaBrowserCompatApi23": "android/support/v4/media/MediaBrowserCompatApi23",
       "android/support/v4/media/session/IMediaSession": "android/support/v4/media/session/IMediaSession",
       "android/support/v4/util/ArrayMap": "androidx/collection/ArrayMap",
       "android/support/v4/app/BundleCompat": "androidx/core/app/BundleCompat",
-      "android/support/v4/media/MediaBrowserCompatApi26": "androidx/media/MediaBrowserCompatApi26",
+      "android/support/v4/media/MediaBrowserCompatApi26": "android/support/v4/media/MediaBrowserCompatApi26",
       "android/support/v4/media/MediaDescriptionCompat": "android/support/v4/media/MediaDescriptionCompat",
       "android/support/v4/media/MediaBrowserCompatUtils": "androidx/media/MediaBrowserCompatUtils",
       "android/support/v4/media/MediaBrowserProtocol": "androidx/media/MediaBrowserProtocol",
@@ -2159,11 +2229,11 @@
       "android/support/v4/media/session/PlaybackStateCompat": "android/support/v4/media/session/PlaybackStateCompat",
       "android/support/v4/media/session/ParcelableVolumeInfo": "android/support/v4/media/session/ParcelableVolumeInfo",
       "android/support/v4/media/session/MediaButtonReceiver": "androidx/media/session/MediaButtonReceiver",
-      "android/support/v4/media/session/MediaControllerCompat": "androidx/media/session/MediaControllerCompat",
-      "android/support/v4/media/session/MediaControllerCompatApi21": "androidx/media/session/MediaControllerCompatApi21",
+      "android/support/v4/media/session/MediaControllerCompat": "android/support/v4/media/session/MediaControllerCompat",
+      "android/support/v4/media/session/MediaControllerCompatApi21": "android/support/v4/media/session/MediaControllerCompatApi21",
       "android/support/v4/app/SupportActivity": "androidx/core/app/SupportActivity",
-      "android/support/v4/media/session/MediaControllerCompatApi23": "androidx/media/session/MediaControllerCompatApi23",
-      "android/support/v4/media/session/MediaControllerCompatApi24": "androidx/media/session/MediaControllerCompatApi24",
+      "android/support/v4/media/session/MediaControllerCompatApi23": "android/support/v4/media/session/MediaControllerCompatApi23",
+      "android/support/v4/media/session/MediaControllerCompatApi24": "android/support/v4/media/session/MediaControllerCompatApi24",
       "android/support/v4/media/session/MediaSessionCompatApi21": "android/support/v4/media/session/MediaSessionCompatApi21",
       "android/support/v4/media/session/MediaSessionCompatApi23": "android/support/v4/media/session/MediaSessionCompatApi23",
       "android/support/v4/media/session/MediaSessionCompatApi24": "android/support/v4/media/session/MediaSessionCompatApi24",
@@ -2241,6 +2311,8 @@
       "android/support/design/resources/TextAppearance": "android/support/design/resources/TextAppearance",
       "android/support/design/resources/R": "android/support/design/resources/R",
       "android/support/v4/content/res/ResourcesCompat": "androidx/core/content/res/ResourcesCompat",
+      "android/arch/lifecycle/DefaultLifecycleObserver": "androidx/lifecycle/DefaultLifecycleObserver",
+      "android/arch/lifecycle/FullLifecycleObserver": "androidx/lifecycle/FullLifecycleObserver",
       "android/support/v7/widget/CardView": "androidx/cardview/widget/CardView",
       "android/support/v7/widget/CardViewDelegate": "androidx/cardview/widget/CardViewDelegate",
       "android/support/v7/cardview/R": "androidx/cardview/R",
@@ -2250,6 +2322,34 @@
       "android/support/v7/widget/CardViewBaseImpl": "androidx/cardview/widget/CardViewBaseImpl",
       "android/support/v7/widget/RoundRectDrawableWithShadow": "androidx/cardview/widget/RoundRectDrawableWithShadow",
       "android/support/v7/widget/RoundRectDrawable": "androidx/cardview/widget/RoundRectDrawable",
+      "android/arch/persistence/room/DatabaseConfiguration": "androidx/room/DatabaseConfiguration",
+      "android/arch/persistence/db/SupportSQLiteOpenHelper": "androidx/sqlite/db/SupportSQLiteOpenHelper",
+      "android/arch/persistence/room/RoomDatabase": "androidx/room/RoomDatabase",
+      "android/arch/persistence/room/EntityDeletionOrUpdateAdapter": "androidx/room/EntityDeletionOrUpdateAdapter",
+      "android/arch/persistence/room/SharedSQLiteStatement": "androidx/room/SharedSQLiteStatement",
+      "android/arch/persistence/db/SupportSQLiteStatement": "androidx/sqlite/db/SupportSQLiteStatement",
+      "android/arch/persistence/room/EntityInsertionAdapter": "androidx/room/EntityInsertionAdapter",
+      "android/arch/persistence/room/InvalidationTracker": "androidx/room/InvalidationTracker",
+      "android/arch/persistence/db/SupportSQLiteDatabase": "androidx/sqlite/db/SupportSQLiteDatabase",
+      "android/arch/core/internal/SafeIterableMap": "androidx/arch/core/internal/SafeIterableMap",
+      "android/support/v4/util/ArraySet": "androidx/collection/ArraySet",
+      "android/arch/core/executor/ArchTaskExecutor": "androidx/arch/core/executor/ArchTaskExecutor",
+      "android/arch/persistence/room/Room": "androidx/room/Room",
+      "android/arch/persistence/room/migration/Migration": "androidx/room/migration/Migration",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelperFactory": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelperFactory",
+      "android/support/v4/app/ActivityManagerCompat": "androidx/core/app/ActivityManagerCompat",
+      "android/support/v4/util/SparseArrayCompat": "androidx/collection/SparseArrayCompat",
+      "android/arch/persistence/db/SimpleSQLiteQuery": "androidx/sqlite/db/SimpleSQLiteQuery",
+      "android/arch/persistence/db/SupportSQLiteQuery": "androidx/sqlite/db/SupportSQLiteQuery",
+      "android/arch/persistence/room/RoomOpenHelper": "androidx/room/RoomOpenHelper",
+      "android/arch/persistence/room/RoomMasterTable": "androidx/room/RoomMasterTable",
+      "android/arch/persistence/room/RoomSQLiteQuery": "androidx/room/RoomSQLiteQuery",
+      "android/arch/persistence/db/SupportSQLiteProgram": "androidx/sqlite/db/SupportSQLiteProgram",
+      "android/arch/persistence/room/paging/LimitOffsetDataSource": "androidx/room/paging/LimitOffsetDataSource",
+      "android/arch/paging/PositionalDataSource": "androidx/paging/PositionalDataSource",
+      "android/arch/persistence/room/util/StringUtil": "androidx/room/util/StringUtil",
+      "android/arch/persistence/room/util/TableInfo": "androidx/room/util/TableInfo",
+      "android/arch/persistence/room/ColumnInfo": "androidx/room/ColumnInfo",
       "android/support/text/emoji/bundled/BundledEmojiCompatConfig": "androidx/emoji/bundled/BundledEmojiCompatConfig",
       "android/support/text/emoji/EmojiCompat": "androidx/emoji/text/EmojiCompat",
       "android/support/v4/util/Preconditions": "androidx/core/util/Preconditions",
@@ -2257,6 +2357,8 @@
       "android/support/v7/graphics/ColorCutQuantizer": "androidx/palette/graphics/ColorCutQuantizer",
       "android/support/v7/graphics/Palette": "androidx/palette/graphics/Palette",
       "android/support/v7/graphics/Target": "androidx/palette/graphics/Target",
+      "android/arch/persistence/room/EmptyResultSetException": "androidx/room/EmptyResultSetException",
+      "android/arch/persistence/room/RxRoom": "androidx/room/RxRoom",
       "android/support/v4/app/ActionBarDrawerToggle": "androidx/legacy/app/ActionBarDrawerToggle",
       "android/support/v4/widget/Space": "androidx/legacy/widget/Space",
       "android/support/animation/AnimationHandler": "androidx/dynamicanimation/animation/AnimationHandler",
@@ -2267,6 +2369,12 @@
       "android/support/animation/Force": "androidx/dynamicanimation/animation/Force",
       "android/support/animation/SpringAnimation": "androidx/dynamicanimation/animation/SpringAnimation",
       "android/support/animation/SpringForce": "androidx/dynamicanimation/animation/SpringForce",
+      "android/arch/persistence/db/framework/FrameworkSQLiteDatabase": "androidx/sqlite/db/framework/FrameworkSQLiteDatabase",
+      "android/arch/persistence/db/framework/FrameworkSQLiteProgram": "androidx/sqlite/db/framework/FrameworkSQLiteProgram",
+      "android/arch/persistence/db/framework/FrameworkSQLiteStatement": "androidx/sqlite/db/framework/FrameworkSQLiteStatement",
+      "android/arch/persistence/db/framework/FrameworkSQLiteOpenHelper": "androidx/sqlite/db/framework/FrameworkSQLiteOpenHelper",
+      "android/arch/persistence/room/guava/GuavaRoom": "androidx/room/guava/GuavaRoom",
+      "android/arch/lifecycle/LiveDataReactiveStreams": "androidx/lifecycle/LiveDataReactiveStreams",
       "android/support/v4/widget/CircleImageView": "androidx/swiperefreshlayout/widget/CircleImageView",
       "android/support/v4/widget/CircularProgressDrawable": "androidx/swiperefreshlayout/widget/CircularProgressDrawable",
       "android/support/v4/view/animation/FastOutSlowInInterpolator": "androidx/interpolator/view/animation/FastOutSlowInInterpolator",
@@ -2283,6 +2391,19 @@
       "android/support/design/widget/FloatingActionButton": "android/support/design/widget/FloatingActionButton",
       "android/support/v7/widget/Toolbar": "androidx/appcompat/widget/Toolbar",
       "android/support/design/bottomappbar/R": "android/support/design/bottomappbar/R",
+      "android/arch/paging/AsyncPagedListDiffer": "androidx/paging/AsyncPagedListDiffer",
+      "android/arch/paging/PagedList": "androidx/paging/PagedList",
+      "android/support/v7/util/ListUpdateCallback": "androidx/recyclerview/widget/ListUpdateCallback",
+      "android/support/v7/util/DiffUtil": "androidx/recyclerview/widget/DiffUtil",
+      "android/arch/paging/PagedStorage": "androidx/paging/PagedStorage",
+      "android/support/v7/recyclerview/extensions/AsyncDifferConfig": "androidx/recyclerview/widget/AsyncDifferConfig",
+      "android/arch/paging/PagedStorageDiffHelper": "androidx/paging/PagedStorageDiffHelper",
+      "android/support/v7/util/AdapterListUpdateCallback": "androidx/recyclerview/widget/AdapterListUpdateCallback",
+      "android/arch/paging/LivePagedListBuilder": "androidx/paging/LivePagedListBuilder",
+      "android/arch/paging/DataSource": "androidx/paging/DataSource",
+      "android/arch/lifecycle/ComputableLiveData": "androidx/lifecycle/ComputableLiveData",
+      "android/arch/paging/LivePagedListProvider": "androidx/paging/LivePagedListProvider",
+      "android/arch/paging/PagedListAdapter": "androidx/paging/PagedListAdapter",
       "android/support/design/chip/Chip": "android/support/design/chip/Chip",
       "android/support/design/chip/ChipDrawable": "android/support/design/chip/ChipDrawable",
       "android/support/v4/widget/ExploreByTouchHelper": "androidx/customview/widget/ExploreByTouchHelper",
@@ -2294,9 +2415,13 @@
       "android/support/design/chip/ChipGroup": "android/support/design/chip/ChipGroup",
       "android/support/v4/app/LoaderManager": "androidx/loader/app/LoaderManager",
       "android/support/v4/content/Loader": "androidx/loader/content/Loader",
+      "android/arch/lifecycle/ViewModelStoreOwner": "androidx/lifecycle/ViewModelStoreOwner",
       "android/support/v4/app/LoaderManagerImpl": "androidx/loader/app/LoaderManagerImpl",
+      "android/arch/lifecycle/ViewModelStore": "androidx/lifecycle/ViewModelStore",
+      "android/arch/lifecycle/MutableLiveData": "androidx/lifecycle/MutableLiveData",
       "android/support/v4/util/DebugUtils": "androidx/core/util/DebugUtils",
-      "android/support/v4/util/SparseArrayCompat": "androidx/collection/SparseArrayCompat",
+      "android/arch/lifecycle/ViewModelProvider": "androidx/lifecycle/ViewModelProvider",
+      "android/arch/lifecycle/ViewModel": "androidx/lifecycle/ViewModel",
       "android/support/v4/content/AsyncTaskLoader": "androidx/loader/content/AsyncTaskLoader",
       "android/support/v4/content/ModernAsyncTask": "androidx/loader/content/ModernAsyncTask",
       "android/support/v4/os/OperationCanceledException": "androidx/core/os/OperationCanceledException",
@@ -2304,6 +2429,16 @@
       "android/support/v4/content/CursorLoader": "androidx/loader/content/CursorLoader",
       "android/support/v4/os/CancellationSignal": "androidx/core/os/CancellationSignal",
       "android/support/v4/content/ContentResolverCompat": "androidx/core/content/ContentResolverCompat",
+      "android/arch/persistence/room/migration/bundle/DatabaseBundle": "androidx/room/migration/bundle/DatabaseBundle",
+      "android/arch/persistence/room/migration/bundle/SchemaEquality": "androidx/room/migration/bundle/SchemaEquality",
+      "android/arch/persistence/room/migration/bundle/EntityBundle": "androidx/room/migration/bundle/EntityBundle",
+      "android/arch/persistence/room/migration/bundle/SchemaEqualityUtil": "androidx/room/migration/bundle/SchemaEqualityUtil",
+      "android/arch/persistence/room/migration/bundle/FieldBundle": "androidx/room/migration/bundle/FieldBundle",
+      "android/arch/persistence/room/migration/bundle/IndexBundle": "androidx/room/migration/bundle/IndexBundle",
+      "android/arch/persistence/room/migration/bundle/BundleUtil": "androidx/room/migration/bundle/BundleUtil",
+      "android/arch/persistence/room/migration/bundle/PrimaryKeyBundle": "androidx/room/migration/bundle/PrimaryKeyBundle",
+      "android/arch/persistence/room/migration/bundle/ForeignKeyBundle": "androidx/room/migration/bundle/ForeignKeyBundle",
+      "android/arch/persistence/room/migration/bundle/SchemaBundle": "androidx/room/migration/bundle/SchemaBundle",
       "android/support/design/widget/AppBarLayout": "android/support/design/widget/AppBarLayout",
       "android/support/v4/view/OnApplyWindowInsetsListener": "androidx/core/view/OnApplyWindowInsetsListener",
       "android/support/v4/view/WindowInsetsCompat": "androidx/core/view/WindowInsetsCompat",
@@ -2390,9 +2525,55 @@
       "android/support/v4/view/animation/FastOutLinearInInterpolator": "androidx/interpolator/view/animation/FastOutLinearInInterpolator",
       "android/support/v4/view/animation/LookupTableInterpolator": "androidx/interpolator/view/animation/LookupTableInterpolator",
       "android/support/v4/view/animation/LinearOutSlowInInterpolator": "androidx/interpolator/view/animation/LinearOutSlowInInterpolator",
+      "android/arch/lifecycle/MediatorLiveData": "androidx/lifecycle/MediatorLiveData",
+      "android/arch/lifecycle/Transformations": "androidx/lifecycle/Transformations",
+      "android/arch/core/util/Function": "androidx/arch/core/util/Function",
+      "android/databinding/adapters/AbsListViewBindingAdapter": "androidx/databinding/adapters/AbsListViewBindingAdapter",
+      "android/databinding/adapters/AbsSeekBarBindingAdapter": "androidx/databinding/adapters/AbsSeekBarBindingAdapter",
+      "android/databinding/adapters/AbsSpinnerBindingAdapter": "androidx/databinding/adapters/AbsSpinnerBindingAdapter",
+      "android/databinding/adapters/ObservableListAdapter": "androidx/databinding/adapters/ObservableListAdapter",
+      "android/databinding/adapters/ActionMenuViewBindingAdapter": "androidx/databinding/adapters/ActionMenuViewBindingAdapter",
+      "android/databinding/adapters/AdapterViewBindingAdapter": "androidx/databinding/adapters/AdapterViewBindingAdapter",
+      "android/databinding/adapters/AutoCompleteTextViewBindingAdapter": "androidx/databinding/adapters/AutoCompleteTextViewBindingAdapter",
+      "android/databinding/adapters/CalendarViewBindingAdapter": "androidx/databinding/adapters/CalendarViewBindingAdapter",
+      "android/databinding/adapters/CardViewBindingAdapter": "androidx/databinding/adapters/CardViewBindingAdapter",
+      "android/databinding/adapters/CheckedTextViewBindingAdapter": "androidx/databinding/adapters/CheckedTextViewBindingAdapter",
+      "android/databinding/adapters/ChronometerBindingAdapter": "androidx/databinding/adapters/ChronometerBindingAdapter",
+      "android/databinding/adapters/CompoundButtonBindingAdapter": "androidx/databinding/adapters/CompoundButtonBindingAdapter",
+      "android/databinding/adapters/Converters": "androidx/databinding/adapters/Converters",
+      "android/databinding/adapters/DatePickerBindingAdapter": "androidx/databinding/adapters/DatePickerBindingAdapter",
+      "android/databinding/adapters/ListenerUtil": "androidx/databinding/adapters/ListenerUtil",
+      "android/databinding/adapters/ExpandableListViewBindingAdapter": "androidx/databinding/adapters/ExpandableListViewBindingAdapter",
+      "android/databinding/adapters/FrameLayoutBindingAdapter": "androidx/databinding/adapters/FrameLayoutBindingAdapter",
+      "android/databinding/adapters/ImageViewBindingAdapter": "androidx/databinding/adapters/ImageViewBindingAdapter",
+      "android/databinding/adapters/LinearLayoutBindingAdapter": "androidx/databinding/adapters/LinearLayoutBindingAdapter",
+      "android/databinding/adapters/NumberPickerBindingAdapter": "androidx/databinding/adapters/NumberPickerBindingAdapter",
+      "android/databinding/adapters/ProgressBarBindingAdapter": "androidx/databinding/adapters/ProgressBarBindingAdapter",
+      "android/databinding/adapters/RadioGroupBindingAdapter": "androidx/databinding/adapters/RadioGroupBindingAdapter",
+      "android/databinding/adapters/RatingBarBindingAdapter": "androidx/databinding/adapters/RatingBarBindingAdapter",
+      "android/databinding/adapters/SearchViewBindingAdapter": "androidx/databinding/adapters/SearchViewBindingAdapter",
+      "android/databinding/adapters/SeekBarBindingAdapter": "androidx/databinding/adapters/SeekBarBindingAdapter",
+      "android/databinding/adapters/SpinnerBindingAdapter": "androidx/databinding/adapters/SpinnerBindingAdapter",
+      "android/databinding/adapters/SwitchBindingAdapter": "androidx/databinding/adapters/SwitchBindingAdapter",
+      "android/databinding/adapters/SwitchCompatBindingAdapter": "androidx/databinding/adapters/SwitchCompatBindingAdapter",
+      "android/support/v7/widget/SwitchCompat": "androidx/appcompat/widget/SwitchCompat",
+      "android/databinding/adapters/TabHostBindingAdapter": "androidx/databinding/adapters/TabHostBindingAdapter",
+      "android/databinding/adapters/TabWidgetBindingAdapter": "androidx/databinding/adapters/TabWidgetBindingAdapter",
+      "android/databinding/adapters/TableLayoutBindingAdapter": "androidx/databinding/adapters/TableLayoutBindingAdapter",
+      "android/databinding/adapters/TextViewBindingAdapter": "androidx/databinding/adapters/TextViewBindingAdapter",
+      "android/databinding/adapters/TimePickerBindingAdapter": "androidx/databinding/adapters/TimePickerBindingAdapter",
+      "android/databinding/adapters/ToolbarBindingAdapter": "androidx/databinding/adapters/ToolbarBindingAdapter",
+      "android/databinding/adapters/VideoViewBindingAdapter": "androidx/databinding/adapters/VideoViewBindingAdapter",
+      "android/databinding/adapters/ViewBindingAdapter": "androidx/databinding/adapters/ViewBindingAdapter",
+      "android/databinding/adapters/ViewGroupBindingAdapter": "androidx/databinding/adapters/ViewGroupBindingAdapter",
+      "android/databinding/adapters/ViewStubBindingAdapter": "androidx/databinding/adapters/ViewStubBindingAdapter",
+      "android/databinding/ViewStubProxy": "androidx/databinding/ViewStubProxy",
+      "android/databinding/adapters/ZoomControlsBindingAdapter": "androidx/databinding/adapters/ZoomControlsBindingAdapter",
+      "android/databinding/DataBinderMapper": "androidx/databinding/DataBinderMapper",
+      "android/databinding/DataBindingComponent": "androidx/databinding/DataBindingComponent",
+      "android/databinding/ViewDataBinding": "androidx/databinding/ViewDataBinding",
       "android/support/text/emoji/EmojiProcessor": "androidx/emoji/text/EmojiProcessor",
       "android/support/text/emoji/EmojiMetadata": "androidx/emoji/text/EmojiMetadata",
-      "android/support/v4/util/ArraySet": "androidx/collection/ArraySet",
       "android/support/text/emoji/EmojiSpan": "androidx/emoji/text/EmojiSpan",
       "android/support/text/emoji/TypefaceEmojiSpan": "androidx/emoji/text/TypefaceEmojiSpan",
       "android/support/v4/graphics/PaintCompat": "androidx/core/graphics/PaintCompat",
@@ -2418,6 +2599,7 @@
       "android/support/text/emoji/widget/EmojiInputFilter": "androidx/emoji/widget/EmojiInputFilter",
       "android/support/text/emoji/widget/EmojiTextView": "androidx/emoji/widget/EmojiTextView",
       "android/support/text/emoji/widget/EmojiTransformationMethod": "androidx/emoji/widget/EmojiTransformationMethod",
+      "android/arch/lifecycle/GenericLifecycleObserver": "androidx/lifecycle/GenericLifecycleObserver",
       "android/support/v13/view/DragAndDropPermissionsCompat": "androidx/core/view/DragAndDropPermissionsCompat",
       "android/support/v13/view/DragStartHelper": "androidx/core/view/DragStartHelper",
       "android/support/v4/view/MotionEventCompat": "androidx/core/view/MotionEventCompat",
@@ -2427,7 +2609,6 @@
       "android/support/v4/accessibilityservice/AccessibilityServiceInfoCompat": "androidx/core/accessibilityservice/AccessibilityServiceInfoCompat",
       "android/support/v4/app/ActivityCompat": "androidx/core/app/ActivityCompat",
       "android/support/v4/app/SharedElementCallback": "androidx/core/app/SharedElementCallback",
-      "android/support/v4/app/ActivityManagerCompat": "androidx/core/app/ActivityManagerCompat",
       "android/support/v4/app/ActivityOptionsCompat": "androidx/core/app/ActivityOptionsCompat",
       "android/support/v4/app/AlarmManagerCompat": "androidx/core/app/AlarmManagerCompat",
       "android/support/v4/app/AppLaunchChecker": "androidx/core/app/AppLaunchChecker",
@@ -2445,6 +2626,8 @@
       "android/support/v4/app/NotificationManagerCompat": "androidx/core/app/NotificationManagerCompat",
       "android/support/v4/app/ServiceCompat": "androidx/core/app/ServiceCompat",
       "android/support/v4/app/ShareCompat": "androidx/core/app/ShareCompat",
+      "android/arch/lifecycle/LifecycleRegistry": "androidx/lifecycle/LifecycleRegistry",
+      "android/arch/lifecycle/ReportFragment": "androidx/lifecycle/ReportFragment",
       "android/support/v4/app/TaskStackBuilder": "androidx/core/app/TaskStackBuilder",
       "android/support/v4/content/FileProvider": "androidx/core/content/FileProvider",
       "android/support/v4/content/IntentCompat": "androidx/core/content/IntentCompat",
@@ -2543,6 +2726,8 @@
       "android/support/v4/widget/PopupMenuCompat": "androidx/core/widget/PopupMenuCompat",
       "android/support/v4/widget/PopupWindowCompat": "androidx/core/widget/PopupWindowCompat",
       "android/support/v4/widget/ScrollerCompat": "androidx/core/widget/ScrollerCompat",
+      "android/arch/core/internal/FastSafeIterableMap": "androidx/arch/core/internal/FastSafeIterableMap",
+      "android/arch/lifecycle/LifecycleRegistryOwner": "androidx/lifecycle/LifecycleRegistryOwner",
       "android/support/design/transformation/ExpandableBehavior": "android/support/design/transformation/ExpandableBehavior",
       "android/support/design/transformation/ExpandableTransformationBehavior": "android/support/design/transformation/ExpandableTransformationBehavior",
       "android/support/design/transformation/FabTransformationBehavior": "android/support/design/transformation/FabTransformationBehavior",
@@ -2567,6 +2752,28 @@
       "android/support/v4/widget/SimpleCursorAdapter": "androidx/cursoradapter/widget/SimpleCursorAdapter",
       "android/support/design/theme/MaterialComponentsViewInflater": "android/support/design/theme/MaterialComponentsViewInflater",
       "android/support/v7/app/AppCompatViewInflater": "androidx/appcompat/app/AppCompatViewInflater",
+      "android/databinding/BaseObservable": "androidx/databinding/BaseObservable",
+      "android/databinding/PropertyChangeRegistry": "androidx/databinding/PropertyChangeRegistry",
+      "android/databinding/BaseObservableField": "androidx/databinding/BaseObservableField",
+      "android/databinding/DataBindingUtil": "androidx/databinding/DataBindingUtil",
+      "android/databinding/DataBinderMapperImpl": "androidx/databinding/DataBinderMapperImpl",
+      "android/databinding/ListChangeRegistry": "androidx/databinding/ListChangeRegistry",
+      "android/databinding/MapChangeRegistry": "androidx/databinding/MapChangeRegistry",
+      "android/databinding/MergedDataBinderMapper": "androidx/databinding/MergedDataBinderMapper",
+      "android/databinding/ObservableArrayList": "androidx/databinding/ObservableArrayList",
+      "android/databinding/ObservableArrayMap": "androidx/databinding/ObservableArrayMap",
+      "android/databinding/ObservableBoolean": "androidx/databinding/ObservableBoolean",
+      "android/databinding/ObservableByte": "androidx/databinding/ObservableByte",
+      "android/databinding/ObservableChar": "androidx/databinding/ObservableChar",
+      "android/databinding/ObservableDouble": "androidx/databinding/ObservableDouble",
+      "android/databinding/ObservableField": "androidx/databinding/ObservableField",
+      "android/databinding/ObservableFloat": "androidx/databinding/ObservableFloat",
+      "android/databinding/ObservableInt": "androidx/databinding/ObservableInt",
+      "android/databinding/ObservableLong": "androidx/databinding/ObservableLong",
+      "android/databinding/ObservableParcelable": "androidx/databinding/ObservableParcelable",
+      "android/databinding/ObservableShort": "androidx/databinding/ObservableShort",
+      "android/databinding/OnRebindCallback": "androidx/databinding/OnRebindCallback",
+      "android/support/v4/util/LongSparseArray": "androidx/collection/LongSparseArray",
       "android/support/v4/app/BackStackRecord": "androidx/fragment/app/BackStackRecord",
       "android/support/v4/app/Fragment": "androidx/fragment/app/Fragment",
       "android/support/v4/app/FragmentTransaction": "androidx/fragment/app/FragmentTransaction",
@@ -2742,8 +2949,6 @@
       "android/support/v17/leanback/widget/MediaItemActionPresenter": "androidx/leanback/widget/MediaItemActionPresenter",
       "android/support/v17/leanback/widget/AbstractMediaListHeaderPresenter": "androidx/leanback/widget/AbstractMediaListHeaderPresenter",
       "android/support/v17/leanback/widget/ActionPresenterSelector": "androidx/leanback/widget/ActionPresenterSelector",
-      "android/support/v7/util/DiffUtil": "androidx/recyclerview/widget/DiffUtil",
-      "android/support/v7/util/ListUpdateCallback": "androidx/recyclerview/widget/ListUpdateCallback",
       "android/support/v17/leanback/widget/BaseCardView": "androidx/leanback/widget/BaseCardView",
       "android/support/v17/leanback/widget/GridLayoutManager": "androidx/leanback/widget/GridLayoutManager",
       "android/support/v17/leanback/widget/WindowAlignment": "androidx/leanback/widget/WindowAlignment",
@@ -2830,6 +3035,16 @@
       "android/support/v4/provider/SingleDocumentFile": "androidx/documentfile/provider/SingleDocumentFile",
       "android/support/v4/provider/TreeDocumentFile": "androidx/documentfile/provider/TreeDocumentFile",
       "android/support/v4/provider/DocumentsContractApi19": "androidx/documentfile/provider/DocumentsContractApi19",
+      "android/arch/lifecycle/EmptyActivityLifecycleCallbacks": "androidx/lifecycle/EmptyActivityLifecycleCallbacks",
+      "android/arch/lifecycle/HolderFragment": "androidx/lifecycle/HolderFragment",
+      "android/arch/lifecycle/LifecycleDispatcher": "androidx/lifecycle/LifecycleDispatcher",
+      "android/arch/lifecycle/LifecycleService": "androidx/lifecycle/LifecycleService",
+      "android/arch/lifecycle/ServiceLifecycleDispatcher": "androidx/lifecycle/ServiceLifecycleDispatcher",
+      "android/arch/lifecycle/ProcessLifecycleOwner": "androidx/lifecycle/ProcessLifecycleOwner",
+      "android/arch/lifecycle/ProcessLifecycleOwnerInitializer": "androidx/lifecycle/ProcessLifecycleOwnerInitializer",
+      "android/arch/lifecycle/ViewModelProviders": "androidx/lifecycle/ViewModelProviders",
+      "android/arch/lifecycle/ViewModelStores": "androidx/lifecycle/ViewModelStores",
+      "android/arch/persistence/room/testing/MigrationTestHelper": "androidx/room/testing/MigrationTestHelper",
       "android/support/wear/ambient/AmbientDelegate": "androidx/wear/ambient/AmbientDelegate",
       "android/support/wear/ambient/WearableControllerProvider": "androidx/wear/ambient/WearableControllerProvider",
       "android/support/wear/ambient/AmbientMode": "androidx/wear/ambient/AmbientMode",
@@ -2871,8 +3086,6 @@
       "android/support/wear/widget/drawer/WearableDrawerLayout": "androidx/wear/widget/drawer/WearableDrawerLayout",
       "android/support/v4/content/LocalBroadcastManager": "androidx/localbroadcastmanager/content/LocalBroadcastManager",
       "android/support/v4/print/PrintHelper": "androidx/print/PrintHelper",
-      "android/support/v7/recyclerview/extensions/AsyncDifferConfig": "androidx/recyclerview/widget/AsyncDifferConfig",
-      "android/support/v7/util/AdapterListUpdateCallback": "androidx/recyclerview/widget/AdapterListUpdateCallback",
       "android/support/media/ExifInterface": "androidx/exifinterface/media/ExifInterface",
       "android/support/v7/app/MediaRouteActionProvider": "androidx/mediarouter/app/MediaRouteActionProvider",
       "android/support/v7/media/MediaRouter": "androidx/mediarouter/media/MediaRouter",
@@ -2994,7 +3207,6 @@
       "android/support/transition/Slide": "androidx/transition/Slide",
       "android/support/transition/WindowIdImpl": "androidx/transition/WindowIdImpl",
       "android/support/transition/TransitionValuesMaps": "androidx/transition/TransitionValuesMaps",
-      "android/support/v4/util/LongSparseArray": "androidx/collection/LongSparseArray",
       "android/support/transition/TransitionInflater": "androidx/transition/TransitionInflater",
       "android/support/transition/ViewGroupOverlayApi14": "androidx/transition/ViewGroupOverlayApi14",
       "android/support/transition/ViewOverlayApi14": "androidx/transition/ViewOverlayApi14",
@@ -3040,7 +3252,6 @@
       "android/support/v7/preference/PreferenceInflater": "androidx/preference/PreferenceInflater",
       "android/support/v7/preference/SeekBarPreference": "androidx/preference/SeekBarPreference",
       "android/support/v7/preference/SwitchPreferenceCompat": "androidx/preference/SwitchPreferenceCompat",
-      "android/support/v7/widget/SwitchCompat": "androidx/appcompat/widget/SwitchCompat",
       "android/support/v7/preference/UnPressableLinearLayout": "androidx/preference/UnPressableLinearLayout",
       "android/support/v7/view/menu/SubMenuBuilder": "androidx/appcompat/view/menu/SubMenuBuilder",
       "android/support/v7/widget/LinearLayoutCompat": "androidx/appcompat/widget/LinearLayoutCompat",
@@ -3082,6 +3293,182 @@
       "android/support/content/Query": "androidx/contentpager/content/Query",
       "android/support/content/InMemoryCursor": "androidx/contentpager/content/InMemoryCursor",
       "android/support/content/LoaderQueryRunner": "androidx/contentpager/content/LoaderQueryRunner",
+      "android/arch/persistence/room/parser/SQLiteParser": "androidx/room/parser/SQLiteParser",
+      "android/arch/persistence/room/parser/SQLiteListener": "androidx/room/parser/SQLiteListener",
+      "android/arch/persistence/room/parser/SQLiteVisitor": "androidx/room/parser/SQLiteVisitor",
+      "android/arch/persistence/room/parser/SQLiteLexer": "androidx/room/parser/SQLiteLexer",
+      "android/arch/persistence/room/parser/SQLiteBaseVisitor": "androidx/room/parser/SQLiteBaseVisitor",
+      "android/arch/persistence/room/parser/SQLiteBaseListener": "androidx/room/parser/SQLiteBaseListener",
+      "android/arch/persistence/room/parser/SQLTypeAffinity": "androidx/room/parser/SQLTypeAffinity",
+      "android/arch/persistence/room/verifier/ColumnInfo": "androidx/room/verifier/ColumnInfo",
+      "android/arch/persistence/room/parser/QueryVisitor": "androidx/room/parser/QueryVisitor",
+      "android/arch/persistence/room/parser/ParsedQuery": "androidx/room/parser/ParsedQuery",
+      "android/arch/persistence/room/parser/ParserErrors": "androidx/room/parser/ParserErrors",
+      "android/arch/persistence/room/parser/QueryType": "androidx/room/parser/QueryType",
+      "android/arch/persistence/room/parser/SqlParser": "androidx/room/parser/SqlParser",
+      "android/arch/persistence/room/parser/Table": "androidx/room/parser/Table",
+      "android/arch/persistence/room/parser/Section": "androidx/room/parser/Section",
+      "android/arch/persistence/room/parser/SectionType": "androidx/room/parser/SectionType",
+      "android/arch/persistence/room/verifier/QueryResultInfo": "androidx/room/verifier/QueryResultInfo",
+      "android/arch/persistence/room/parser/Collate": "androidx/room/parser/Collate",
+      "android/arch/persistence/room/verifier/DatabaseVerifier": "androidx/room/verifier/DatabaseVerifier",
+      "android/arch/persistence/room/processor/Context": "androidx/room/processor/Context",
+      "android/arch/persistence/room/vo/Entity": "androidx/room/vo/Entity",
+      "android/arch/persistence/room/log/RLog": "androidx/room/log/RLog",
+      "android/arch/persistence/room/vo/Warning": "androidx/room/vo/Warning",
+      "android/arch/persistence/room/verifier/DatabaseVerificaitonErrors": "androidx/room/verifier/DatabaseVerificaitonErrors",
+      "android/arch/persistence/room/solver/types/BoxedBooleanToBoxedIntConverter": "androidx/room/solver/types/BoxedBooleanToBoxedIntConverter",
+      "android/arch/persistence/room/solver/types/TypeConverter": "androidx/room/solver/types/TypeConverter",
+      "android/arch/persistence/room/solver/CodeGenScope": "androidx/room/solver/CodeGenScope",
+      "android/arch/persistence/room/ext/Javapoet_extKt": "androidx/room/ext/Javapoet_extKt",
+      "android/arch/persistence/room/solver/types/PrimitiveColumnTypeAdapter": "androidx/room/solver/types/PrimitiveColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/ColumnTypeAdapter": "androidx/room/solver/types/ColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/BoxedPrimitiveColumnTypeAdapter": "androidx/room/solver/types/BoxedPrimitiveColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/PrimitiveBooleanToIntConverter": "androidx/room/solver/types/PrimitiveBooleanToIntConverter",
+      "android/arch/persistence/room/solver/types/CompositeAdapter": "androidx/room/solver/types/CompositeAdapter",
+      "android/arch/persistence/room/solver/types/NoOpConverter": "androidx/room/solver/types/NoOpConverter",
+      "android/arch/persistence/room/solver/types/StringColumnTypeAdapter": "androidx/room/solver/types/StringColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/StatementValueBinder": "androidx/room/solver/types/StatementValueBinder",
+      "android/arch/persistence/room/solver/types/CursorValueReader": "androidx/room/solver/types/CursorValueReader",
+      "android/arch/persistence/room/solver/types/CustomTypeConverterWrapper": "androidx/room/solver/types/CustomTypeConverterWrapper",
+      "android/arch/persistence/room/vo/CustomTypeConverter": "androidx/room/vo/CustomTypeConverter",
+      "android/arch/persistence/room/writer/ClassWriter": "androidx/room/writer/ClassWriter",
+      "android/arch/persistence/room/solver/types/ByteArrayColumnTypeAdapter": "androidx/room/solver/types/ByteArrayColumnTypeAdapter",
+      "android/arch/persistence/room/solver/types/CompositeTypeConverter": "androidx/room/solver/types/CompositeTypeConverter",
+      "android/arch/persistence/room/solver/TypeAdapterStore": "androidx/room/solver/TypeAdapterStore",
+      "android/arch/persistence/room/solver/binderprovider/LiveDataQueryResultBinderProvider": "androidx/room/solver/binderprovider/LiveDataQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/ObservableQueryResultBinderProvider": "androidx/room/solver/ObservableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/QueryResultAdapter": "androidx/room/solver/query/result/QueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/QueryResultBinder": "androidx/room/solver/query/result/QueryResultBinder",
+      "android/arch/persistence/room/solver/query/result/LiveDataQueryResultBinder": "androidx/room/solver/query/result/LiveDataQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceQueryResultBinderProvider": "androidx/room/solver/binderprovider/DataSourceQueryResultBinderProvider",
+      "android/arch/persistence/room/ext/PagingTypeNames": "androidx/room/ext/PagingTypeNames",
+      "android/arch/persistence/room/solver/QueryResultBinderProvider": "androidx/room/solver/QueryResultBinderProvider",
+      "android/arch/persistence/room/processor/ProcessorErrors": "androidx/room/processor/ProcessorErrors",
+      "android/arch/persistence/room/solver/query/result/RowAdapter": "androidx/room/solver/query/result/RowAdapter",
+      "android/arch/persistence/room/solver/query/result/ListQueryResultAdapter": "androidx/room/solver/query/result/ListQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/PositionalDataSourceQueryResultBinder": "androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder",
+      "android/arch/persistence/room/ext/LifecyclesTypeNames": "androidx/room/ext/LifecyclesTypeNames",
+      "android/arch/persistence/room/solver/binderprovider/RxMaybeQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxMaybeQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/binderprovider/RxCallableQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxCallableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/RxCallableQueryResultBinder": "androidx/room/solver/query/result/RxCallableQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider": "androidx/room/solver/binderprovider/GuavaListenableFutureQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/GuavaListenableFutureQueryResultBinder": "androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder",
+      "android/arch/persistence/room/ext/GuavaUtilConcurrentTypeNames": "androidx/room/ext/GuavaUtilConcurrentTypeNames",
+      "android/arch/persistence/room/solver/binderprovider/FlowableQueryResultBinderProvider": "androidx/room/solver/binderprovider/FlowableQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/FlowableQueryResultBinder": "androidx/room/solver/query/result/FlowableQueryResultBinder",
+      "android/arch/persistence/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider": "androidx/room/solver/binderprovider/DataSourceFactoryQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/DataSourceFactoryQueryResultBinder": "androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder",
+      "android/arch/persistence/room/ext/RoomRxJava2TypeNames": "androidx/room/ext/RoomRxJava2TypeNames",
+      "android/arch/persistence/room/ext/RoomGuavaTypeNames": "androidx/room/ext/RoomGuavaTypeNames",
+      "android/arch/persistence/room/solver/binderprovider/InstantQueryResultBinderProvider": "androidx/room/solver/binderprovider/InstantQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/InstantQueryResultBinder": "androidx/room/solver/query/result/InstantQueryResultBinder",
+      "android/arch/persistence/room/ext/RxJava2TypeNames": "androidx/room/ext/RxJava2TypeNames",
+      "android/arch/persistence/room/solver/binderprovider/CursorQueryResultBinderProvider": "androidx/room/solver/binderprovider/CursorQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/CursorQueryResultBinder": "androidx/room/solver/query/result/CursorQueryResultBinder",
+      "android/arch/persistence/room/ext/AndroidTypeNames": "androidx/room/ext/AndroidTypeNames",
+      "android/arch/persistence/room/solver/binderprovider/RxSingleQueryResultBinderProvider": "androidx/room/solver/binderprovider/RxSingleQueryResultBinderProvider",
+      "android/arch/persistence/room/solver/query/result/SingleEntityQueryResultAdapter": "androidx/room/solver/query/result/SingleEntityQueryResultAdapter",
+      "android/arch/persistence/room/ext/GuavaBaseTypeNames": "androidx/room/ext/GuavaBaseTypeNames",
+      "android/arch/persistence/room/solver/query/result/GuavaOptionalQueryResultAdapter": "androidx/room/solver/query/result/GuavaOptionalQueryResultAdapter",
+      "android/arch/persistence/room/ext/CommonTypeNames": "androidx/room/ext/CommonTypeNames",
+      "android/arch/persistence/room/solver/query/result/OptionalQueryResultAdapter": "androidx/room/solver/query/result/OptionalQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/ArrayQueryResultAdapter": "androidx/room/solver/query/result/ArrayQueryResultAdapter",
+      "android/arch/persistence/room/solver/query/result/PojoRowAdapter": "androidx/room/solver/query/result/PojoRowAdapter",
+      "android/arch/persistence/room/Entity": "androidx/room/Entity",
+      "android/arch/persistence/room/ext/Element_extKt": "androidx/room/ext/Element_extKt",
+      "android/arch/persistence/room/solver/query/result/EntityRowAdapter": "androidx/room/solver/query/result/EntityRowAdapter",
+      "android/arch/persistence/room/processor/EntityProcessor": "androidx/room/processor/EntityProcessor",
+      "android/arch/persistence/room/solver/query/result/SingleColumnRowAdapter": "androidx/room/solver/query/result/SingleColumnRowAdapter",
+      "android/arch/persistence/room/processor/PojoProcessor": "androidx/room/processor/PojoProcessor",
+      "android/arch/persistence/room/processor/FieldProcessor": "androidx/room/processor/FieldProcessor",
+      "android/arch/persistence/room/vo/EmbeddedField": "androidx/room/vo/EmbeddedField",
+      "android/arch/persistence/room/vo/Pojo": "androidx/room/vo/Pojo",
+      "android/arch/persistence/room/solver/query/parameter/QueryParameterAdapter": "androidx/room/solver/query/parameter/QueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/CollectionQueryParameterAdapter": "androidx/room/solver/query/parameter/CollectionQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/BasicQueryParameterAdapter": "androidx/room/solver/query/parameter/BasicQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/parameter/ArrayQueryParameterAdapter": "androidx/room/solver/query/parameter/ArrayQueryParameterAdapter",
+      "android/arch/persistence/room/solver/query/result/BaseObservableQueryResultBinder": "androidx/room/solver/query/result/BaseObservableQueryResultBinder",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapperKt": "androidx/room/solver/query/result/TransactionWrapperKt",
+      "android/arch/persistence/room/solver/query/result/TransactionWrapper": "androidx/room/solver/query/result/TransactionWrapper",
+      "android/arch/persistence/room/writer/DaoWriter": "androidx/room/writer/DaoWriter",
+      "android/arch/persistence/room/writer/EntityCursorConverterWriter": "androidx/room/writer/EntityCursorConverterWriter",
+      "android/arch/persistence/room/vo/RelationCollector": "androidx/room/vo/RelationCollector",
+      "android/arch/persistence/room/vo/Field": "androidx/room/vo/Field",
+      "android/arch/persistence/room/vo/FieldWithIndex": "androidx/room/vo/FieldWithIndex",
+      "android/arch/persistence/room/writer/FieldReadWriteWriter": "androidx/room/writer/FieldReadWriteWriter",
+      "android/arch/persistence/room/ext/RoomTypeNames": "androidx/room/ext/RoomTypeNames",
+      "android/arch/persistence/room/vo/Dao": "androidx/room/vo/Dao",
+      "android/arch/persistence/room/vo/Constructor": "androidx/room/vo/Constructor",
+      "android/arch/persistence/room/vo/Database": "androidx/room/vo/Database",
+      "android/arch/persistence/room/vo/Index": "androidx/room/vo/Index",
+      "android/arch/persistence/room/vo/SchemaIdentityKey": "androidx/room/vo/SchemaIdentityKey",
+      "android/arch/persistence/room/vo/DeletionMethod": "androidx/room/vo/DeletionMethod",
+      "android/arch/persistence/room/vo/ShortcutMethod": "androidx/room/vo/ShortcutMethod",
+      "android/arch/persistence/room/vo/ShortcutQueryParameter": "androidx/room/vo/ShortcutQueryParameter",
+      "android/arch/persistence/room/vo/HasSchemaIdentity": "androidx/room/vo/HasSchemaIdentity",
+      "android/arch/persistence/room/vo/PrimaryKey": "androidx/room/vo/PrimaryKey",
+      "android/arch/persistence/room/vo/PojoMethod": "androidx/room/vo/PojoMethod",
+      "android/arch/persistence/room/vo/TransactionMethod": "androidx/room/vo/TransactionMethod",
+      "android/arch/persistence/room/vo/QueryMethod": "androidx/room/vo/QueryMethod",
+      "android/arch/persistence/room/vo/FieldGetter": "androidx/room/vo/FieldGetter",
+      "android/arch/persistence/room/vo/CallType": "androidx/room/vo/CallType",
+      "android/arch/persistence/room/vo/ForeignKeyAction": "androidx/room/vo/ForeignKeyAction",
+      "android/arch/persistence/room/vo/ForeignKey": "androidx/room/vo/ForeignKey",
+      "android/arch/persistence/room/vo/Relation": "androidx/room/vo/Relation",
+      "android/arch/persistence/room/preconditions/Checks": "androidx/room/preconditions/Checks",
+      "android/arch/persistence/room/vo/QueryParameter": "androidx/room/vo/QueryParameter",
+      "android/arch/persistence/room/writer/RelationCollectorMethodWriter": "androidx/room/writer/RelationCollectorMethodWriter",
+      "android/arch/persistence/room/writer/QueryWriter": "androidx/room/writer/QueryWriter",
+      "android/arch/persistence/room/vo/RawQueryMethod": "androidx/room/vo/RawQueryMethod",
+      "android/arch/persistence/room/vo/UpdateMethod": "androidx/room/vo/UpdateMethod",
+      "android/arch/persistence/room/vo/FieldSetter": "androidx/room/vo/FieldSetter",
+      "android/arch/persistence/room/vo/InsertionMethod": "androidx/room/vo/InsertionMethod",
+      "android/arch/persistence/room/vo/DaoMethod": "androidx/room/vo/DaoMethod",
+      "android/arch/persistence/room/ext/SupportDbTypeNames": "androidx/room/ext/SupportDbTypeNames",
+      "android/arch/persistence/room/RoomProcessor": "androidx/room/RoomProcessor",
+      "android/arch/persistence/room/writer/EntityInsertionAdapterWriter": "androidx/room/writer/EntityInsertionAdapterWriter",
+      "android/arch/persistence/room/writer/TableInfoValidationWriter": "androidx/room/writer/TableInfoValidationWriter",
+      "android/arch/persistence/room/writer/DatabaseWriter": "androidx/room/writer/DatabaseWriter",
+      "android/arch/persistence/room/writer/EntityDeleteComparator": "androidx/room/writer/EntityDeleteComparator",
+      "android/arch/persistence/room/writer/EntityDeletionAdapterWriter": "androidx/room/writer/EntityDeletionAdapterWriter",
+      "android/arch/persistence/room/writer/EntityUpdateAdapterWriter": "androidx/room/writer/EntityUpdateAdapterWriter",
+      "android/arch/persistence/room/writer/SQLiteOpenHelperWriter": "androidx/room/writer/SQLiteOpenHelperWriter",
+      "android/arch/persistence/room/processor/OnConflictProcessor": "androidx/room/processor/OnConflictProcessor",
+      "android/arch/persistence/room/writer/PreparedStatementWriter": "androidx/room/writer/PreparedStatementWriter",
+      "android/arch/persistence/room/ext/KotlinMetadataProcessor": "androidx/room/ext/KotlinMetadataProcessor",
+      "android/arch/persistence/room/ext/ArchTypeNames": "androidx/room/ext/ArchTypeNames",
+      "android/arch/persistence/room/ext/ReactiveStreamsTypeNames": "androidx/room/ext/ReactiveStreamsTypeNames",
+      "android/arch/persistence/room/Database": "androidx/room/Database",
+      "android/arch/persistence/room/processor/DatabaseProcessor": "androidx/room/processor/DatabaseProcessor",
+      "android/arch/persistence/room/Dao": "androidx/room/Dao",
+      "android/arch/persistence/room/processor/CustomConverterProcessor": "androidx/room/processor/CustomConverterProcessor",
+      "android/arch/persistence/room/processor/cache/Cache": "androidx/room/processor/cache/Cache",
+      "android/arch/persistence/room/Embedded": "androidx/room/Embedded",
+      "android/arch/persistence/room/Relation": "androidx/room/Relation",
+      "android/arch/persistence/room/Ignore": "androidx/room/Ignore",
+      "android/arch/persistence/room/processor/PojoMethodProcessor": "androidx/room/processor/PojoMethodProcessor",
+      "android/arch/persistence/room/processor/InsertionMethodProcessor": "androidx/room/processor/InsertionMethodProcessor",
+      "android/arch/persistence/room/SkipQueryVerification": "androidx/room/SkipQueryVerification",
+      "android/arch/persistence/room/processor/DaoProcessor": "androidx/room/processor/DaoProcessor",
+      "android/arch/persistence/room/processor/DeletionMethodProcessor": "androidx/room/processor/DeletionMethodProcessor",
+      "android/arch/persistence/room/processor/ShortcutMethodProcessor": "androidx/room/processor/ShortcutMethodProcessor",
+      "android/arch/persistence/room/Delete": "androidx/room/Delete",
+      "android/arch/persistence/room/processor/TransactionMethodProcessor": "androidx/room/processor/TransactionMethodProcessor",
+      "android/arch/persistence/room/processor/ShortcutParameterProcessor": "androidx/room/processor/ShortcutParameterProcessor",
+      "android/arch/persistence/room/processor/RawQueryMethodProcessor": "androidx/room/processor/RawQueryMethodProcessor",
+      "android/arch/persistence/room/RawQuery": "androidx/room/RawQuery",
+      "android/arch/persistence/room/Transaction": "androidx/room/Transaction",
+      "android/arch/persistence/room/processor/SuppressWarningProcessor": "androidx/room/processor/SuppressWarningProcessor",
+      "android/arch/persistence/room/Insert": "androidx/room/Insert",
+      "android/arch/persistence/room/processor/QueryMethodProcessor": "androidx/room/processor/QueryMethodProcessor",
+      "android/arch/persistence/room/processor/QueryParameterProcessor": "androidx/room/processor/QueryParameterProcessor",
+      "android/arch/persistence/room/processor/UpdateMethodProcessor": "androidx/room/processor/UpdateMethodProcessor",
+      "android/arch/persistence/room/Update": "androidx/room/Update",
+      "android/arch/persistence/room/Query": "androidx/room/Query",
+      "android/arch/persistence/room/TypeConverter": "androidx/room/TypeConverter",
+      "android/arch/persistence/room/TypeConverters": "androidx/room/TypeConverters",
+      "android/arch/persistence/room/PrimaryKey": "androidx/room/PrimaryKey",
       "android/support/coordinatorlayout/R": "androidx/coordinatorlayout/R",
       "android/support/v4/widget/DirectedAcyclicGraph": "androidx/coordinatorlayout/widget/DirectedAcyclicGraph",
       "android/support/v4/widget/ViewGroupUtils": "androidx/coordinatorlayout/widget/ViewGroupUtils",
@@ -3215,12 +3602,23 @@
       "android/support/v7/widget/TintResources": "androidx/appcompat/widget/TintResources",
       "android/support/v7/widget/TooltipCompatHandler": "androidx/appcompat/widget/TooltipCompatHandler",
       "android/support/v7/widget/TooltipPopup": "androidx/appcompat/widget/TooltipPopup",
+      "android/arch/core/executor/JunitTaskExecutorRule": "androidx/arch/core/executor/JunitTaskExecutorRule",
+      "android/arch/core/executor/TaskExecutorWithFakeMainThread": "androidx/arch/core/executor/TaskExecutorWithFakeMainThread",
+      "android/arch/core/executor/TaskExecutor": "androidx/arch/core/executor/TaskExecutor",
+      "android/arch/core/executor/testing/CountingTaskExecutorRule": "androidx/arch/core/executor/testing/CountingTaskExecutorRule",
+      "android/arch/core/executor/DefaultTaskExecutor": "androidx/arch/core/executor/DefaultTaskExecutor",
+      "android/arch/core/executor/testing/InstantTaskExecutorRule": "androidx/arch/core/executor/testing/InstantTaskExecutorRule",
       "android/support/text/emoji/widget/EmojiAppCompatButton": "androidx/emoji/widget/EmojiAppCompatButton",
       "android/support/text/emoji/widget/EmojiAppCompatEditText": "androidx/emoji/widget/EmojiAppCompatEditText",
       "android/support/text/emoji/widget/EmojiAppCompatTextView": "androidx/emoji/widget/EmojiAppCompatTextView",
       "android/support/design/card/MaterialCardView": "android/support/design/card/MaterialCardView",
       "android/support/design/card/R": "android/support/design/card/R",
       "android/support/design/card/MaterialCardViewHelper": "android/support/design/card/MaterialCardViewHelper",
+      "android/arch/lifecycle/ClassesInfoCache": "androidx/lifecycle/ClassesInfoCache",
+      "android/arch/lifecycle/FullLifecycleObserverAdapter": "androidx/lifecycle/FullLifecycleObserverAdapter",
+      "android/arch/lifecycle/SingleGeneratedAdapterObserver": "androidx/lifecycle/SingleGeneratedAdapterObserver",
+      "android/arch/lifecycle/CompositeGeneratedAdaptersObserver": "androidx/lifecycle/CompositeGeneratedAdaptersObserver",
+      "android/arch/lifecycle/ReflectiveGenericLifecycleObserver": "androidx/lifecycle/ReflectiveGenericLifecycleObserver",
       "android/support/customtabs/CustomTabsCallback": "androidx/browser/customtabs/CustomTabsCallback",
       "android/support/customtabs/CustomTabsClient": "androidx/browser/customtabs/CustomTabsClient",
       "android/support/customtabs/CustomTabsServiceConnection": "androidx/browser/customtabs/CustomTabsServiceConnection",
@@ -3235,13 +3633,31 @@
       "android/support/customtabs/PostMessageServiceConnection": "androidx/browser/customtabs/PostMessageServiceConnection",
       "android/support/customtabs/TrustedWebUtils": "androidx/browser/customtabs/TrustedWebUtils",
       "android/support/customtabs/R": "androidx/browser/R",
+      "android/arch/lifecycle/AndroidViewModel": "androidx/lifecycle/AndroidViewModel",
       "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout": "android/support/design/circularreveal/coordinatorlayout/CircularRevealCoordinatorLayout",
       "android/support/percent/PercentFrameLayout": "androidx/percentlayout/widget/PercentFrameLayout",
       "android/support/percent/PercentLayoutHelper": "androidx/percentlayout/widget/PercentLayoutHelper",
       "android/support/percent/R": "androidx/percentlayout/R",
       "android/support/percent/PercentRelativeLayout": "androidx/percentlayout/widget/PercentRelativeLayout",
+      "android/arch/persistence/db/SupportSQLiteQueryBuilder": "androidx/sqlite/db/SupportSQLiteQueryBuilder",
       "android/support/design/animation/R": "android/support/design/animation/R",
+      "android/arch/paging/PageResult": "androidx/paging/PageResult",
+      "android/arch/paging/ListDataSource": "androidx/paging/ListDataSource",
+      "android/arch/paging/WrapperItemKeyedDataSource": "androidx/paging/WrapperItemKeyedDataSource",
+      "android/arch/paging/PageKeyedDataSource": "androidx/paging/PageKeyedDataSource",
+      "android/arch/paging/ContiguousDataSource": "androidx/paging/ContiguousDataSource",
+      "android/arch/paging/WrapperPageKeyedDataSource": "androidx/paging/WrapperPageKeyedDataSource",
+      "android/arch/paging/ItemKeyedDataSource": "androidx/paging/ItemKeyedDataSource",
+      "android/arch/paging/TiledPagedList": "androidx/paging/TiledPagedList",
+      "android/arch/paging/TiledDataSource": "androidx/paging/TiledDataSource",
+      "android/arch/paging/WrapperPositionalDataSource": "androidx/paging/WrapperPositionalDataSource",
+      "android/arch/paging/ContiguousPagedList": "androidx/paging/ContiguousPagedList",
+      "android/arch/paging/SnapshotPagedList": "androidx/paging/SnapshotPagedList",
       "android/support/v4/view/AsyncLayoutInflater": "androidx/asynclayoutinflater/view/AsyncLayoutInflater",
+      "android/arch/persistence/room/ForeignKey": "androidx/room/ForeignKey",
+      "android/arch/persistence/room/RoomWarnings": "androidx/room/RoomWarnings",
+      "android/arch/persistence/room/Index": "androidx/room/Index",
+      "android/arch/persistence/room/OnConflictStrategy": "androidx/room/OnConflictStrategy",
       "android/support/design/circularreveal/CircularRevealGridLayout": "android/support/design/circularreveal/CircularRevealGridLayout",
       "android/support/design/circularreveal/CircularRevealLinearLayout": "android/support/design/circularreveal/CircularRevealLinearLayout",
       "android/support/design/circularreveal/CircularRevealRelativeLayout": "android/support/design/circularreveal/CircularRevealRelativeLayout"
@@ -3250,7 +3666,8 @@
   "proGuardMap": {
     "rules": {
       "android/support/transition/ChangeBounds$*": "androidx/transition/ChangeBounds$*",
-      "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat$*"
+      "android/support/graphics/drawable/VectorDrawableCompat$*": "androidx/vectordrawable/graphics/drawable/VectorDrawableCompat$*",
+      "android/arch/persistence/room/paging/**": "androidx/room/paging/**"
     }
   }
 }
\ No newline at end of file
diff --git a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
index d6f8971..19dcc7e 100755
--- a/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
+++ b/jetifier/jetifier/preprocessor/scripts/processDefaultConfig.sh
@@ -32,6 +32,7 @@
 PREPROCESSOR_DISTRO_PATH="$BUILD_DIR/jetifier-preprocessor/build/distributions/jetifier-preprocessor.zip"
 PREPROCESSOR_BIN_PATH="$OUT_DIR/jetifier-preprocessor/bin/jetifier-preprocessor"
 SUPPORT_LIBS_BUILD_NUMBER="4631572"
+APP_TOOLKIT_BUILD_NUMBER="4669041"
 SUPPORT_LIBS_DOWNLOADED="$OUT_DIR/supportLibs/downloaded"
 SUPPORT_LIBS_UNPACKED="$OUT_DIR/supportLibs/unpacked"
 
@@ -65,7 +66,6 @@
 echo "OUT dir is at '$OUT_DIR'"
 
 function getPreRenamedSupportLib() {
-	INPUT_FILENAME="top-of-tree-m2repository-$SUPPORT_LIBS_BUILD_NUMBER.zip"
 	printSectionStart "Downloading all affected support libraries"
 	mkdir -p "$SUPPORT_LIBS_DOWNLOADED"
 
@@ -79,17 +79,28 @@
 	fi
 
 	cd "$SUPPORT_LIBS_DOWNLOADED"
-	"$FETCH_ARTIFACT" --bid "$SUPPORT_LIBS_BUILD_NUMBER" --target support_library "$INPUT_FILENAME" "$SUPPORT_LIBS_DOWNLOADED/support-lib-${SUPPORT_LIBS_BUILD_NUMBER}.zip"
-	"$FETCH_ARTIFACT" --bid "$SUPPORT_LIBS_BUILD_NUMBER" --target support_library_app_toolkit "$INPUT_FILENAME" "$SUPPORT_LIBS_DOWNLOADED/arch-${SUPPORT_LIBS_BUILD_NUMBER}.zip"
+	"$FETCH_ARTIFACT" --bid "$SUPPORT_LIBS_BUILD_NUMBER" --target support_library "top-of-tree-m2repository-$SUPPORT_LIBS_BUILD_NUMBER.zip" "$SUPPORT_LIBS_DOWNLOADED/support-lib.zip"
+	"$FETCH_ARTIFACT" --bid "$APP_TOOLKIT_BUILD_NUMBER" --target support_library_app_toolkit "top-of-tree-m2repository-$APP_TOOLKIT_BUILD_NUMBER.zip" "$SUPPORT_LIBS_DOWNLOADED/arch.zip"
 	cd -
 
 
-	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/support-lib-${SUPPORT_LIBS_BUILD_NUMBER}.zip" -d "$SUPPORT_LIBS_UNPACKED"
-	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/arch-${SUPPORT_LIBS_BUILD_NUMBER}.zip" -d "$SUPPORT_LIBS_UNPACKED"
+	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/support-lib.zip" -d "$SUPPORT_LIBS_UNPACKED"
+	unzip -oj "$SUPPORT_LIBS_DOWNLOADED/arch.zip" -d "$SUPPORT_LIBS_UNPACKED"
 	find "$CHECKOUT_DIR/prebuilts/maven_repo/android/com/android/support/" -type f -name "*design-*28.0.0*.aar" -exec cp '{}' -t "$SUPPORT_LIBS_UNPACKED" \;
 	find "$SUPPORT_LIBS_UNPACKED" -type f -name "jetifier*" -exec rm -f {} \;
 }
+
+DATA_BINDING_VERSION=`curl https://dl.google.com/dl/android/maven2/com/android/databinding/baseLibrary/maven-metadata.xml|xmllint --format -|grep latest|awk '{split($NAME,a,"[><]"); print a[3]}'`
+function pullDataBinding() {
+	NAME=$1
+	TYPE=$2
+	curl "https://dl.google.com/dl/android/maven2/com/android/databinding/$NAME/$DATA_BINDING_VERSION/$NAME-$DATA_BINDING_VERSION.$TYPE" -o "$SUPPORT_LIBS_UNPACKED/databinding-$NAME.$TYPE"
+}
+
 getPreRenamedSupportLib
+pullDataBinding "baseLibrary" "jar"
+pullDataBinding "adapters" "aar"
+pullDataBinding "library" "aar"
 
 printSectionStart "Preparing Jetifier"
 buildProjectUsingGradle $JETIFIER_DIR/../..
diff --git a/leanback/api21/androidx/leanback/transition/TransitionHelperApi21.java b/leanback/api21/androidx/leanback/transition/TransitionHelperApi21.java
deleted file mode 100644
index 57d7476..0000000
--- a/leanback/api21/androidx/leanback/transition/TransitionHelperApi21.java
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * 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.
- */
-package androidx.leanback.transition;
-
-import android.R;
-import android.content.Context;
-import android.graphics.Rect;
-import android.transition.ChangeTransform;
-import android.transition.Transition;
-import android.transition.TransitionManager;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
-import android.view.animation.AnimationUtils;
-
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(21)
-final class TransitionHelperApi21 {
-
-    TransitionHelperApi21() {
-    }
-
-    public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
-        fragment.setEnterTransition((Transition)transition);
-    }
-
-    public static void setExitTransition(android.app.Fragment fragment, Object transition) {
-       fragment.setExitTransition((Transition)transition);
-    }
-
-    public static void setSharedElementEnterTransition(android.app.Fragment fragment,
-            Object transition) {
-        fragment.setSharedElementEnterTransition((Transition)transition);
-     }
-
-    public static void addSharedElement(android.app.FragmentTransaction ft,
-            View view, String transitionName) {
-        ft.addSharedElement(view, transitionName);
-    }
-
-    public static Object getSharedElementEnterTransition(Window window) {
-        return window.getSharedElementEnterTransition();
-    }
-
-    public static void setSharedElementEnterTransition(Window window, Object transition) {
-        window.setSharedElementEnterTransition((Transition) transition);
-    }
-
-    public static Object getSharedElementReturnTransition(Window window) {
-        return window.getSharedElementReturnTransition();
-    }
-
-    public static void setSharedElementReturnTransition(Window window, Object transition) {
-        window.setSharedElementReturnTransition((Transition) transition);
-    }
-
-    public static Object getSharedElementExitTransition(Window window) {
-        return window.getSharedElementExitTransition();
-    }
-
-    public static Object getSharedElementReenterTransition(Window window) {
-        return window.getSharedElementReenterTransition();
-    }
-
-    public static Object getEnterTransition(Window window) {
-        return window.getEnterTransition();
-    }
-
-    public static void setEnterTransition(Window window, Object transition) {
-        window.setEnterTransition((Transition) transition);
-    }
-
-    public static Object getReturnTransition(Window window) {
-        return window.getReturnTransition();
-    }
-
-    public static void setReturnTransition(Window window, Object transition) {
-        window.setReturnTransition((Transition) transition);
-    }
-
-    public static Object getExitTransition(Window window) {
-        return window.getExitTransition();
-    }
-
-    public static Object getReenterTransition(Window window) {
-        return window.getReenterTransition();
-    }
-
-    public static Object createScale() {
-        return new ChangeTransform();
-    }
-
-    public static Object createDefaultInterpolator(Context context) {
-        return AnimationUtils.loadInterpolator(context, R.interpolator.fast_out_linear_in);
-    }
-
-    public static Object createChangeTransform() {
-        return new ChangeTransform();
-    }
-
-    public static Object createFadeAndShortSlide(int edge) {
-        return new FadeAndShortSlide(edge);
-    }
-
-    public static Object createFadeAndShortSlide(int edge, float distance) {
-        FadeAndShortSlide slide = new FadeAndShortSlide(edge);
-        slide.setDistance(distance);
-        return slide;
-    }
-
-    public static void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
-        Transition transition = (Transition) transitionObject;
-        TransitionManager.beginDelayedTransition(sceneRoot, transition);
-    }
-
-    public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
-        viewGroup.setTransitionGroup(transitionGroup);
-    }
-
-    public static void setEpicenterCallback(Object transitionObject,
-            final TransitionEpicenterCallback callback) {
-        Transition transition = (Transition) transitionObject;
-        if (callback == null) {
-            transition.setEpicenterCallback(null);
-        } else {
-            transition.setEpicenterCallback(new Transition.EpicenterCallback() {
-                @Override
-                public Rect onGetEpicenter(Transition transition) {
-                    return callback.onGetEpicenter(transition);
-                }
-            });
-        }
-    }
-}
diff --git a/leanback/build.gradle b/leanback/build.gradle
index fe04a8a..56b7fc5 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -23,7 +23,6 @@
     sourceSets {
         main.java.srcDirs += [
                 'common',
-                'jbmr2',
                 'kitkat',
                 'api21',
         ]
diff --git a/leanback/jbmr2/androidx/leanback/widget/ShadowHelperJbmr2.java b/leanback/jbmr2/androidx/leanback/widget/ShadowHelperJbmr2.java
deleted file mode 100644
index 49e5532..0000000
--- a/leanback/jbmr2/androidx/leanback/widget/ShadowHelperJbmr2.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-package androidx.leanback.widget;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.RequiresApi;
-import androidx.leanback.R;
-
-@RequiresApi(18)
-class ShadowHelperJbmr2 {
-
-    static class ShadowImpl {
-        View mNormalShadow;
-        View mFocusShadow;
-    }
-
-    /* prepare parent for allowing shadows of a child */
-    public static void prepareParent(ViewGroup parent) {
-        parent.setLayoutMode(ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
-    }
-
-    /* add shadows and return a implementation detail object */
-    public static Object addShadow(ViewGroup shadowContainer) {
-        shadowContainer.setLayoutMode(ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
-        LayoutInflater inflater = LayoutInflater.from(shadowContainer.getContext());
-        inflater.inflate(R.layout.lb_shadow, shadowContainer, true);
-        ShadowImpl impl = new ShadowImpl();
-        impl.mNormalShadow = shadowContainer.findViewById(R.id.lb_shadow_normal);
-        impl.mFocusShadow = shadowContainer.findViewById(R.id.lb_shadow_focused);
-        return impl;
-    }
-
-    /* set shadow focus level 0 for unfocused 1 for fully focused */
-    public static void setShadowFocusLevel(Object impl, float level) {
-        ShadowImpl shadowImpl = (ShadowImpl) impl;
-        shadowImpl.mNormalShadow.setAlpha(1 - level);
-        shadowImpl.mFocusShadow.setAlpha(level);
-    }
-}
diff --git a/leanback/kitkat/androidx/leanback/transition/CustomChangeBounds.java b/leanback/kitkat/androidx/leanback/transition/CustomChangeBounds.java
new file mode 100644
index 0000000..0331b50
--- /dev/null
+++ b/leanback/kitkat/androidx/leanback/transition/CustomChangeBounds.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 androidx.leanback.transition;
+
+import android.animation.Animator;
+import android.transition.ChangeBounds;
+import android.transition.TransitionValues;
+import android.util.SparseIntArray;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.RequiresApi;
+
+import java.util.HashMap;
+
+/**
+ * change bounds that support customized start delay.
+ */
+@RequiresApi(19)
+class CustomChangeBounds extends ChangeBounds {
+
+    int mDefaultStartDelay;
+    // View -> delay
+    final HashMap<View, Integer> mViewStartDelays = new HashMap<View, Integer>();
+    // id -> delay
+    final SparseIntArray mIdStartDelays = new SparseIntArray();
+    // Class.getName() -> delay
+    final HashMap<String, Integer> mClassStartDelays = new HashMap<String, Integer>();
+
+    private int getDelay(View view) {
+        Integer delay = mViewStartDelays.get(view);
+        if (delay != null) {
+            return delay;
+        }
+        int idStartDelay = mIdStartDelays.get(view.getId(), -1);
+        if (idStartDelay != -1) {
+            return idStartDelay;
+        }
+        delay = mClassStartDelays.get(view.getClass().getName());
+        if (delay != null) {
+            return delay;
+        }
+        return mDefaultStartDelay;
+    }
+
+    @Override
+    public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
+            TransitionValues endValues) {
+        Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
+        if (animator != null && endValues != null && endValues.view != null) {
+            animator.setStartDelay(getDelay(endValues.view));
+        }
+        return animator;
+    }
+
+    public void setStartDelay(View view, int startDelay) {
+        mViewStartDelays.put(view, startDelay);
+    }
+
+    public void setStartDelay(int viewId, int startDelay) {
+        mIdStartDelays.put(viewId, startDelay);
+    }
+
+    public void setStartDelay(String className, int startDelay) {
+        mClassStartDelays.put(className, startDelay);
+    }
+
+    public void setDefaultStartDelay(int startDelay) {
+        mDefaultStartDelay = startDelay;
+    }
+}
diff --git a/leanback/kitkat/androidx/leanback/transition/LeanbackTransitionHelperKitKat.java b/leanback/kitkat/androidx/leanback/transition/LeanbackTransitionHelperKitKat.java
deleted file mode 100644
index 49e16b1..0000000
--- a/leanback/kitkat/androidx/leanback/transition/LeanbackTransitionHelperKitKat.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-package androidx.leanback.transition;
-
-import android.content.Context;
-import android.view.Gravity;
-import android.view.animation.AnimationUtils;
-
-import androidx.annotation.RequiresApi;
-import androidx.leanback.R;
-
-@RequiresApi(19)
-class LeanbackTransitionHelperKitKat {
-
-    static public Object loadTitleInTransition(Context context) {
-        SlideKitkat slide = new SlideKitkat();
-        slide.setSlideEdge(Gravity.TOP);
-        slide.setInterpolator(AnimationUtils.loadInterpolator(context,
-                android.R.anim.decelerate_interpolator));
-        slide.addTarget(R.id.browse_title_group);
-        return slide;
-    }
-
-    static public Object loadTitleOutTransition(Context context) {
-        SlideKitkat slide = new SlideKitkat();
-        slide.setSlideEdge(Gravity.TOP);
-        slide.setInterpolator(AnimationUtils.loadInterpolator(context,
-                R.anim.lb_decelerator_4));
-        slide.addTarget(R.id.browse_title_group);
-        return slide;
-    }
-
-}
diff --git a/leanback/kitkat/androidx/leanback/transition/TransitionHelperKitkat.java b/leanback/kitkat/androidx/leanback/transition/TransitionHelperKitkat.java
deleted file mode 100644
index ae1ca02..0000000
--- a/leanback/kitkat/androidx/leanback/transition/TransitionHelperKitkat.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * 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.
- */
-package androidx.leanback.transition;
-
-import android.animation.Animator;
-import android.animation.TimeInterpolator;
-import android.content.Context;
-import android.transition.AutoTransition;
-import android.transition.ChangeBounds;
-import android.transition.Fade;
-import android.transition.Scene;
-import android.transition.Transition;
-import android.transition.TransitionInflater;
-import android.transition.TransitionManager;
-import android.transition.TransitionSet;
-import android.transition.TransitionValues;
-import android.util.SparseIntArray;
-import android.view.View;
-import android.view.ViewGroup;
-
-import androidx.annotation.RequiresApi;
-
-import java.util.HashMap;
-
-@RequiresApi(19)
-final class TransitionHelperKitkat {
-
-    TransitionHelperKitkat() {
-    }
-
-    static Object createScene(ViewGroup sceneRoot, Runnable enterAction) {
-        Scene scene = new Scene(sceneRoot);
-        scene.setEnterAction(enterAction);
-        return scene;
-    }
-
-    static Object createTransitionSet(boolean sequential) {
-        TransitionSet set = new TransitionSet();
-        set.setOrdering(sequential ? TransitionSet.ORDERING_SEQUENTIAL :
-            TransitionSet.ORDERING_TOGETHER);
-        return set;
-    }
-
-    static void addTransition(Object transitionSet, Object transition) {
-        ((TransitionSet) transitionSet).addTransition((Transition) transition);
-    }
-
-    static Object createAutoTransition() {
-        return new AutoTransition();
-    }
-
-    static Object createSlide(int slideEdge) {
-        SlideKitkat slide = new SlideKitkat();
-        slide.setSlideEdge(slideEdge);
-        return slide;
-    }
-
-    static Object createScale() {
-        Scale scale = new Scale();
-        return scale;
-    }
-
-    static Object createFadeTransition(int fadingMode) {
-        Fade fade = new Fade(fadingMode);
-        return fade;
-    }
-
-    /**
-     * change bounds that support customized start delay.
-     */
-    static class CustomChangeBounds extends ChangeBounds {
-
-        int mDefaultStartDelay;
-        // View -> delay
-        final HashMap<View, Integer> mViewStartDelays = new HashMap<View, Integer>();
-        // id -> delay
-        final SparseIntArray mIdStartDelays = new SparseIntArray();
-        // Class.getName() -> delay
-        final HashMap<String, Integer> mClassStartDelays = new HashMap<String, Integer>();
-
-        private int getDelay(View view) {
-            Integer delay = mViewStartDelays.get(view);
-            if (delay != null) {
-                return delay;
-            }
-            int idStartDelay = mIdStartDelays.get(view.getId(), -1);
-            if (idStartDelay != -1) {
-                return idStartDelay;
-            }
-            delay = mClassStartDelays.get(view.getClass().getName());
-            if (delay != null) {
-                return delay;
-            }
-            return mDefaultStartDelay;
-        }
-
-        @Override
-        public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues,
-                TransitionValues endValues) {
-            Animator animator = super.createAnimator(sceneRoot, startValues, endValues);
-            if (animator != null && endValues != null && endValues.view != null) {
-                animator.setStartDelay(getDelay(endValues.view));
-            }
-            return animator;
-        }
-
-        public void setStartDelay(View view, int startDelay) {
-            mViewStartDelays.put(view, startDelay);
-        }
-
-        public void setStartDelay(int viewId, int startDelay) {
-            mIdStartDelays.put(viewId, startDelay);
-        }
-
-        public void setStartDelay(String className, int startDelay) {
-            mClassStartDelays.put(className, startDelay);
-        }
-
-        public void setDefaultStartDelay(int startDelay) {
-            mDefaultStartDelay = startDelay;
-        }
-    }
-
-    static Object createChangeBounds(boolean reparent) {
-        CustomChangeBounds changeBounds = new CustomChangeBounds();
-        changeBounds.setReparent(reparent);
-        return changeBounds;
-    }
-
-    static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
-        ((CustomChangeBounds) changeBounds).setStartDelay(viewId, startDelay);
-    }
-
-    static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
-        ((CustomChangeBounds) changeBounds).setStartDelay(view, startDelay);
-    }
-
-    static void setChangeBoundsStartDelay(Object changeBounds, String className, int startDelay) {
-        ((CustomChangeBounds) changeBounds).setStartDelay(className, startDelay);
-    }
-
-    static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
-        ((CustomChangeBounds) changeBounds).setDefaultStartDelay(startDelay);
-    }
-
-    static void setStartDelay(Object transition, long startDelay) {
-        ((Transition)transition).setStartDelay(startDelay);
-    }
-
-    static void setDuration(Object transition, long duration) {
-        ((Transition)transition).setDuration(duration);
-    }
-
-    static void exclude(Object transition, int targetId, boolean exclude) {
-        ((Transition) transition).excludeTarget(targetId, exclude);
-    }
-
-    static void exclude(Object transition, View targetView, boolean exclude) {
-        ((Transition) transition).excludeTarget(targetView, exclude);
-    }
-
-    static void excludeChildren(Object transition, int targetId, boolean exclude) {
-        ((Transition) transition).excludeChildren(targetId, exclude);
-    }
-
-    static void excludeChildren(Object transition, View targetView, boolean exclude) {
-        ((Transition) transition).excludeChildren(targetView, exclude);
-    }
-
-    static void include(Object transition, int targetId) {
-        ((Transition) transition).addTarget(targetId);
-    }
-
-    static void include(Object transition, View targetView) {
-        ((Transition) transition).addTarget(targetView);
-    }
-
-    static void addTransitionListener(Object transition, final TransitionListener listener) {
-        if (listener == null) {
-            return;
-        }
-        Transition t = (Transition) transition;
-        listener.mImpl = new Transition.TransitionListener() {
-
-            @Override
-            public void onTransitionStart(Transition transition) {
-                listener.onTransitionStart(transition);
-            }
-
-            @Override
-            public void onTransitionResume(Transition transition) {
-                listener.onTransitionResume(transition);
-            }
-
-            @Override
-            public void onTransitionPause(Transition transition) {
-                listener.onTransitionPause(transition);
-            }
-
-            @Override
-            public void onTransitionEnd(Transition transition) {
-                listener.onTransitionEnd(transition);
-            }
-
-            @Override
-            public void onTransitionCancel(Transition transition) {
-                listener.onTransitionCancel(transition);
-            }
-        };
-        t.addListener((Transition.TransitionListener) listener.mImpl);
-    }
-
-    static void removeTransitionListener(Object transition, final TransitionListener listener) {
-        if (listener == null || listener.mImpl == null) {
-            return;
-        }
-        Transition t = (Transition) transition;
-        t.removeListener((Transition.TransitionListener) listener.mImpl);
-        listener.mImpl = null;
-    }
-
-    static void runTransition(Object scene, Object transition) {
-        TransitionManager.go((Scene) scene, (Transition) transition);
-    }
-
-    static void setInterpolator(Object transition, Object timeInterpolator) {
-        ((Transition) transition).setInterpolator((TimeInterpolator) timeInterpolator);
-    }
-
-    static void addTarget(Object transition, View view) {
-        ((Transition) transition).addTarget(view);
-    }
-
-    static Object loadTransition(Context context, int resId) {
-        return TransitionInflater.from(context).inflateTransition(resId);
-    }
-}
diff --git a/leanback/src/main/java/androidx/leanback/app/FragmentUtil.java b/leanback/src/main/java/androidx/leanback/app/FragmentUtil.java
index 84ff0b7..8d042e8 100644
--- a/leanback/src/main/java/androidx/leanback/app/FragmentUtil.java
+++ b/leanback/src/main/java/androidx/leanback/app/FragmentUtil.java
@@ -19,20 +19,11 @@
 import android.content.Context;
 import android.os.Build;
 
-import androidx.annotation.RequiresApi;
-
 class FragmentUtil {
-
-    @RequiresApi(23)
-    private static Context getContextNew(Fragment fragment) {
-        return fragment.getContext();
-    }
-
-    public static Context getContext(Fragment fragment) {
+    static Context getContext(Fragment fragment) {
         if (Build.VERSION.SDK_INT >= 23) {
-            return getContextNew(fragment);
-        } else {
-            return fragment.getActivity();
+            return fragment.getContext();
         }
+        return fragment.getActivity();
     }
 }
diff --git a/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java b/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
index 4ea8986..3215c98 100644
--- a/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
+++ b/leanback/src/main/java/androidx/leanback/app/GuidedStepSupportFragment.java
@@ -556,7 +556,7 @@
                                                            String transitionName)
     {
         if (subView != null)
-            TransitionHelper.addSharedElement(ft, subView, transitionName);
+            ft.addSharedElement(subView, transitionName);
     }
 
     /**
@@ -897,7 +897,7 @@
                 TransitionHelper.exclude(enterTransition, R.id.guidedstep_background, true);
                 TransitionHelper.exclude(enterTransition, R.id.guidedactions_sub_list_background,
                         true);
-                TransitionHelper.setEnterTransition(this, enterTransition);
+                setEnterTransition(enterTransition);
 
                 Object fade = TransitionHelper.createFadeTransition(
                         TransitionHelper.FADE_IN | TransitionHelper.FADE_OUT);
@@ -906,7 +906,7 @@
                 Object sharedElementTransition = TransitionHelper.createTransitionSet(false);
                 TransitionHelper.addTransition(sharedElementTransition, fade);
                 TransitionHelper.addTransition(sharedElementTransition, changeBounds);
-                TransitionHelper.setSharedElementEnterTransition(this, sharedElementTransition);
+                setSharedElementEnterTransition(sharedElementTransition);
             } else if (uiStyle == UI_STYLE_ENTRANCE) {
                 if (entranceTransitionType == SLIDE_FROM_SIDE) {
                     Object fade = TransitionHelper.createFadeTransition(
@@ -919,29 +919,29 @@
                     Object enterTransition = TransitionHelper.createTransitionSet(false);
                     TransitionHelper.addTransition(enterTransition, fade);
                     TransitionHelper.addTransition(enterTransition, slideFromSide);
-                    TransitionHelper.setEnterTransition(this, enterTransition);
+                    setEnterTransition(enterTransition);
                 } else {
                     Object slideFromBottom = TransitionHelper.createFadeAndShortSlide(
                             Gravity.BOTTOM);
                     TransitionHelper.include(slideFromBottom, R.id.guidedstep_background_view_root);
                     Object enterTransition = TransitionHelper.createTransitionSet(false);
                     TransitionHelper.addTransition(enterTransition, slideFromBottom);
-                    TransitionHelper.setEnterTransition(this, enterTransition);
+                    setEnterTransition(enterTransition);
                 }
                 // No shared element transition
-                TransitionHelper.setSharedElementEnterTransition(this, null);
+                setSharedElementEnterTransition(null);
             } else if (uiStyle == UI_STYLE_ACTIVITY_ROOT) {
                 // for Activity root, we don't need enter transition, use activity transition
-                TransitionHelper.setEnterTransition(this, null);
+                setEnterTransition(null);
                 // No shared element transition
-                TransitionHelper.setSharedElementEnterTransition(this, null);
+                setSharedElementEnterTransition(null);
             }
             // exitTransition is same for all style
             Object exitTransition = TransitionHelper.createFadeAndShortSlide(Gravity.START);
             TransitionHelper.exclude(exitTransition, R.id.guidedstep_background, true);
             TransitionHelper.exclude(exitTransition, R.id.guidedactions_sub_list_background,
                     true);
-            TransitionHelper.setExitTransition(this, exitTransition);
+            setExitTransition(exitTransition);
         }
     }
 
diff --git a/leanback/src/main/java/androidx/leanback/app/PermissionHelper.java b/leanback/src/main/java/androidx/leanback/app/PermissionHelper.java
index 7ee619e..73d1a05 100644
--- a/leanback/src/main/java/androidx/leanback/app/PermissionHelper.java
+++ b/leanback/src/main/java/androidx/leanback/app/PermissionHelper.java
@@ -18,7 +18,6 @@
 import android.os.Build;
 
 import androidx.annotation.RestrictTo;
-import androidx.fragment.app.Fragment;
 
 /**
  * @hide
@@ -33,9 +32,4 @@
         }
     }
 
-    public static void requestPermissions(Fragment fragment,
-            String[] permissions, int requestCode) {
-        fragment.requestPermissions(permissions, requestCode);
-    }
-
 }
diff --git a/leanback/src/main/java/androidx/leanback/app/SearchSupportFragment.java b/leanback/src/main/java/androidx/leanback/app/SearchSupportFragment.java
index 60c0db8..2d1d29e 100644
--- a/leanback/src/main/java/androidx/leanback/app/SearchSupportFragment.java
+++ b/leanback/src/main/java/androidx/leanback/app/SearchSupportFragment.java
@@ -232,8 +232,8 @@
             new SearchBar.SearchBarPermissionListener() {
         @Override
         public void requestAudioPermission() {
-            PermissionHelper.requestPermissions(SearchSupportFragment.this,
-                    new String[]{Manifest.permission.RECORD_AUDIO}, AUDIO_PERMISSION_REQUEST_CODE);
+            requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},
+                    AUDIO_PERMISSION_REQUEST_CODE);
         }
     };
 
diff --git a/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java b/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
index 7b373be..a259050 100644
--- a/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
+++ b/leanback/src/main/java/androidx/leanback/transition/LeanbackTransitionHelper.java
@@ -17,8 +17,9 @@
 
 import android.content.Context;
 import android.os.Build;
+import android.view.Gravity;
+import android.view.animation.AnimationUtils;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.leanback.R;
 
@@ -29,63 +30,29 @@
 @RestrictTo(LIBRARY_GROUP)
 public class LeanbackTransitionHelper {
 
-    interface LeanbackTransitionHelperVersion {
-        Object loadTitleInTransition(Context context);
-        Object loadTitleOutTransition(Context context);
-    }
-
-    /*
-     * Kitkat does not allow load custom transition from resource, calling
-     * LeanbackTransitionHelperKitKat to build custom transition in code.
-     */
-    @RequiresApi(19)
-    static class LeanbackTransitionHelperKitKatImpl implements LeanbackTransitionHelperVersion {
-
-        @Override
-        public Object loadTitleInTransition(Context context) {
-            return LeanbackTransitionHelperKitKat.loadTitleInTransition(context);
-        }
-
-        @Override
-        public Object loadTitleOutTransition(Context context) {
-            return LeanbackTransitionHelperKitKat.loadTitleOutTransition(context);
-        }
-    }
-
-    /*
-     * Load transition from resource or just return stub for API17.
-     */
-    static class LeanbackTransitionHelperDefault implements LeanbackTransitionHelperVersion {
-
-        @Override
-        public Object loadTitleInTransition(Context context) {
+    public static Object loadTitleInTransition(Context context) {
+        if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 21) {
             return TransitionHelper.loadTransition(context, R.transition.lb_title_in);
         }
 
-        @Override
-        public Object loadTitleOutTransition(Context context) {
+        SlideKitkat slide = new SlideKitkat();
+        slide.setSlideEdge(Gravity.TOP);
+        slide.setInterpolator(AnimationUtils.loadInterpolator(context,
+                android.R.anim.decelerate_interpolator));
+        slide.addTarget(R.id.browse_title_group);
+        return slide;
+    }
+
+    public static Object loadTitleOutTransition(Context context) {
+        if (Build.VERSION.SDK_INT < 19 || Build.VERSION.SDK_INT >= 21) {
             return TransitionHelper.loadTransition(context, R.transition.lb_title_out);
         }
-    }
 
-    static LeanbackTransitionHelperVersion sImpl;
-
-    static {
-        if (Build.VERSION.SDK_INT >= 21) {
-            sImpl = new LeanbackTransitionHelperDefault();
-        } else if (Build.VERSION.SDK_INT >= 19) {
-            sImpl = new LeanbackTransitionHelperKitKatImpl();
-        } else {
-            // Helper will create a stub object for transition in this case.
-            sImpl = new LeanbackTransitionHelperDefault();
-        }
-    }
-
-    static public Object loadTitleInTransition(Context context) {
-        return sImpl.loadTitleInTransition(context);
-    }
-
-    static public Object loadTitleOutTransition(Context context) {
-        return sImpl.loadTitleOutTransition(context);
+        SlideKitkat slide = new SlideKitkat();
+        slide.setSlideEdge(Gravity.TOP);
+        slide.setInterpolator(AnimationUtils.loadInterpolator(context,
+                R.anim.lb_decelerator_4));
+        slide.addTarget(R.id.browse_title_group);
+        return slide;
     }
 }
diff --git a/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java b/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
index b829587..084e1e7 100644
--- a/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
+++ b/leanback/src/main/java/androidx/leanback/transition/TransitionHelper.java
@@ -15,17 +15,24 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import android.animation.TimeInterpolator;
 import android.content.Context;
+import android.graphics.Rect;
 import android.os.Build;
-import android.view.Gravity;
+import android.transition.AutoTransition;
+import android.transition.ChangeTransform;
+import android.transition.Fade;
+import android.transition.Scene;
+import android.transition.Transition;
+import android.transition.TransitionInflater;
+import android.transition.TransitionManager;
+import android.transition.TransitionSet;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
+import android.view.animation.AnimationUtils;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentTransaction;
 
 import java.util.ArrayList;
 
@@ -39,23 +46,6 @@
     public static final int FADE_IN = 0x1;
     public static final int FADE_OUT = 0x2;
 
-    public static final int SLIDE_LEFT = Gravity.LEFT;
-    public static final int SLIDE_TOP = Gravity.TOP;
-    public static final int SLIDE_RIGHT = Gravity.RIGHT;
-    public static final int SLIDE_BOTTOM = Gravity.BOTTOM;
-
-    private static TransitionHelperVersionImpl sImpl;
-
-    /**
-     * Gets whether the system supports Transition animations.
-     *
-     * @return True if Transition animations are supported.
-     */
-    public static boolean systemSupportsTransitions() {
-        // Supported on Android 4.4 or later.
-        return Build.VERSION.SDK_INT >= 19;
-    }
-
     /**
      * Returns true if system supports entrance Transition animations.
      */
@@ -63,322 +53,302 @@
         return Build.VERSION.SDK_INT >= 21;
     }
 
-    /**
-     * Interface implemented by classes that support Transition animations.
-     */
-    interface TransitionHelperVersionImpl {
+    private static class TransitionStub {
+        ArrayList<TransitionListener> mTransitionListeners;
 
-        void setEnterTransition(android.app.Fragment fragment, Object transition);
-
-        void setExitTransition(android.app.Fragment fragment, Object transition);
-
-        void setSharedElementEnterTransition(android.app.Fragment fragment,
-                Object transition);
-
-        void addSharedElement(android.app.FragmentTransaction ft,
-                View view, String transitionName);
-
-        Object getSharedElementEnterTransition(Window window);
-
-        void setSharedElementEnterTransition(Window window, Object transition);
-
-        Object getSharedElementReturnTransition(Window window);
-
-        void setSharedElementReturnTransition(Window window, Object transition);
-
-        Object getSharedElementExitTransition(Window window);
-
-        Object getSharedElementReenterTransition(Window window);
-
-        Object getEnterTransition(Window window);
-
-        void setEnterTransition(Window window, Object transition);
-
-        Object getReturnTransition(Window window);
-
-        void setReturnTransition(Window window, Object transition);
-
-        Object getExitTransition(Window window);
-
-        Object getReenterTransition(Window window);
-
-        Object createScene(ViewGroup sceneRoot, Runnable r);
-
-        Object createAutoTransition();
-
-        Object createSlide(int slideEdge);
-
-        Object createScale();
-
-        Object createFadeTransition(int fadingMode);
-
-        Object createChangeTransform();
-
-        Object createChangeBounds(boolean reparent);
-
-        Object createFadeAndShortSlide(int edge);
-
-        Object createFadeAndShortSlide(int edge, float distance);
-
-        void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay);
-
-        void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay);
-
-        void setChangeBoundsStartDelay(Object changeBounds, String className,
-                int startDelay);
-
-        void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay);
-
-        Object createTransitionSet(boolean sequential);
-
-        void addTransition(Object transitionSet, Object transition);
-
-        void addTransitionListener(Object transition, TransitionListener listener);
-
-        void removeTransitionListener(Object transition, TransitionListener listener);
-
-        void runTransition(Object scene, Object transition);
-
-        void exclude(Object transition, int targetId, boolean exclude);
-
-        void exclude(Object transition, View targetView, boolean exclude);
-
-        void excludeChildren(Object transition, int targetId, boolean exclude);
-
-        void excludeChildren(Object transition, View target, boolean exclude);
-
-        void include(Object transition, int targetId);
-
-        void include(Object transition, View targetView);
-
-        void setStartDelay(Object transition, long startDelay);
-
-        void setDuration(Object transition, long duration);
-
-        void setInterpolator(Object transition, Object timeInterpolator);
-
-        void addTarget(Object transition, View view);
-
-        Object createDefaultInterpolator(Context context);
-
-        Object loadTransition(Context context, int resId);
-
-        void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject);
-
-        void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup);
-
-        void setEpicenterCallback(Object transitionObject,
-                TransitionEpicenterCallback callback);
+        TransitionStub() {
+        }
     }
 
-    /**
-     * Interface used when we do not support Transition animations.
-     */
-    static class TransitionHelperStubImpl implements TransitionHelperVersionImpl {
-
-        private static class TransitionStub {
-            ArrayList<TransitionListener> mTransitionListeners;
-
-            TransitionStub() {
-            }
+    public static Object getSharedElementEnterTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getSharedElementEnterTransition();
         }
+        return null;
+    }
 
-        @Override
-        public void setEnterTransition(android.app.Fragment fragment, Object transition) {
+    public static void setSharedElementEnterTransition(Window window, Object transition) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            window.setSharedElementEnterTransition((Transition) transition);
         }
+    }
 
-        @Override
-        public void setExitTransition(android.app.Fragment fragment, Object transition) {
+    public static Object getSharedElementReturnTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getSharedElementReturnTransition();
         }
+        return null;
+    }
 
-        @Override
-        public void setSharedElementEnterTransition(android.app.Fragment fragment,
-                Object transition) {
+    public static void setSharedElementReturnTransition(Window window, Object transition) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            window.setSharedElementReturnTransition((Transition) transition);
         }
+    }
 
-        @Override
-        public void addSharedElement(android.app.FragmentTransaction ft,
-                View view, String transitionName) {
+    public static Object getSharedElementExitTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getSharedElementExitTransition();
         }
+        return null;
+    }
 
-        @Override
-        public Object getSharedElementEnterTransition(Window window) {
-            return null;
+    public static Object getSharedElementReenterTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getSharedElementReenterTransition();
         }
+        return null;
+    }
 
-        @Override
-        public void setSharedElementEnterTransition(Window window, Object object) {
+    public static Object getEnterTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getEnterTransition();
         }
+        return null;
+    }
 
-        @Override
-        public Object getSharedElementReturnTransition(Window window) {
-            return null;
+    public static void setEnterTransition(Window window, Object transition) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            window.setEnterTransition((Transition) transition);
         }
+    }
 
-        @Override
-        public void setSharedElementReturnTransition(Window window, Object transition) {
+    public static Object getReturnTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getReturnTransition();
         }
+        return null;
+    }
 
-        @Override
-        public Object getSharedElementExitTransition(Window window) {
-            return null;
+    public static void setReturnTransition(Window window, Object transition) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            window.setReturnTransition((Transition) transition);
         }
+    }
 
-        @Override
-        public Object getSharedElementReenterTransition(Window window) {
-            return null;
+    public static Object getExitTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getExitTransition();
         }
+        return null;
+    }
 
-        @Override
-        public Object getEnterTransition(Window window) {
-            return null;
+    public static Object getReenterTransition(Window window) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return window.getReenterTransition();
         }
+        return null;
+    }
 
-        @Override
-        public void setEnterTransition(Window window, Object transition) {
+    public static Object createScene(ViewGroup sceneRoot, Runnable r) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            Scene scene = new Scene(sceneRoot);
+            scene.setEnterAction(r);
+            return scene;
         }
+        return r;
+    }
 
-        @Override
-        public Object getReturnTransition(Window window) {
-            return null;
+    public static Object createChangeBounds(boolean reparent) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            CustomChangeBounds changeBounds = new CustomChangeBounds();
+            changeBounds.setReparent(reparent);
+            return changeBounds;
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public void setReturnTransition(Window window, Object transition) {
+    public static Object createChangeTransform() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return new ChangeTransform();
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public Object getExitTransition(Window window) {
-            return null;
+    public static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((CustomChangeBounds) changeBounds).setStartDelay(view, startDelay);
         }
+    }
 
-        @Override
-        public Object getReenterTransition(Window window) {
-            return null;
+    public static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((CustomChangeBounds) changeBounds).setStartDelay(viewId, startDelay);
         }
+    }
 
-        @Override
-        public Object createScene(ViewGroup sceneRoot, Runnable r) {
-            return r;
+    public static void setChangeBoundsStartDelay(Object changeBounds, String className,
+            int startDelay) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((CustomChangeBounds) changeBounds).setStartDelay(className, startDelay);
         }
+    }
 
-        @Override
-        public Object createAutoTransition() {
-            return new TransitionStub();
+    public static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((CustomChangeBounds) changeBounds).setDefaultStartDelay(startDelay);
         }
+    }
 
-        @Override
-        public Object createFadeTransition(int fadingMode) {
-            return new TransitionStub();
+    public static Object createTransitionSet(boolean sequential) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            TransitionSet set = new TransitionSet();
+            set.setOrdering(sequential ? TransitionSet.ORDERING_SEQUENTIAL
+                    : TransitionSet.ORDERING_TOGETHER);
+            return set;
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public Object createChangeBounds(boolean reparent) {
-            return new TransitionStub();
+    public static Object createSlide(int slideEdge) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            SlideKitkat slide = new SlideKitkat();
+            slide.setSlideEdge(slideEdge);
+            return slide;
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public Object createChangeTransform() {
-            return new TransitionStub();
+    public static Object createScale() {
+        if (Build.VERSION.SDK_INT >= 21) {
+            return new ChangeTransform();
         }
-
-        @Override
-        public Object createFadeAndShortSlide(int edge) {
-            return new TransitionStub();
+        if (Build.VERSION.SDK_INT >= 19) {
+            return new Scale();
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public Object createFadeAndShortSlide(int edge, float distance) {
-            return new TransitionStub();
+    public static void addTransition(Object transitionSet, Object transition) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((TransitionSet) transitionSet).addTransition((Transition) transition);
         }
+    }
 
-        @Override
-        public Object createSlide(int slideEdge) {
-            return new TransitionStub();
+    public static void exclude(Object transition, int targetId, boolean exclude) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).excludeTarget(targetId, exclude);
         }
+    }
 
-        @Override
-        public Object createScale() {
-            return new TransitionStub();
+    public static void exclude(Object transition, View targetView, boolean exclude) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).excludeTarget(targetView, exclude);
         }
+    }
 
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
+    public static void excludeChildren(Object transition, int targetId, boolean exclude) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).excludeChildren(targetId, exclude);
         }
+    }
 
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
+    public static void excludeChildren(Object transition, View targetView, boolean exclude) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).excludeChildren(targetView, exclude);
         }
+    }
 
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, String className,
-                int startDelay) {
+    public static void include(Object transition, int targetId) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).addTarget(targetId);
         }
+    }
 
-        @Override
-        public void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
+    public static void include(Object transition, View targetView) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).addTarget(targetView);
         }
+    }
 
-        @Override
-        public Object createTransitionSet(boolean sequential) {
-            return new TransitionStub();
+    public static void setStartDelay(Object transition, long startDelay) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).setStartDelay(startDelay);
         }
+    }
 
-        @Override
-        public void addTransition(Object transitionSet, Object transition) {
+    public static void setDuration(Object transition, long duration) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).setDuration(duration);
         }
+    }
 
-        @Override
-        public void exclude(Object transition, int targetId, boolean exclude) {
+    public static Object createAutoTransition() {
+        if (Build.VERSION.SDK_INT >= 19) {
+            return new AutoTransition();
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public void exclude(Object transition, View targetView, boolean exclude) {
+    public static Object createFadeTransition(int fadeMode) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            return new Fade(fadeMode);
         }
+        return new TransitionStub();
+    }
 
-        @Override
-        public void excludeChildren(Object transition, int targetId, boolean exclude) {
+    public static void addTransitionListener(Object transition, final TransitionListener listener) {
+        if (listener == null) {
+            return;
         }
+        if (Build.VERSION.SDK_INT >= 19) {
+            Transition t = (Transition) transition;
+            listener.mImpl = new Transition.TransitionListener() {
+                @Override
+                public void onTransitionStart(Transition transition11) {
+                    listener.onTransitionStart(transition11);
+                }
 
-        @Override
-        public void excludeChildren(Object transition, View targetView, boolean exclude) {
-        }
+                @Override
+                public void onTransitionResume(Transition transition11) {
+                    listener.onTransitionResume(transition11);
+                }
 
-        @Override
-        public void include(Object transition, int targetId) {
-        }
+                @Override
+                public void onTransitionPause(Transition transition11) {
+                    listener.onTransitionPause(transition11);
+                }
 
-        @Override
-        public void include(Object transition, View targetView) {
-        }
+                @Override
+                public void onTransitionEnd(Transition transition11) {
+                    listener.onTransitionEnd(transition11);
+                }
 
-        @Override
-        public void setStartDelay(Object transition, long startDelay) {
-        }
-
-        @Override
-        public void setDuration(Object transition, long duration) {
-        }
-
-        @Override
-        public void addTransitionListener(Object transition, TransitionListener listener) {
+                @Override
+                public void onTransitionCancel(Transition transition11) {
+                    listener.onTransitionCancel(transition11);
+                }
+            };
+            t.addListener((Transition.TransitionListener) listener.mImpl);
+        } else {
             TransitionStub stub = (TransitionStub) transition;
             if (stub.mTransitionListeners == null) {
-                stub.mTransitionListeners = new ArrayList<TransitionListener>();
+                stub.mTransitionListeners = new ArrayList<>();
             }
             stub.mTransitionListeners.add(listener);
         }
+    }
 
-        @Override
-        public void removeTransitionListener(Object transition, TransitionListener listener) {
+    public static void removeTransitionListener(Object transition, TransitionListener listener) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            if (listener == null || listener.mImpl == null) {
+                return;
+            }
+            Transition t = (Transition) transition;
+            t.removeListener((Transition.TransitionListener) listener.mImpl);
+            listener.mImpl = null;
+        } else {
             TransitionStub stub = (TransitionStub) transition;
             if (stub.mTransitionListeners != null) {
                 stub.mTransitionListeners.remove(listener);
             }
         }
+    }
 
-        @Override
-        public void runTransition(Object scene, Object transition) {
+    public static void runTransition(Object scene, Object transition) {
+        if (Build.VERSION.SDK_INT >= 19) {
+            TransitionManager.go((Scene) scene, (Transition) transition);
+        } else {
             TransitionStub transitionStub = (TransitionStub) transition;
             if (transitionStub != null && transitionStub.mTransitionListeners != null) {
                 for (int i = 0, size = transitionStub.mTransitionListeners.size(); i < size; i++) {
@@ -395,552 +365,103 @@
                 }
             }
         }
-
-        @Override
-        public void setInterpolator(Object transition, Object timeInterpolator) {
-        }
-
-        @Override
-        public void addTarget(Object transition, View view) {
-        }
-
-        @Override
-        public Object createDefaultInterpolator(Context context) {
-            return null;
-        }
-
-        @Override
-        public Object loadTransition(Context context, int resId) {
-            return new TransitionStub();
-        }
-
-        @Override
-        public void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
-        }
-
-        @Override
-        public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
-        }
-
-        @Override
-        public void setEpicenterCallback(Object transitionObject,
-                TransitionEpicenterCallback callback) {
-        }
-    }
-
-    /**
-     * Implementation used on KitKat (and above).
-     */
-    @RequiresApi(19)
-    static class TransitionHelperKitkatImpl extends TransitionHelperStubImpl {
-
-        @Override
-        public Object createScene(ViewGroup sceneRoot, Runnable r) {
-            return TransitionHelperKitkat.createScene(sceneRoot, r);
-        }
-
-        @Override
-        public Object createAutoTransition() {
-            return TransitionHelperKitkat.createAutoTransition();
-        }
-
-        @Override
-        public Object createFadeTransition(int fadingMode) {
-            return TransitionHelperKitkat.createFadeTransition(fadingMode);
-        }
-
-        @Override
-        public Object createChangeBounds(boolean reparent) {
-            return TransitionHelperKitkat.createChangeBounds(reparent);
-        }
-
-        @Override
-        public Object createSlide(int slideEdge) {
-            return TransitionHelperKitkat.createSlide(slideEdge);
-        }
-
-        @Override
-        public Object createScale() {
-            return TransitionHelperKitkat.createScale();
-        }
-
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
-            TransitionHelperKitkat.setChangeBoundsStartDelay(changeBounds, view, startDelay);
-        }
-
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
-            TransitionHelperKitkat.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
-        }
-
-        @Override
-        public void setChangeBoundsStartDelay(Object changeBounds, String className,
-                int startDelay) {
-            TransitionHelperKitkat.setChangeBoundsStartDelay(changeBounds, className, startDelay);
-        }
-
-        @Override
-        public void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
-            TransitionHelperKitkat.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
-        }
-
-        @Override
-        public Object createTransitionSet(boolean sequential) {
-            return TransitionHelperKitkat.createTransitionSet(sequential);
-        }
-
-        @Override
-        public void addTransition(Object transitionSet, Object transition) {
-            TransitionHelperKitkat.addTransition(transitionSet, transition);
-        }
-
-        @Override
-        public void exclude(Object transition, int targetId, boolean exclude) {
-            TransitionHelperKitkat.exclude(transition, targetId, exclude);
-        }
-
-        @Override
-        public void exclude(Object transition, View targetView, boolean exclude) {
-            TransitionHelperKitkat.exclude(transition, targetView, exclude);
-        }
-
-        @Override
-        public void excludeChildren(Object transition, int targetId, boolean exclude) {
-            TransitionHelperKitkat.excludeChildren(transition, targetId, exclude);
-        }
-
-        @Override
-        public void excludeChildren(Object transition, View targetView, boolean exclude) {
-            TransitionHelperKitkat.excludeChildren(transition, targetView, exclude);
-        }
-
-        @Override
-        public void include(Object transition, int targetId) {
-            TransitionHelperKitkat.include(transition, targetId);
-        }
-
-        @Override
-        public void include(Object transition, View targetView) {
-            TransitionHelperKitkat.include(transition, targetView);
-        }
-
-        @Override
-        public void setStartDelay(Object transition, long startDelay) {
-            TransitionHelperKitkat.setStartDelay(transition, startDelay);
-        }
-
-        @Override
-        public void setDuration(Object transition, long duration) {
-            TransitionHelperKitkat.setDuration(transition, duration);
-        }
-
-        @Override
-        public void addTransitionListener(Object transition, TransitionListener listener) {
-            TransitionHelperKitkat.addTransitionListener(transition, listener);
-        }
-
-        @Override
-        public void removeTransitionListener(Object transition, TransitionListener listener) {
-            TransitionHelperKitkat.removeTransitionListener(transition, listener);
-        }
-
-        @Override
-        public void runTransition(Object scene, Object transition) {
-            TransitionHelperKitkat.runTransition(scene, transition);
-        }
-
-        @Override
-        public void setInterpolator(Object transition, Object timeInterpolator) {
-            TransitionHelperKitkat.setInterpolator(transition, timeInterpolator);
-        }
-
-        @Override
-        public void addTarget(Object transition, View view) {
-            TransitionHelperKitkat.addTarget(transition, view);
-        }
-
-        @Override
-        public Object createDefaultInterpolator(Context context) {
-            return null;
-        }
-
-        @Override
-        public Object loadTransition(Context context, int resId) {
-            return TransitionHelperKitkat.loadTransition(context, resId);
-        }
-    }
-
-    @RequiresApi(21)
-    static final class TransitionHelperApi21Impl extends TransitionHelperKitkatImpl {
-
-        @Override
-        public void setEnterTransition(android.app.Fragment fragment, Object transition) {
-            TransitionHelperApi21.setEnterTransition(fragment, transition);
-        }
-
-        @Override
-        public void setExitTransition(android.app.Fragment fragment, Object transition) {
-            TransitionHelperApi21.setExitTransition(fragment, transition);
-        }
-
-        @Override
-        public void setSharedElementEnterTransition(android.app.Fragment fragment,
-                Object transition) {
-            TransitionHelperApi21.setSharedElementEnterTransition(fragment, transition);
-        }
-
-        @Override
-        public void addSharedElement(android.app.FragmentTransaction ft,
-                View view, String transitionName) {
-            TransitionHelperApi21.addSharedElement(ft, view, transitionName);
-        }
-
-        @Override
-        public Object getSharedElementEnterTransition(Window window) {
-            return TransitionHelperApi21.getSharedElementEnterTransition(window);
-        }
-
-        @Override
-        public void setSharedElementEnterTransition(Window window, Object object) {
-            TransitionHelperApi21.setSharedElementEnterTransition(window, object);
-        }
-
-        @Override
-        public Object getSharedElementReturnTransition(Window window) {
-            return TransitionHelperApi21.getSharedElementReturnTransition(window);
-        }
-
-        @Override
-        public void setSharedElementReturnTransition(Window window, Object transition) {
-            TransitionHelperApi21.setSharedElementReturnTransition(window, transition);
-        }
-
-        @Override
-        public Object getSharedElementExitTransition(Window window) {
-            return TransitionHelperApi21.getSharedElementExitTransition(window);
-        }
-
-        @Override
-        public Object getSharedElementReenterTransition(Window window) {
-            return TransitionHelperApi21.getSharedElementReenterTransition(window);
-        }
-
-        @Override
-        public Object createFadeAndShortSlide(int edge) {
-            return TransitionHelperApi21.createFadeAndShortSlide(edge);
-        }
-
-        @Override
-        public Object createFadeAndShortSlide(int edge, float distance) {
-            return TransitionHelperApi21.createFadeAndShortSlide(edge, distance);
-        }
-
-        @Override
-        public void beginDelayedTransition(ViewGroup sceneRoot, Object transition) {
-            TransitionHelperApi21.beginDelayedTransition(sceneRoot, transition);
-        }
-
-        @Override
-        public Object getEnterTransition(Window window) {
-            return TransitionHelperApi21.getEnterTransition(window);
-        }
-
-        @Override
-        public void setEnterTransition(Window window, Object transition) {
-            TransitionHelperApi21.setEnterTransition(window, transition);
-        }
-
-        @Override
-        public Object getReturnTransition(Window window) {
-            return TransitionHelperApi21.getReturnTransition(window);
-        }
-
-        @Override
-        public void setReturnTransition(Window window, Object transition) {
-            TransitionHelperApi21.setReturnTransition(window, transition);
-        }
-
-        @Override
-        public Object getExitTransition(Window window) {
-            return TransitionHelperApi21.getExitTransition(window);
-        }
-
-        @Override
-        public Object getReenterTransition(Window window) {
-            return TransitionHelperApi21.getReenterTransition(window);
-        }
-
-        @Override
-        public Object createScale() {
-            return TransitionHelperApi21.createScale();
-        }
-
-        @Override
-        public Object createDefaultInterpolator(Context context) {
-            return TransitionHelperApi21.createDefaultInterpolator(context);
-        }
-
-        @Override
-        public void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
-            TransitionHelperApi21.setTransitionGroup(viewGroup, transitionGroup);
-        }
-
-        @Override
-        public Object createChangeTransform() {
-            return TransitionHelperApi21.createChangeTransform();
-        }
-
-        @Override
-        public void setEpicenterCallback(Object transitionObject,
-                TransitionEpicenterCallback callback) {
-            TransitionHelperApi21.setEpicenterCallback(transitionObject, callback);
-        }
-    }
-
-    static {
-        if (Build.VERSION.SDK_INT >= 21) {
-            sImpl = new TransitionHelperApi21Impl();
-        } else  if (systemSupportsTransitions()) {
-            sImpl = new TransitionHelperKitkatImpl();
-        } else {
-            sImpl = new TransitionHelperStubImpl();
-        }
-    }
-
-    public static Object getSharedElementEnterTransition(Window window) {
-        return sImpl.getSharedElementEnterTransition(window);
-    }
-
-    public static void setSharedElementEnterTransition(Window window, Object transition) {
-        sImpl.setSharedElementEnterTransition(window, transition);
-    }
-
-    public static Object getSharedElementReturnTransition(Window window) {
-        return sImpl.getSharedElementReturnTransition(window);
-    }
-
-    public static void setSharedElementReturnTransition(Window window, Object transition) {
-        sImpl.setSharedElementReturnTransition(window, transition);
-    }
-
-    public static Object getSharedElementExitTransition(Window window) {
-        return sImpl.getSharedElementExitTransition(window);
-    }
-
-    public static Object getSharedElementReenterTransition(Window window) {
-        return sImpl.getSharedElementReenterTransition(window);
-    }
-
-    public static Object getEnterTransition(Window window) {
-        return sImpl.getEnterTransition(window);
-    }
-
-    public static void setEnterTransition(Window window, Object transition) {
-        sImpl.setEnterTransition(window, transition);
-    }
-
-    public static Object getReturnTransition(Window window) {
-        return sImpl.getReturnTransition(window);
-    }
-
-    public static void setReturnTransition(Window window, Object transition) {
-        sImpl.setReturnTransition(window, transition);
-    }
-
-    public static Object getExitTransition(Window window) {
-        return sImpl.getExitTransition(window);
-    }
-
-    public static Object getReenterTransition(Window window) {
-        return sImpl.getReenterTransition(window);
-    }
-
-    public static Object createScene(ViewGroup sceneRoot, Runnable r) {
-        return sImpl.createScene(sceneRoot, r);
-    }
-
-    public static Object createChangeBounds(boolean reparent) {
-        return sImpl.createChangeBounds(reparent);
-    }
-
-    public static Object createChangeTransform() {
-        return sImpl.createChangeTransform();
-    }
-
-    public static void setChangeBoundsStartDelay(Object changeBounds, View view, int startDelay) {
-        sImpl.setChangeBoundsStartDelay(changeBounds, view, startDelay);
-    }
-
-    public static void setChangeBoundsStartDelay(Object changeBounds, int viewId, int startDelay) {
-        sImpl.setChangeBoundsStartDelay(changeBounds, viewId, startDelay);
-    }
-
-    public static void setChangeBoundsStartDelay(Object changeBounds, String className,
-            int startDelay) {
-        sImpl.setChangeBoundsStartDelay(changeBounds, className, startDelay);
-    }
-
-    public static void setChangeBoundsDefaultStartDelay(Object changeBounds, int startDelay) {
-        sImpl.setChangeBoundsDefaultStartDelay(changeBounds, startDelay);
-    }
-
-    public static Object createTransitionSet(boolean sequential) {
-        return sImpl.createTransitionSet(sequential);
-    }
-
-    public static Object createSlide(int slideEdge) {
-        return sImpl.createSlide(slideEdge);
-    }
-
-    public static Object createScale() {
-        return sImpl.createScale();
-    }
-
-    public static void addTransition(Object transitionSet, Object transition) {
-        sImpl.addTransition(transitionSet, transition);
-    }
-
-    public static void exclude(Object transition, int targetId, boolean exclude) {
-        sImpl.exclude(transition, targetId, exclude);
-    }
-
-    public static void exclude(Object transition, View targetView, boolean exclude) {
-        sImpl.exclude(transition, targetView, exclude);
-    }
-
-    public static void excludeChildren(Object transition, int targetId, boolean exclude) {
-        sImpl.excludeChildren(transition, targetId, exclude);
-    }
-
-    public static void excludeChildren(Object transition, View targetView, boolean exclude) {
-        sImpl.excludeChildren(transition, targetView, exclude);
-    }
-
-    public static void include(Object transition, int targetId) {
-        sImpl.include(transition, targetId);
-    }
-
-    public static void include(Object transition, View targetView) {
-        sImpl.include(transition, targetView);
-    }
-
-    public static void setStartDelay(Object transition, long startDelay) {
-        sImpl.setStartDelay(transition, startDelay);
-    }
-
-    public static void setDuration(Object transition, long duration) {
-        sImpl.setDuration(transition, duration);
-    }
-
-    public static Object createAutoTransition() {
-        return sImpl.createAutoTransition();
-    }
-
-    public static Object createFadeTransition(int fadeMode) {
-        return sImpl.createFadeTransition(fadeMode);
-    }
-
-    public static void addTransitionListener(Object transition, TransitionListener listener) {
-        sImpl.addTransitionListener(transition, listener);
-    }
-
-    public static void removeTransitionListener(Object transition, TransitionListener listener) {
-        sImpl.removeTransitionListener(transition, listener);
-    }
-
-    public static void runTransition(Object scene, Object transition) {
-        sImpl.runTransition(scene, transition);
     }
 
     public static void setInterpolator(Object transition, Object timeInterpolator) {
-        sImpl.setInterpolator(transition, timeInterpolator);
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).setInterpolator((TimeInterpolator) timeInterpolator);
+        }
     }
 
     public static void addTarget(Object transition, View view) {
-        sImpl.addTarget(transition, view);
+        if (Build.VERSION.SDK_INT >= 19) {
+            ((Transition) transition).addTarget(view);
+        }
     }
 
     public static Object createDefaultInterpolator(Context context) {
-        return sImpl.createDefaultInterpolator(context);
+        if (Build.VERSION.SDK_INT >= 21) {
+            return AnimationUtils.loadInterpolator(context,
+                    android.R.interpolator.fast_out_linear_in);
+        }
+        return null;
     }
 
     public static Object loadTransition(Context context, int resId) {
-        return sImpl.loadTransition(context, resId);
+        if (Build.VERSION.SDK_INT >= 19) {
+            return TransitionInflater.from(context).inflateTransition(resId);
+        }
+        return new TransitionStub();
     }
 
     public static void setEnterTransition(android.app.Fragment fragment, Object transition) {
-        sImpl.setEnterTransition(fragment, transition);
+        if (Build.VERSION.SDK_INT >= 21) {
+            fragment.setEnterTransition((Transition) transition);
+        }
     }
 
     public static void setExitTransition(android.app.Fragment fragment, Object transition) {
-        sImpl.setExitTransition(fragment, transition);
+        if (Build.VERSION.SDK_INT >= 21) {
+            fragment.setExitTransition((Transition) transition);
+        }
     }
 
     public static void setSharedElementEnterTransition(android.app.Fragment fragment,
             Object transition) {
-        sImpl.setSharedElementEnterTransition(fragment, transition);
+        if (Build.VERSION.SDK_INT >= 21) {
+            fragment.setSharedElementEnterTransition((Transition) transition);
+        }
     }
 
     public static void addSharedElement(android.app.FragmentTransaction ft,
             View view, String transitionName) {
-        sImpl.addSharedElement(ft, view, transitionName);
-    }
-
-    public static void setEnterTransition(Fragment fragment,
-            Object transition) {
-        fragment.setEnterTransition(transition);
-    }
-
-    public static void setExitTransition(Fragment fragment,
-            Object transition) {
-        fragment.setExitTransition(transition);
-    }
-
-    public static void setSharedElementEnterTransition(Fragment fragment,
-            Object transition) {
-        fragment.setSharedElementEnterTransition(transition);
-    }
-
-    public static void addSharedElement(FragmentTransaction ft,
-            View view, String transitionName) {
-        ft.addSharedElement(view, transitionName);
+        if (Build.VERSION.SDK_INT >= 21) {
+            ft.addSharedElement(view, transitionName);
+        }
     }
 
     public static Object createFadeAndShortSlide(int edge) {
-        return sImpl.createFadeAndShortSlide(edge);
+        if (Build.VERSION.SDK_INT >= 21) {
+            return new FadeAndShortSlide(edge);
+        }
+        return new TransitionStub();
     }
 
     public static Object createFadeAndShortSlide(int edge, float distance) {
-        return sImpl.createFadeAndShortSlide(edge, distance);
+        if (Build.VERSION.SDK_INT >= 21) {
+            FadeAndShortSlide slide = new FadeAndShortSlide(edge);
+            slide.setDistance(distance);
+            return slide;
+        }
+        return new TransitionStub();
     }
 
     public static void beginDelayedTransition(ViewGroup sceneRoot, Object transitionObject) {
-        sImpl.beginDelayedTransition(sceneRoot, transitionObject);
+        if (Build.VERSION.SDK_INT >= 21) {
+            Transition transition = (Transition) transitionObject;
+            TransitionManager.beginDelayedTransition(sceneRoot, transition);
+        }
     }
 
     public static void setTransitionGroup(ViewGroup viewGroup, boolean transitionGroup) {
-        sImpl.setTransitionGroup(viewGroup, transitionGroup);
+        if (Build.VERSION.SDK_INT >= 21) {
+            viewGroup.setTransitionGroup(transitionGroup);
+        }
     }
 
     public static void setEpicenterCallback(Object transition,
-            TransitionEpicenterCallback callback) {
-        sImpl.setEpicenterCallback(transition, callback);
-    }
-
-    /**
-     * @deprecated Use static calls.
-     */
-    @Deprecated
-    public static TransitionHelper getInstance() {
-        return new TransitionHelper();
-    }
-
-    /**
-     * @deprecated Use {@link #addTransitionListener(Object, TransitionListener)}
-     */
-    @Deprecated
-    public static void setTransitionListener(Object transition, TransitionListener listener) {
-        sImpl.addTransitionListener(transition, listener);
+            final TransitionEpicenterCallback callback) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            if (callback == null) {
+                ((Transition) transition).setEpicenterCallback(null);
+            } else {
+                ((Transition) transition).setEpicenterCallback(new Transition.EpicenterCallback() {
+                    @Override
+                    public Rect onGetEpicenter(Transition transition11) {
+                        return callback.onGetEpicenter(transition11);
+                    }
+                });
+            }
+        }
     }
 }
diff --git a/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayContainer.java b/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayContainer.java
index 20abd7f..b0b45de 100644
--- a/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayContainer.java
+++ b/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayContainer.java
@@ -119,7 +119,7 @@
      * Return true if the platform sdk supports shadow.
      */
     public static boolean supportsShadow() {
-        return StaticShadowHelper.getInstance().supportsShadow();
+        return StaticShadowHelper.supportsShadow();
     }
 
     /**
@@ -135,7 +135,7 @@
      * to parent.
      */
     public static void prepareParentForShadow(ViewGroup parent) {
-        StaticShadowHelper.getInstance().prepareParent(parent);
+        StaticShadowHelper.prepareParent(parent);
     }
 
     /**
@@ -226,7 +226,7 @@
                         this, mUnfocusedZ, mFocusedZ, mRoundedCornerRadius);
                 break;
             case SHADOW_STATIC:
-                mShadowImpl = StaticShadowHelper.getInstance().addStaticShadow(this);
+                mShadowImpl = StaticShadowHelper.addStaticShadow(this);
                 break;
         }
         if (hasColorDimOverlay) {
diff --git a/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayHelper.java b/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayHelper.java
index 0299142..1dfd653 100644
--- a/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayHelper.java
+++ b/leanback/src/main/java/androidx/leanback/widget/ShadowOverlayHelper.java
@@ -280,7 +280,7 @@
      * Return true if the platform sdk supports shadow.
      */
     public static boolean supportsShadow() {
-        return StaticShadowHelper.getInstance().supportsShadow();
+        return StaticShadowHelper.supportsShadow();
     }
 
     /**
@@ -316,7 +316,7 @@
      */
     public void prepareParentForShadow(ViewGroup parent) {
         if (mShadowType == SHADOW_STATIC) {
-            StaticShadowHelper.getInstance().prepareParent(parent);
+            StaticShadowHelper.prepareParent(parent);
         }
     }
 
@@ -458,7 +458,7 @@
                     ShadowHelper.setShadowFocusLevel(impl, level);
                     break;
                 case SHADOW_STATIC:
-                    StaticShadowHelper.getInstance().setShadowFocusLevel(impl, level);
+                    StaticShadowHelper.setShadowFocusLevel(impl, level);
                     break;
             }
         }
diff --git a/leanback/src/main/java/androidx/leanback/widget/StaticShadowHelper.java b/leanback/src/main/java/androidx/leanback/widget/StaticShadowHelper.java
index 5b3ff45..5ab0c61 100644
--- a/leanback/src/main/java/androidx/leanback/widget/StaticShadowHelper.java
+++ b/leanback/src/main/java/androidx/leanback/widget/StaticShadowHelper.java
@@ -16,107 +16,52 @@
 package androidx.leanback.widget;
 
 import android.os.Build;
+import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.RequiresApi;
-
+import androidx.leanback.R;
 
 /**
  * Helper for static (nine patch) shadows.
  */
 final class StaticShadowHelper {
-
-    final static StaticShadowHelper sInstance = new StaticShadowHelper();
-    boolean mSupportsShadow;
-    ShadowHelperVersionImpl mImpl;
-
-    /**
-     * Interface implemented by classes that support Shadow.
-     */
-    static interface ShadowHelperVersionImpl {
-        public void prepareParent(ViewGroup parent);
-        public Object addStaticShadow(ViewGroup shadowContainer);
-        public void setShadowFocusLevel(Object impl, float level);
-    }
-
-    /**
-     * Interface used when we do not support Shadow animations.
-     */
-    private static final class ShadowHelperStubImpl implements ShadowHelperVersionImpl {
-        ShadowHelperStubImpl() {
-        }
-
-        @Override
-        public void prepareParent(ViewGroup parent) {
-            // do nothing
-        }
-
-        @Override
-        public Object addStaticShadow(ViewGroup shadowContainer) {
-            // do nothing
-            return null;
-        }
-
-        @Override
-        public void setShadowFocusLevel(Object impl, float level) {
-            // do nothing
-        }
-    }
-
-    /**
-     * Implementation used on JBMR2 (and above).
-     */
-    @RequiresApi(19)
-    private static final class ShadowHelperJbmr2Impl implements ShadowHelperVersionImpl {
-        ShadowHelperJbmr2Impl() {
-        }
-
-        @Override
-        public void prepareParent(ViewGroup parent) {
-            ShadowHelperJbmr2.prepareParent(parent);
-        }
-
-        @Override
-        public Object addStaticShadow(ViewGroup shadowContainer) {
-            return ShadowHelperJbmr2.addShadow(shadowContainer);
-        }
-
-        @Override
-        public void setShadowFocusLevel(Object impl, float level) {
-            ShadowHelperJbmr2.setShadowFocusLevel(impl, level);
-        }
-    }
-
-    /**
-     * Returns the StaticShadowHelper.
-     */
     private StaticShadowHelper() {
+    }
+
+    static boolean supportsShadow() {
+        return Build.VERSION.SDK_INT >= 21;
+    }
+
+    static void prepareParent(ViewGroup parent) {
         if (Build.VERSION.SDK_INT >= 21) {
-            mSupportsShadow = true;
-            mImpl = new ShadowHelperJbmr2Impl();
-        } else {
-            mSupportsShadow = false;
-            mImpl = new ShadowHelperStubImpl();
+            parent.setLayoutMode(ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
         }
     }
 
-    public static StaticShadowHelper getInstance() {
-        return sInstance;
+    static Object addStaticShadow(ViewGroup shadowContainer) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            shadowContainer.setLayoutMode(ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
+            LayoutInflater inflater = LayoutInflater.from(shadowContainer.getContext());
+            inflater.inflate(R.layout.lb_shadow, shadowContainer, true);
+            ShadowImpl impl = new ShadowImpl();
+            impl.mNormalShadow = shadowContainer.findViewById(R.id.lb_shadow_normal);
+            impl.mFocusShadow = shadowContainer.findViewById(R.id.lb_shadow_focused);
+            return impl;
+        }
+        return null;
     }
 
-    public boolean supportsShadow() {
-        return mSupportsShadow;
+    static void setShadowFocusLevel(Object impl, float level) {
+        if (Build.VERSION.SDK_INT >= 21) {
+            ShadowImpl shadowImpl = (ShadowImpl) impl;
+            shadowImpl.mNormalShadow.setAlpha(1 - level);
+            shadowImpl.mFocusShadow.setAlpha(level);
+        }
     }
 
-    public void prepareParent(ViewGroup parent) {
-        mImpl.prepareParent(parent);
-    }
-
-    public Object addStaticShadow(ViewGroup shadowContainer) {
-        return mImpl.addStaticShadow(shadowContainer);
-    }
-
-    public void setShadowFocusLevel(Object impl, float level) {
-        mImpl.setShadowFocusLevel(impl, level);
+    static class ShadowImpl {
+        View mNormalShadow;
+        View mFocusShadow;
     }
 }
diff --git a/lifecycle/common-java8/api/current.txt b/lifecycle/common-java8/api/current.txt
new file mode 100644
index 0000000..07ed08c
--- /dev/null
+++ b/lifecycle/common-java8/api/current.txt
@@ -0,0 +1,13 @@
+package androidx.lifecycle {
+
+  public abstract interface DefaultLifecycleObserver implements androidx.lifecycle.LifecycleObserver {
+    method public default void onCreate(androidx.lifecycle.LifecycleOwner);
+    method public default void onDestroy(androidx.lifecycle.LifecycleOwner);
+    method public default void onPause(androidx.lifecycle.LifecycleOwner);
+    method public default void onResume(androidx.lifecycle.LifecycleOwner);
+    method public default void onStart(androidx.lifecycle.LifecycleOwner);
+    method public default void onStop(androidx.lifecycle.LifecycleOwner);
+  }
+
+}
+
diff --git a/lifecycle/common/api/current.txt b/lifecycle/common/api/current.txt
new file mode 100644
index 0000000..370089b
--- /dev/null
+++ b/lifecycle/common/api/current.txt
@@ -0,0 +1,44 @@
+package androidx.lifecycle {
+
+  public abstract class Lifecycle {
+    ctor public Lifecycle();
+    method public abstract void addObserver(androidx.lifecycle.LifecycleObserver);
+    method public abstract androidx.lifecycle.Lifecycle.State getCurrentState();
+    method public abstract void removeObserver(androidx.lifecycle.LifecycleObserver);
+  }
+
+  public static final class Lifecycle.Event extends java.lang.Enum {
+    method public static androidx.lifecycle.Lifecycle.Event valueOf(java.lang.String);
+    method public static final androidx.lifecycle.Lifecycle.Event[] values();
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_ANY;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_CREATE;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_DESTROY;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_PAUSE;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_RESUME;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_START;
+    enum_constant public static final androidx.lifecycle.Lifecycle.Event ON_STOP;
+  }
+
+  public static final class Lifecycle.State extends java.lang.Enum {
+    method public boolean isAtLeast(androidx.lifecycle.Lifecycle.State);
+    method public static androidx.lifecycle.Lifecycle.State valueOf(java.lang.String);
+    method public static final androidx.lifecycle.Lifecycle.State[] values();
+    enum_constant public static final androidx.lifecycle.Lifecycle.State CREATED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State DESTROYED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State INITIALIZED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State RESUMED;
+    enum_constant public static final androidx.lifecycle.Lifecycle.State STARTED;
+  }
+
+  public abstract interface LifecycleObserver {
+  }
+
+  public abstract interface LifecycleOwner {
+    method public abstract androidx.lifecycle.Lifecycle getLifecycle();
+  }
+
+  public abstract class OnLifecycleEvent implements java.lang.annotation.Annotation {
+  }
+
+}
+
diff --git a/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java b/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java
index 33f4eba..8c94a95 100644
--- a/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java
+++ b/lifecycle/livedata-core/src/main/java/androidx/lifecycle/LiveData.java
@@ -23,7 +23,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.arch.core.internal.SafeIterableMap;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import java.util.Iterator;
 import java.util.Map;
diff --git a/lifecycle/livedata-core/src/test/java/androidx/lifecycle/LiveDataTest.java b/lifecycle/livedata-core/src/test/java/androidx/lifecycle/LiveDataTest.java
index 9b78ed0..741ee66 100644
--- a/lifecycle/livedata-core/src/test/java/androidx/lifecycle/LiveDataTest.java
+++ b/lifecycle/livedata-core/src/test/java/androidx/lifecycle/LiveDataTest.java
@@ -38,8 +38,8 @@
 import static org.mockito.Mockito.when;
 
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.testing.InstantTaskExecutorRule;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
 
 import org.junit.After;
 import org.junit.Before;
diff --git a/lifecycle/livedata-core/src/test/java/androidx/lifecycle/ThreadedLiveDataTest.java b/lifecycle/livedata-core/src/test/java/androidx/lifecycle/ThreadedLiveDataTest.java
index e4eb869..19dcd21 100644
--- a/lifecycle/livedata-core/src/test/java/androidx/lifecycle/ThreadedLiveDataTest.java
+++ b/lifecycle/livedata-core/src/test/java/androidx/lifecycle/ThreadedLiveDataTest.java
@@ -24,8 +24,8 @@
 import static org.mockito.Mockito.when;
 
 import androidx.annotation.Nullable;
-import androidx.executor.JunitTaskExecutorRule;
-import androidx.executor.TaskExecutor;
+import androidx.arch.core.executor.JunitTaskExecutorRule;
+import androidx.arch.core.executor.TaskExecutor;
 
 import org.junit.Before;
 import org.junit.Rule;
diff --git a/lifecycle/livedata/src/main/java/androidx/lifecycle/ComputableLiveData.java b/lifecycle/livedata/src/main/java/androidx/lifecycle/ComputableLiveData.java
index 2c91427..e2e2a1b 100644
--- a/lifecycle/livedata/src/main/java/androidx/lifecycle/ComputableLiveData.java
+++ b/lifecycle/livedata/src/main/java/androidx/lifecycle/ComputableLiveData.java
@@ -21,7 +21,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.VisibleForTesting;
 import androidx.annotation.WorkerThread;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
diff --git a/lifecycle/livedata/src/test/java/androidx/lifecycle/ComputableLiveDataTest.java b/lifecycle/livedata/src/test/java/androidx/lifecycle/ComputableLiveDataTest.java
index e84eb42..2b9d37e 100644
--- a/lifecycle/livedata/src/test/java/androidx/lifecycle/ComputableLiveDataTest.java
+++ b/lifecycle/livedata/src/test/java/androidx/lifecycle/ComputableLiveDataTest.java
@@ -29,9 +29,9 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.TaskExecutor;
-import androidx.executor.TaskExecutorWithFakeMainThread;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.TaskExecutor;
+import androidx.arch.core.executor.TaskExecutorWithFakeMainThread;
 import androidx.lifecycle.util.InstantTaskExecutor;
 
 import org.junit.After;
diff --git a/lifecycle/livedata/src/test/java/androidx/lifecycle/MediatorLiveDataTest.java b/lifecycle/livedata/src/test/java/androidx/lifecycle/MediatorLiveDataTest.java
index ac065fb..a90c343 100644
--- a/lifecycle/livedata/src/test/java/androidx/lifecycle/MediatorLiveDataTest.java
+++ b/lifecycle/livedata/src/test/java/androidx/lifecycle/MediatorLiveDataTest.java
@@ -26,8 +26,8 @@
 import static org.mockito.Mockito.when;
 
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.testing.InstantTaskExecutorRule;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
 import androidx.lifecycle.util.InstantTaskExecutor;
 
 import org.junit.Before;
diff --git a/lifecycle/livedata/src/test/java/androidx/lifecycle/TransformationsTest.java b/lifecycle/livedata/src/test/java/androidx/lifecycle/TransformationsTest.java
index 7bb37ec..4994523 100644
--- a/lifecycle/livedata/src/test/java/androidx/lifecycle/TransformationsTest.java
+++ b/lifecycle/livedata/src/test/java/androidx/lifecycle/TransformationsTest.java
@@ -27,7 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import androidx.arch.core.util.Function;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.lifecycle.util.InstantTaskExecutor;
 
 import org.junit.Before;
diff --git a/lifecycle/livedata/src/test/java/androidx/lifecycle/util/InstantTaskExecutor.java b/lifecycle/livedata/src/test/java/androidx/lifecycle/util/InstantTaskExecutor.java
index 56facd3..60d703f 100644
--- a/lifecycle/livedata/src/test/java/androidx/lifecycle/util/InstantTaskExecutor.java
+++ b/lifecycle/livedata/src/test/java/androidx/lifecycle/util/InstantTaskExecutor.java
@@ -16,7 +16,7 @@
 
 package androidx.lifecycle.util;
 
-import androidx.executor.TaskExecutor;
+import androidx.arch.core.executor.TaskExecutor;
 
 public class InstantTaskExecutor extends TaskExecutor {
     @Override
diff --git a/lifecycle/reactivestreams/build.gradle b/lifecycle/reactivestreams/build.gradle
index 34390b7..649c526 100644
--- a/lifecycle/reactivestreams/build.gradle
+++ b/lifecycle/reactivestreams/build.gradle
@@ -35,9 +35,7 @@
 
     testImplementation(JUNIT)
     testImplementation(RX_JAVA)
-    testImplementation(TEST_RUNNER)
-
-    androidTestImplementation(SUPPORT_APPCOMPAT, libs.support_exclude_config)
+    testImplementation(project(":arch:core-testing"))
 }
 
 supportLibrary {
@@ -48,4 +46,4 @@
     inceptionYear = "2017"
     description = "Android Lifecycle Reactivestreams"
     url = SupportLibraryExtension.ARCHITECTURE_URL
-}
\ No newline at end of file
+}
diff --git a/collection-ktx/OWNERS b/lifecycle/reactivestreams/ktx/OWNERS
similarity index 100%
copy from collection-ktx/OWNERS
copy to lifecycle/reactivestreams/ktx/OWNERS
diff --git a/lifecycle/reactivestreams/ktx/build.gradle b/lifecycle/reactivestreams/ktx/build.gradle
new file mode 100644
index 0000000..2604a8e
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/build.gradle
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+  id("SupportAndroidLibraryPlugin")
+  id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+  api(project(":lifecycle:lifecycle-reactivestreams"))
+  api(KOTLIN_STDLIB)
+
+  testImplementation(JUNIT)
+  testImplementation(RX_JAVA)
+  testImplementation(TRUTH)
+  testImplementation(project(":arch:core-testing"))
+}
+
+supportLibrary {
+  name = "Android Lifecycle ReactiveStreams KTX"
+  publish = true
+  mavenVersion = LibraryVersions.LIFECYCLES_EXT
+  mavenGroup = LibraryGroups.LIFECYCLE
+  inceptionYear = "2018"
+  description = "Kotlin extensions for Lifecycle ReactiveStreams"
+  url = SupportLibraryExtension.ARCHITECTURE_URL
+}
diff --git a/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml b/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d2c150c
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/main/AndroidManifest.xml
@@ -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.
+  -->
+
+<manifest package="androidx.lifecycle.reactivestreams.ktx"/>
diff --git a/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt b/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt
new file mode 100644
index 0000000..e4a95e7
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/main/java/androidx/lifecycle/LiveDataReactiveSteams.kt
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("NOTHING_TO_INLINE") // Aliases to public API.
+
+package androidx.lifecycle
+
+import org.reactivestreams.Publisher
+
+/**
+ * Adapts the given [LiveData] stream to a ReactiveStreams [Publisher].
+ *
+ * @see LiveDataReactiveStreams.toPublisher
+ */
+inline fun <T> LiveData<T>.toPublisher(lifecycle: LifecycleOwner): Publisher<T> =
+    LiveDataReactiveStreams.toPublisher(lifecycle, this)
+
+/**
+ * Creates an observable [LiveData] stream from a ReactiveStreams [Publisher].
+ *
+ * @see LiveDataReactiveStreams.fromPublisher
+ */
+inline fun <T> Publisher<T>.toLiveData(): LiveData<T> =
+    LiveDataReactiveStreams.fromPublisher(this)
diff --git a/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt b/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt
new file mode 100644
index 0000000..ad3bdb2
--- /dev/null
+++ b/lifecycle/reactivestreams/ktx/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.kt
@@ -0,0 +1,72 @@
+/*
+ * 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 androidx.lifecycle
+
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import com.google.common.truth.Truth.assertThat
+import io.reactivex.processors.PublishProcessor
+import io.reactivex.processors.ReplayProcessor
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+
+class LiveDataReactiveStreamsTest {
+    @get:Rule val rule = InstantTaskExecutorRule()
+
+    private lateinit var lifecycleOwner: LifecycleOwner
+
+    @Before fun init() {
+        lifecycleOwner = object : LifecycleOwner {
+            internal var registry = LifecycleRegistry(this)
+
+            init {
+                registry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME)
+            }
+
+            override fun getLifecycle(): Lifecycle {
+                return registry
+            }
+        }
+    }
+
+    @Test fun convertsFromPublisher() {
+        val processor = PublishProcessor.create<String>()
+        val liveData = processor.toLiveData()
+
+        val output = mutableListOf<String?>()
+        liveData.observe(lifecycleOwner, Observer { output.add(it) })
+
+        processor.onNext("foo")
+        processor.onNext("bar")
+        processor.onNext("baz")
+
+        assertThat(output).containsExactly("foo", "bar", "baz")
+    }
+
+    @Test fun convertsToPublisherWithSyncData() {
+        val liveData = MutableLiveData<String>()
+        liveData.value = "foo"
+
+        val outputProcessor = ReplayProcessor.create<String>()
+        liveData.toPublisher(lifecycleOwner).subscribe(outputProcessor)
+
+        liveData.value = "bar"
+        liveData.value = "baz"
+
+        assertThat(outputProcessor.values).asList().containsExactly("foo", "bar", "baz")
+    }
+}
diff --git a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml b/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
deleted file mode 100644
index 304fd93..0000000
--- a/lifecycle/reactivestreams/src/androidTest/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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.
-  -->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="androidx.lifecycle.reactivestreams.test">
-    <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <application>
-        <activity android:name="androidx.lifecycle.viewmodeltest.ViewModelActivity"
-                  android:theme="@style/Base.Theme.AppCompat">
-        </activity>
-    </application>
-
-</manifest>
diff --git a/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java b/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
index 250f50d..711e71e 100644
--- a/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
+++ b/lifecycle/reactivestreams/src/main/java/androidx/lifecycle/LiveDataReactiveStreams.java
@@ -18,7 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import org.reactivestreams.Publisher;
 import org.reactivestreams.Subscriber;
@@ -165,7 +165,7 @@
     }
 
     /**
-     * Creates an Observable {@link LiveData} stream from a ReactiveStreams publisher.
+     * Creates an observable {@link LiveData} stream from a ReactiveStreams {@link Publisher}}.
      *
      * <p>
      * When the LiveData becomes active, it subscribes to the emissions from the Publisher.
diff --git a/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java b/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
index decb189..ed792d2 100644
--- a/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
+++ b/lifecycle/reactivestreams/src/test/java/androidx/lifecycle/LiveDataReactiveStreamsTest.java
@@ -21,15 +21,13 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
-import android.support.test.filters.SmallTest;
-
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.TaskExecutor;
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
 
-import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestRule;
 import org.reactivestreams.Subscriber;
 import org.reactivestreams.Subscription;
 
@@ -47,8 +45,9 @@
 import io.reactivex.schedulers.TestScheduler;
 import io.reactivex.subjects.AsyncSubject;
 
-@SmallTest
 public class LiveDataReactiveStreamsTest {
+    @Rule public final TestRule instantTaskExecutorRule = new InstantTaskExecutorRule();
+
     private LifecycleOwner mLifecycleOwner;
 
     private final List<String> mLiveDataOutput = new ArrayList<>();
@@ -62,7 +61,6 @@
     private final ReplayProcessor<String> mOutputProcessor = ReplayProcessor.create();
 
     private static final TestScheduler sBackgroundScheduler = new TestScheduler();
-    private Thread mTestThread;
 
     @Before
     public void init() {
@@ -77,31 +75,6 @@
                 return mRegistry;
             }
         };
-        mTestThread = Thread.currentThread();
-        ArchTaskExecutor.getInstance().setDelegate(new TaskExecutor() {
-
-            @Override
-            public void executeOnDiskIO(Runnable runnable) {
-                throw new IllegalStateException();
-            }
-
-            @Override
-            public void postToMainThread(Runnable runnable) {
-                // Wrong implementation, but it is fine for test
-                runnable.run();
-            }
-
-            @Override
-            public boolean isMainThread() {
-                return Thread.currentThread() == mTestThread;
-            }
-
-        });
-    }
-
-    @After
-    public void removeExecutorDelegate() {
-        ArchTaskExecutor.getInstance().setDelegate(null);
     }
 
     @Test
diff --git a/loader/api/current.txt b/loader/api/current.txt
index 2d00efb..275582d 100644
--- a/loader/api/current.txt
+++ b/loader/api/current.txt
@@ -5,7 +5,7 @@
     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 static <T extends android.arch.lifecycle.LifecycleOwner & android.arch.lifecycle.ViewModelStoreOwner> androidx.loader.app.LoaderManager getInstance(T);
+    method public static <T extends androidx.lifecycle.LifecycleOwner & androidx.lifecycle.ViewModelStoreOwner> androidx.loader.app.LoaderManager getInstance(T);
     method public abstract <D> androidx.loader.content.Loader<D> getLoader(int);
     method public boolean hasRunningLoaders();
     method public abstract <D> androidx.loader.content.Loader<D> initLoader(int, android.os.Bundle, androidx.loader.app.LoaderManager.LoaderCallbacks<D>);
diff --git a/loader/src/androidTest/AndroidManifest.xml b/loader/src/androidTest/AndroidManifest.xml
index 641063e..5115c15 100644
--- a/loader/src/androidTest/AndroidManifest.xml
+++ b/loader/src/androidTest/AndroidManifest.xml
@@ -17,10 +17,5 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="android.support.loader.test">
     <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
-
-    <application>
-        <activity android:name="androidx.loader.app.test.EmptyActivity" />
-    </application>
-
 </manifest>
 
diff --git a/loader/src/androidTest/java/androidx/loader/app/LoaderInfoTest.java b/loader/src/androidTest/java/androidx/loader/app/LoaderInfoTest.java
index ecdf44f..963d390 100644
--- a/loader/src/androidTest/java/androidx/loader/app/LoaderInfoTest.java
+++ b/loader/src/androidTest/java/androidx/loader/app/LoaderInfoTest.java
@@ -22,9 +22,9 @@
 import static org.mockito.Mockito.when;
 
 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.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 
 import androidx.lifecycle.Lifecycle;
@@ -32,11 +32,9 @@
 import androidx.lifecycle.LifecycleRegistry;
 import androidx.loader.app.test.DelayLoader;
 import androidx.loader.app.test.DummyLoaderCallbacks;
-import androidx.loader.app.test.EmptyActivity;
 import androidx.loader.content.Loader;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,25 +57,21 @@
         mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
     }
 
-    @Rule
-    public ActivityTestRule<EmptyActivity> mActivityRule =
-            new ActivityTestRule<>(EmptyActivity.class);
-
     @Test
     public void testIsCallbackWaitingForData() throws Throwable {
         final DummyLoaderCallbacks loaderCallback = new DummyLoaderCallbacks(mock(Context.class));
         final CountDownLatch deliverResultLatch = new CountDownLatch(1);
-        Loader<Boolean> delayLoader = new DelayLoader(mActivityRule.getActivity(),
+        Loader<Boolean> delayLoader = new DelayLoader(mock(Context.class),
                 deliverResultLatch);
         final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
                 0, null, delayLoader, null);
         assertFalse("isCallbackWaitingForData should be false before setCallback",
                 loaderInfo.isCallbackWaitingForData());
 
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+                loaderInfo.setCallback(mOwner, loaderCallback);
             }
         });
         assertTrue("isCallbackWaitingForData should be true immediately after setCallback",
@@ -86,7 +80,7 @@
         assertTrue("Loader timed out delivering results",
                 deliverResultLatch.await(1, TimeUnit.SECONDS));
         // Results are posted to the UI thread, so we wait for them there
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 assertTrue("onLoadFinished should be called after setCallback",
@@ -107,7 +101,7 @@
         assertFalse("onLoadFinished shouldn't be called before setCallback",
                 loaderCallback.mOnLoadFinished);
 
-        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+        loaderInfo.setCallback(mOwner, loaderCallback);
         assertTrue("onLoadFinished should be called after setCallback",
                 loaderCallback.mOnLoadFinished);
     }
@@ -122,15 +116,15 @@
         assertFalse("onLoadFinished for initial shouldn't be called before setCallback initial",
                 initialCallback.mOnLoadFinished);
 
-        loaderInfo.setCallback(mActivityRule.getActivity(), initialCallback);
+        loaderInfo.setCallback(mOwner, initialCallback);
         assertTrue("onLoadFinished for initial should be called after setCallback initial",
                 initialCallback.mOnLoadFinished);
 
         final DummyLoaderCallbacks replacementCallback =
-                new DummyLoaderCallbacks(mActivityRule.getActivity());
+                new DummyLoaderCallbacks(mock(Context.class));
         initialCallback.mOnLoadFinished = false;
 
-        loaderInfo.setCallback(mActivityRule.getActivity(), replacementCallback);
+        loaderInfo.setCallback(mOwner, replacementCallback);
         assertFalse("onLoadFinished for initial should not be called "
                         + "after setCallback replacement",
                 initialCallback.mOnLoadFinished);
@@ -202,7 +196,7 @@
         final LoaderManagerImpl.LoaderInfo<Boolean> loaderInfo = new LoaderManagerImpl.LoaderInfo<>(
                 0, null, loader, null);
 
-        loaderInfo.setCallback(mActivityRule.getActivity(), loaderCallback);
+        loaderInfo.setCallback(mOwner, loaderCallback);
         assertTrue("Loader should be started after setCallback", loader.isStarted());
         loaderInfo.destroy(true);
         assertFalse("Loader should not be started after destroy", loader.isStarted());
diff --git a/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java b/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
index cd60ee8..bbe7e52 100644
--- a/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
+++ b/loader/src/androidTest/java/androidx/loader/app/LoaderManagerTest.java
@@ -23,8 +23,9 @@
 
 import android.content.Context;
 import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
-import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
 
 import androidx.annotation.NonNull;
@@ -35,10 +36,9 @@
 import androidx.lifecycle.ViewModelStoreOwner;
 import androidx.loader.app.test.DelayLoaderCallbacks;
 import androidx.loader.app.test.DummyLoaderCallbacks;
-import androidx.loader.app.test.EmptyActivity;
 import androidx.loader.content.Loader;
 
-import org.junit.Rule;
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,24 +49,26 @@
 @SmallTest
 public class LoaderManagerTest {
 
-    @Rule
-    public ActivityTestRule<EmptyActivity> mActivityRule =
-            new ActivityTestRule<>(EmptyActivity.class);
+    private LoaderManager mLoaderManager;
+
+    @Before
+    public void setup() {
+        mLoaderManager = LoaderManager.getInstance(new LoaderOwner());
+    }
 
     @Test
     public void testDestroyFromOnCreateLoader() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
         final CountDownLatch onCreateLoaderLatch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                LoaderManager.getInstance(loaderOwner).initLoader(65, null,
+                mLoaderManager.initLoader(65, null,
                         new DummyLoaderCallbacks(mock(Context.class)) {
                             @NonNull
                             @Override
                             public Loader<Boolean> onCreateLoader(int id, Bundle args) {
                                 try {
-                                    LoaderManager.getInstance(loaderOwner).destroyLoader(65);
+                                    mLoaderManager.destroyLoader(65);
                                     fail("Calling destroyLoader in onCreateLoader should throw an "
                                             + "IllegalStateException");
                                 } catch (IllegalStateException e) {
@@ -87,18 +89,17 @@
      */
     @Test
     public void testDestroyFromOnLoadFinished() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
         final CountDownLatch onLoadFinishedLatch = new CountDownLatch(1);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                LoaderManager.getInstance(loaderOwner).initLoader(43, null,
+                mLoaderManager.initLoader(43, null,
                         new DummyLoaderCallbacks(mock(Context.class)) {
                             @Override
                             public void onLoadFinished(@NonNull Loader<Boolean> loader,
                                     Boolean data) {
                                 super.onLoadFinished(loader, data);
-                                LoaderManager.getInstance(loaderOwner).destroyLoader(43);
+                                mLoaderManager.destroyLoader(43);
                             }
                         });
             }
@@ -108,16 +109,14 @@
 
     @Test
     public void testDestroyLoaderBeforeDeliverData() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
-        final LoaderManager loaderManager = LoaderManager.getInstance(loaderOwner);
         final DelayLoaderCallbacks callback =
                 new DelayLoaderCallbacks(mock(Context.class), new CountDownLatch(1));
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.initLoader(37, null, callback);
+                mLoaderManager.initLoader(37, null, callback);
                 // Immediately destroy it before it has a chance to deliver data
-                loaderManager.destroyLoader(37);
+                mLoaderManager.destroyLoader(37);
             }
         });
         assertFalse("LoaderCallbacks should not be reset if they never received data",
@@ -128,23 +127,21 @@
 
     @Test
     public void testDestroyLoaderAfterDeliverData() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
-        final LoaderManager loaderManager = LoaderManager.getInstance(loaderOwner);
         CountDownLatch countDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks callback =
                 new DelayLoaderCallbacks(mock(Context.class), countDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.initLoader(38, null, callback);
+                mLoaderManager.initLoader(38, null, callback);
             }
         });
         // Wait for the Loader to return data
         countDownLatch.await(1, TimeUnit.SECONDS);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.destroyLoader(38);
+                mLoaderManager.destroyLoader(38);
             }
         });
         assertTrue("LoaderCallbacks should be reset after destroyLoader()",
@@ -156,19 +153,17 @@
 
     @Test
     public void testRestartLoaderBeforeDeliverData() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
-        final LoaderManager loaderManager = LoaderManager.getInstance(loaderOwner);
         final DelayLoaderCallbacks initialCallback =
                 new DelayLoaderCallbacks(mock(Context.class), new CountDownLatch(1));
         CountDownLatch restartCountDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks restartCallback =
                 new DelayLoaderCallbacks(mock(Context.class), restartCountDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.initLoader(44, null, initialCallback);
+                mLoaderManager.initLoader(44, null, initialCallback);
                 // Immediately restart it before it has a chance to deliver data
-                loaderManager.restartLoader(44, null, restartCallback);
+                mLoaderManager.restartLoader(44, null, restartCallback);
             }
         });
         assertFalse("Initial LoaderCallbacks should not be reset after restartLoader()",
@@ -180,15 +175,13 @@
 
     @Test
     public void testRestartLoaderAfterDeliverData() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
-        final LoaderManager loaderManager = LoaderManager.getInstance(loaderOwner);
         CountDownLatch initialCountDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks initialCallback =
                 new DelayLoaderCallbacks(mock(Context.class), initialCountDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.initLoader(45, null, initialCallback);
+                mLoaderManager.initLoader(45, null, initialCallback);
             }
         });
         // Wait for the first Loader to return data
@@ -196,10 +189,10 @@
         CountDownLatch restartCountDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks restartCallback =
                 new DelayLoaderCallbacks(mock(Context.class), restartCountDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.restartLoader(45, null, restartCallback);
+                mLoaderManager.restartLoader(45, null, restartCallback);
             }
         });
         assertFalse("Initial LoaderCallbacks should not be reset after restartLoader()",
@@ -213,15 +206,13 @@
 
     @Test
     public void testRestartLoaderMultiple() throws Throwable {
-        final LoaderOwner loaderOwner = new LoaderOwner();
-        final LoaderManager loaderManager = LoaderManager.getInstance(loaderOwner);
         CountDownLatch initialCountDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks initialCallback =
                 new DelayLoaderCallbacks(mock(Context.class), initialCountDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.initLoader(46, null, initialCallback);
+                mLoaderManager.initLoader(46, null, initialCallback);
             }
         });
         // Wait for the first Loader to return data
@@ -231,12 +222,12 @@
         CountDownLatch restartCountDownLatch = new CountDownLatch(1);
         final DelayLoaderCallbacks restartCallback =
                 new DelayLoaderCallbacks(mock(Context.class), restartCountDownLatch);
-        mActivityRule.runOnUiThread(new Runnable() {
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
-                loaderManager.restartLoader(46, null, intermediateCallback);
+                mLoaderManager.restartLoader(46, null, intermediateCallback);
                 // Immediately replace the restarted Loader with yet another Loader
-                loaderManager.restartLoader(46, null, restartCallback);
+                mLoaderManager.restartLoader(46, null, restartCallback);
             }
         });
         assertFalse("Initial LoaderCallbacks should not be reset after restartLoader()",
@@ -250,24 +241,40 @@
                 initialCallback.mLoader.isReset());
     }
 
+    @UiThreadTest
+    @Test(expected = IllegalArgumentException.class)
+    public void enforceNonNullLoader() {
+        mLoaderManager.initLoader(-1, null, new LoaderManager.LoaderCallbacks<Object>() {
+            @Override
+            public Loader<Object> onCreateLoader(int id, Bundle args) {
+                return null;
+            }
+
+            @Override
+            public void onLoadFinished(Loader<Object> loader, Object data) {
+            }
+
+            @Override
+            public void onLoaderReset(Loader<Object> loader) {
+            }
+        });
+    }
+
     @Test(expected = IllegalStateException.class)
     public void enforceOnMainThread_initLoader() {
-        LoaderOwner loaderOwner = new LoaderOwner();
-        LoaderManager.getInstance(loaderOwner).initLoader(-1, null,
+        mLoaderManager.initLoader(-1, null,
                 new DummyLoaderCallbacks(mock(Context.class)));
     }
 
     @Test(expected = IllegalStateException.class)
     public void enforceOnMainThread_restartLoader() {
-        LoaderOwner loaderOwner = new LoaderOwner();
-        LoaderManager.getInstance(loaderOwner).restartLoader(-1, null,
+        mLoaderManager.restartLoader(-1, null,
                 new DummyLoaderCallbacks(mock(Context.class)));
     }
 
     @Test(expected = IllegalStateException.class)
     public void enforceOnMainThread_destroyLoader() {
-        LoaderOwner loaderOwner = new LoaderOwner();
-        LoaderManager.getInstance(loaderOwner).destroyLoader(-1);
+        mLoaderManager.destroyLoader(-1);
     }
 
     class LoaderOwner implements LifecycleOwner, ViewModelStoreOwner {
diff --git a/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java b/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
index 770779d..7a2bae6 100644
--- a/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
+++ b/loader/src/main/java/androidx/loader/app/LoaderManagerImpl.java
@@ -380,6 +380,10 @@
         try {
             mLoaderViewModel.startCreatingLoader();
             Loader<D> loader = callback.onCreateLoader(id, args);
+            if (loader == null) {
+                throw new IllegalArgumentException("Object returned from onCreateLoader "
+                        + "must not be null");
+            }
             if (loader.getClass().isMemberClass()
                     && !Modifier.isStatic(loader.getClass().getModifiers())) {
                 throw new IllegalArgumentException("Object returned from onCreateLoader "
diff --git a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
index c73c01a..66ca559 100644
--- a/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
+++ b/mediarouter/src/main/java/androidx/mediarouter/media/MediaRouter.java
@@ -43,6 +43,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.core.app.ActivityManagerCompat;
 import androidx.core.hardware.display.DisplayManagerCompat;
+import androidx.core.util.ObjectsCompat;
 import androidx.core.util.Pair;
 import androidx.media.VolumeProviderCompat;
 import androidx.mediarouter.app.MediaRouteDiscoveryFragment;
@@ -783,10 +784,6 @@
         }
     }
 
-    static <T> boolean equal(T a, T b) {
-        return a == b || (a != null && b != null && a.equals(b));
-    }
-
     /**
      * Provides information about a media route.
      * <p>
@@ -1490,15 +1487,15 @@
             int changes = 0;
             mDescriptor = descriptor;
             if (descriptor != null) {
-                if (!equal(mName, descriptor.getName())) {
+                if (!ObjectsCompat.equals(mName, descriptor.getName())) {
                     mName = descriptor.getName();
                     changes |= CHANGE_GENERAL;
                 }
-                if (!equal(mDescription, descriptor.getDescription())) {
+                if (!ObjectsCompat.equals(mDescription, descriptor.getDescription())) {
                     mDescription = descriptor.getDescription();
                     changes |= CHANGE_GENERAL;
                 }
-                if (!equal(mIconUri, descriptor.getIconUri())) {
+                if (!ObjectsCompat.equals(mIconUri, descriptor.getIconUri())) {
                     mIconUri = descriptor.getIconUri();
                     changes |= CHANGE_GENERAL;
                 }
@@ -1548,11 +1545,11 @@
                     mPresentationDisplay = null;
                     changes |= CHANGE_GENERAL | CHANGE_PRESENTATION_DISPLAY;
                 }
-                if (!equal(mExtras, descriptor.getExtras())) {
+                if (!ObjectsCompat.equals(mExtras, descriptor.getExtras())) {
                     mExtras = descriptor.getExtras();
                     changes |= CHANGE_GENERAL;
                 }
-                if (!equal(mSettingsIntent, descriptor.getSettingsActivity())) {
+                if (!ObjectsCompat.equals(mSettingsIntent, descriptor.getSettingsActivity())) {
                     mSettingsIntent = descriptor.getSettingsActivity();
                     changes |= CHANGE_GENERAL;
                 }
diff --git a/paging/runtime/src/androidTest/java/androidx/paging/AsyncPagedListDifferTest.kt b/paging/runtime/src/androidTest/java/androidx/paging/AsyncPagedListDifferTest.kt
index 7686132..169779d 100644
--- a/paging/runtime/src/androidTest/java/androidx/paging/AsyncPagedListDifferTest.kt
+++ b/paging/runtime/src/androidTest/java/androidx/paging/AsyncPagedListDifferTest.kt
@@ -17,7 +17,7 @@
 package androidx.paging
 
 import android.support.test.filters.SmallTest
-import androidx.executor.ArchTaskExecutor
+import androidx.arch.core.executor.ArchTaskExecutor
 import androidx.recyclerview.widget.AsyncDifferConfig
 import androidx.recyclerview.widget.DiffUtil
 import androidx.recyclerview.widget.ListUpdateCallback
diff --git a/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
new file mode 100644
index 0000000..54955a0
--- /dev/null
+++ b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
@@ -0,0 +1,124 @@
+/*
+ * 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.paging
+
+import android.support.test.filters.SmallTest
+import androidx.arch.core.executor.ArchTaskExecutor
+import androidx.arch.core.executor.TaskExecutor
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.Observer
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.fail
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LivePagedListBuilderTest {
+    private val backgroundExecutor = TestExecutor()
+    private val lifecycleOwner = object : LifecycleOwner {
+        private val lifecycle = LifecycleRegistry(this)
+
+        override fun getLifecycle(): Lifecycle {
+            return lifecycle
+        }
+
+        fun handleEvent(event: Lifecycle.Event) {
+            lifecycle.handleLifecycleEvent(event)
+        }
+    }
+
+    @Before
+    fun setup() {
+        ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
+            override fun executeOnDiskIO(runnable: Runnable) {
+                fail("IO executor should be overwritten")
+            }
+
+            override fun postToMainThread(runnable: Runnable) {
+                runnable.run()
+            }
+
+            override fun isMainThread(): Boolean {
+                return true
+            }
+        })
+        lifecycleOwner.handleEvent(Lifecycle.Event.ON_START)
+    }
+
+    @After
+    fun teardown() {
+        lifecycleOwner.handleEvent(Lifecycle.Event.ON_STOP)
+        ArchTaskExecutor.getInstance().setDelegate(null)
+    }
+
+    private class MockDataSource : PositionalDataSource<String>() {
+        override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<String>) {
+            assertEquals(2, params.pageSize)
+            callback.onResult(listOf("a", "b"), 0, 4)
+        }
+
+        override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<String>) {
+            callback.onResult(listOf("c", "d"))
+        }
+
+        class Factory : DataSource.Factory<Int, String>() {
+            override fun create(): DataSource<Int, String> {
+                return MockDataSource()
+            }
+        }
+    }
+
+    @Test
+    fun executorBehavior() {
+        // specify a background executor via builder, and verify it gets used for all loads,
+        // overriding default arch IO executor
+        val livePagedList = LivePagedListBuilder(
+                MockDataSource.Factory(), 2)
+                .setBackgroundThreadExecutor(backgroundExecutor)
+                .build()
+
+        val pagedListHolder: Array<PagedList<String>?> = arrayOfNulls(1)
+
+        livePagedList.observe(lifecycleOwner, Observer<PagedList<String>> { newList ->
+            pagedListHolder[0] = newList
+        })
+
+        // won't compute until we flush...
+        assertNull(pagedListHolder[0])
+
+        // flush loadInitial, done with passed executor
+        backgroundExecutor.executeAll()
+
+        val pagedList = pagedListHolder[0]
+        assertNotNull(pagedList)
+        assertEquals(listOf("a", "b", null, null), pagedList)
+
+        // flush loadRange
+        pagedList!!.loadAround(2)
+        backgroundExecutor.executeAll()
+
+        assertEquals(listOf("a", "b", "c", "d"), pagedList)
+    }
+}
diff --git a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
index f37ac5d..f30163d 100644
--- a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
+++ b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.java
@@ -18,7 +18,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.lifecycle.LiveData;
 import androidx.recyclerview.widget.AdapterListUpdateCallback;
 import androidx.recyclerview.widget.AsyncDifferConfig;
diff --git a/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.java b/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.java
index 5d758cb..75c632f 100644
--- a/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.java
+++ b/paging/runtime/src/main/java/androidx/paging/LivePagedListBuilder.java
@@ -19,7 +19,7 @@
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.lifecycle.ComputableLiveData;
 import androidx.lifecycle.LiveData;
 
@@ -167,7 +167,7 @@
             @NonNull final DataSource.Factory<Key, Value> dataSourceFactory,
             @NonNull final Executor mainThreadExecutor,
             @NonNull final Executor backgroundThreadExecutor) {
-        return new ComputableLiveData<PagedList<Value>>() {
+        return new ComputableLiveData<PagedList<Value>>(backgroundThreadExecutor) {
             @Nullable
             private PagedList<Value> mList;
             @Nullable
diff --git a/palette/build.gradle b/palette/build.gradle
index b1ab9e7..4037bf5 100644
--- a/palette/build.gradle
+++ b/palette/build.gradle
@@ -10,6 +10,8 @@
     api(project(":core"))
     api(project(":legacy-support-core-utils"))
 
+    annotationProcessor(NULLAWAY)
+
     androidTestImplementation(TEST_RUNNER_TMP, libs.exclude_for_espresso)
 }
 
diff --git a/palette-ktx/OWNERS b/palette/ktx/OWNERS
similarity index 100%
rename from palette-ktx/OWNERS
rename to palette/ktx/OWNERS
diff --git a/palette-ktx/build.gradle b/palette/ktx/build.gradle
similarity index 100%
rename from palette-ktx/build.gradle
rename to palette/ktx/build.gradle
diff --git a/palette-ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt b/palette/ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt
similarity index 100%
rename from palette-ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt
rename to palette/ktx/src/androidTest/java/androidx/palette/graphics/PaletteTest.kt
diff --git a/palette-ktx/src/main/AndroidManifest.xml b/palette/ktx/src/main/AndroidManifest.xml
similarity index 100%
rename from palette-ktx/src/main/AndroidManifest.xml
rename to palette/ktx/src/main/AndroidManifest.xml
diff --git a/palette-ktx/src/main/java/androidx/palette/graphics/Palette.kt b/palette/ktx/src/main/java/androidx/palette/graphics/Palette.kt
similarity index 100%
rename from palette-ktx/src/main/java/androidx/palette/graphics/Palette.kt
rename to palette/ktx/src/main/java/androidx/palette/graphics/Palette.kt
diff --git a/palette/src/main/java/androidx/palette/graphics/ColorCutQuantizer.java b/palette/src/main/java/androidx/palette/graphics/ColorCutQuantizer.java
index 5c304f8..58e3643 100644
--- a/palette/src/main/java/androidx/palette/graphics/ColorCutQuantizer.java
+++ b/palette/src/main/java/androidx/palette/graphics/ColorCutQuantizer.java
@@ -19,6 +19,7 @@
 import android.graphics.Color;
 import android.util.TimingLogger;
 
+import androidx.annotation.Nullable;
 import androidx.core.graphics.ColorUtils;
 
 import java.util.ArrayList;
@@ -56,7 +57,7 @@
     final int[] mColors;
     final int[] mHistogram;
     final List<Palette.Swatch> mQuantizedColors;
-    final TimingLogger mTimingLogger;
+    @Nullable final TimingLogger mTimingLogger;
     final Palette.Filter[] mFilters;
 
     private final float[] mTempHsl = new float[3];
@@ -68,6 +69,7 @@
      * @param maxColors The maximum number of colors that should be in the result palette.
      * @param filters Set of filters to use in the quantization stage
      */
+    @SuppressWarnings("NullAway") // mTimingLogger initialization and access guarded by LOG_TIMINGS.
     ColorCutQuantizer(final int[] pixels, final int maxColors, final Palette.Filter[] filters) {
         mTimingLogger = LOG_TIMINGS ? new TimingLogger(LOG_TAG, "Creation") : null;
         mFilters = filters;
@@ -169,6 +171,7 @@
      * @param queue {@link java.util.PriorityQueue} to poll for boxes
      * @param maxSize Maximum amount of boxes to split
      */
+    @SuppressWarnings("NullAway") // mTimingLogger initialization and access guarded by LOG_TIMINGS.
     private void splitBoxes(final PriorityQueue<Vbox> queue, final int maxSize) {
         while (queue.size() < maxSize) {
             final Vbox vbox = queue.poll();
diff --git a/palette/src/main/java/androidx/palette/graphics/Palette.java b/palette/src/main/java/androidx/palette/graphics/Palette.java
index 503149c..6f062ac 100644
--- a/palette/src/main/java/androidx/palette/graphics/Palette.java
+++ b/palette/src/main/java/androidx/palette/graphics/Palette.java
@@ -80,9 +80,10 @@
     public interface PaletteAsyncListener {
 
         /**
-         * Called when the {@link Palette} has been generated.
+         * Called when the {@link Palette} has been generated. {@code null} will be passed when an
+         * error occurred during generation.
          */
-        void onGenerated(@NonNull Palette palette);
+        void onGenerated(@Nullable Palette palette);
     }
 
     static final int DEFAULT_RESIZE_BITMAP_AREA = 112 * 112;
@@ -152,7 +153,7 @@
     private final Map<Target, Swatch> mSelectedSwatches;
     private final SparseBooleanArray mUsedColors;
 
-    private final Swatch mDominantSwatch;
+    @Nullable private final Swatch mDominantSwatch;
 
     Palette(List<Swatch> swatches, List<Target> targets) {
         mSwatches = swatches;
@@ -360,6 +361,7 @@
         mUsedColors.clear();
     }
 
+    @Nullable
     private Swatch generateScoredTarget(final Target target) {
         final Swatch maxScoreSwatch = getMaxScoredSwatchForTarget(target);
         if (maxScoreSwatch != null && target.isExclusive()) {
@@ -369,6 +371,7 @@
         return maxScoreSwatch;
     }
 
+    @Nullable
     private Swatch getMaxScoredSwatchForTarget(final Target target) {
         float maxScore = 0;
         Swatch maxScoreSwatch = null;
@@ -419,6 +422,7 @@
         return saturationScore + luminanceScore + populationScore;
     }
 
+    @Nullable
     private Swatch findDominantSwatch() {
         int maxPop = Integer.MIN_VALUE;
         Swatch maxSwatch = null;
@@ -432,12 +436,6 @@
         return maxSwatch;
     }
 
-    private static float[] copyHslValues(Swatch color) {
-        final float[] newHsl = new float[3];
-        System.arraycopy(color.getHsl(), 0, newHsl, 0, 3);
-        return newHsl;
-    }
-
     /**
      * Represents a color swatch generated from an image's palette. The RGB color can be retrieved
      * by calling {@link #getRgb()}.
@@ -451,7 +449,7 @@
         private int mTitleTextColor;
         private int mBodyTextColor;
 
-        private float[] mHsl;
+        @Nullable private float[] mHsl;
 
         public Swatch(@ColorInt int color, int population) {
             mRed = Color.red(color);
@@ -600,8 +598,8 @@
      * Builder class for generating {@link Palette} instances.
      */
     public static final class Builder {
-        private final List<Swatch> mSwatches;
-        private final Bitmap mBitmap;
+        @Nullable private final List<Swatch> mSwatches;
+        @Nullable private final Bitmap mBitmap;
 
         private final List<Target> mTargets = new ArrayList<>();
 
@@ -610,7 +608,7 @@
         private int mResizeMaxDimension = -1;
 
         private final List<Filter> mFilters = new ArrayList<>();
-        private Rect mRegion;
+        @Nullable private Rect mRegion;
 
         /**
          * Construct a new {@link Builder} using a source {@link Bitmap}
@@ -831,9 +829,12 @@
                 if (logger != null) {
                     logger.addSplit("Color quantization completed");
                 }
-            } else {
+            } else if (mSwatches != null) {
                 // Else we're using the provided swatches
                 swatches = mSwatches;
+            } else {
+                // The constructors enforce either a bitmap or swatches are present.
+                throw new AssertionError();
             }
 
             // Now create a Palette instance
@@ -863,6 +864,7 @@
 
             return new AsyncTask<Bitmap, Void, Palette>() {
                 @Override
+                @Nullable
                 protected Palette doInBackground(Bitmap... params) {
                     try {
                         return generate();
@@ -873,7 +875,7 @@
                 }
 
                 @Override
-                protected void onPostExecute(Palette colorExtractor) {
+                protected void onPostExecute(@Nullable Palette colorExtractor) {
                     listener.onGenerated(colorExtractor);
                 }
             }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, mBitmap);
diff --git a/palette-ktx/OWNERS b/persistence/db/ktx/OWNERS
similarity index 100%
copy from palette-ktx/OWNERS
copy to persistence/db/ktx/OWNERS
diff --git a/persistence/db/ktx/build.gradle b/persistence/db/ktx/build.gradle
new file mode 100644
index 0000000..676445b
--- /dev/null
+++ b/persistence/db/ktx/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SupportLibraryExtension
+
+plugins {
+    id("SupportAndroidLibraryPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    api(project(":sqlite:sqlite"))
+    api(KOTLIN_STDLIB)
+
+    testImplementation(JUNIT)
+    testImplementation(MOCKITO_CORE)
+}
+
+supportLibrary {
+    name = "Android DB KTX"
+    publish = true
+    mavenVersion = LibraryVersions.ROOM
+    mavenGroup = LibraryGroups.PERSISTENCE
+    inceptionYear = "2018"
+    description = "Kotlin extensions for DB"
+    url = SupportLibraryExtension.ARCHITECTURE_URL
+}
diff --git a/persistence/db/ktx/src/main/AndroidManifest.xml b/persistence/db/ktx/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..f4d66ba
--- /dev/null
+++ b/persistence/db/ktx/src/main/AndroidManifest.xml
@@ -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.
+  -->
+
+<manifest package="androidx.sqlite.db.ktx"/>
diff --git a/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt b/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt
new file mode 100644
index 0000000..ba7b338
--- /dev/null
+++ b/persistence/db/ktx/src/main/java/androidx/sqlite/db/SupportSQLiteDatabase.kt
@@ -0,0 +1,40 @@
+/*
+ * 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 androidx.sqlite.db
+
+/**
+ * Run [body] in a transaction marking it as successful if it completes without exception.
+ *
+ * @param exclusive Run in `EXCLUSIVE` mode when true, `IMMEDIATE` mode otherwise.
+ */
+inline fun <T> SupportSQLiteDatabase.transaction(
+    exclusive: Boolean = true,
+    body: SupportSQLiteDatabase.() -> T
+): T {
+    if (exclusive) {
+        beginTransaction()
+    } else {
+        beginTransactionNonExclusive()
+    }
+    try {
+        val result = body()
+        setTransactionSuccessful()
+        return result
+    } finally {
+        endTransaction()
+    }
+}
diff --git a/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt b/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt
new file mode 100644
index 0000000..76698d3
--- /dev/null
+++ b/persistence/db/ktx/src/test/java/androidx/sqlite/db/SupportSQLiteDatabaseTest.kt
@@ -0,0 +1,64 @@
+/*
+ * 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 androidx.sqlite.db
+
+import org.junit.Assert.fail
+import org.junit.Test
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+
+class SupportSQLiteDatabaseTest {
+    @Test fun exclusiveDefault() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction {}
+        verify(db).beginTransaction()
+    }
+
+    @Test fun exclusiveFalse() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction(exclusive = false) {}
+        verify(db).beginTransactionNonExclusive()
+    }
+
+    @Test fun exclusiveTrue() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction(exclusive = true) {}
+        verify(db).beginTransaction()
+    }
+
+    @Test fun bodyNormalCallsSuccessAndEnd() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        db.transaction {}
+        verify(db).setTransactionSuccessful()
+        verify(db).endTransaction()
+    }
+
+    @Suppress("UNREACHABLE_CODE") // A programming error might not invoke the lambda.
+    @Test fun bodyThrowsDoesNotCallSuccess() {
+        val db = mock(SupportSQLiteDatabase::class.java)
+        try {
+            db.transaction {
+                throw IllegalStateException()
+            }
+            fail()
+        } catch (e: IllegalStateException) {
+        }
+        verify(db, times(0)).setTransactionSuccessful()
+        verify(db).endTransaction()
+    }
+}
diff --git a/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragment.java b/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragment.java
index 2fa0e1b..f25710b 100644
--- a/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragment.java
+++ b/preference/src/main/java/androidx/preference/EditTextPreferenceDialogFragment.java
@@ -63,6 +63,7 @@
         super.onBindDialogView(view);
 
         mEditText = view.findViewById(android.R.id.edit);
+        mEditText.requestFocus();
 
         if (mEditText == null) {
             throw new IllegalStateException("Dialog view must contain an EditText with id"
@@ -71,7 +72,7 @@
 
         mEditText.setText(mText);
         // Place cursor at the end
-        mEditText.setSelection(mText.length());
+        mEditText.setSelection(mEditText.getText().length());
     }
 
     private EditTextPreference getEditTextPreference() {
diff --git a/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java b/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
index a4123fe..2b911a1 100644
--- a/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
+++ b/preference/src/main/java/androidx/preference/PreferenceDialogFragment.java
@@ -193,6 +193,11 @@
      * Returns whether the preference needs to display a soft input method when the dialog
      * is displayed. Default is false. Subclasses should override this method if they need
      * the soft input method brought up automatically.
+     *
+     * <p>Note: If your application targets P or above, ensure your subclass manually requests
+     * focus (ideally in {@link #onBindDialogView(View)}) for the input field in order to
+     * correctly attach the input method to the field.
+     *
      * @hide
      */
     @RestrictTo(LIBRARY_GROUP)
diff --git a/print/src/main/java/androidx/print/PrintHelper.java b/print/src/main/java/androidx/print/PrintHelper.java
index f32eb23..2630940 100644
--- a/print/src/main/java/androidx/print/PrintHelper.java
+++ b/print/src/main/java/androidx/print/PrintHelper.java
@@ -56,6 +56,24 @@
  * Helper for printing bitmaps.
  */
 public final class PrintHelper {
+    private static final String LOG_TAG = "PrintHelper";
+    // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi)
+    private static final int MAX_PRINT_SIZE = 3500;
+
+    /**
+     * Whether the PrintActivity respects the suggested orientation.
+     *
+     * There is a bug in the PrintActivity that causes it to ignore the orientation
+     */
+    private static final boolean PRINT_ACTIVITY_RESPECTS_ORIENTATION =
+            Build.VERSION.SDK_INT < 20 || Build.VERSION.SDK_INT > 23;
+
+    /**
+     * Whether the print subsystem handles min margins correctly. If not the print helper needs
+     * to fake this.
+     */
+    private static final boolean IS_MIN_MARGINS_HANDLING_CORRECT = Build.VERSION.SDK_INT != 23;
+
     /**
      * image will be scaled but leave white space
      */
@@ -110,7 +128,14 @@
     @Retention(RetentionPolicy.SOURCE)
     private @interface Orientation {}
 
-    private final PrintHelperVersionImpl mImpl;
+    private final Context mContext;
+
+    BitmapFactory.Options mDecodeOptions = null;
+    private final Object mLock = new Object();
+
+    @ScaleMode int mScaleMode = SCALE_MODE_FILL;
+    @ColorMode int mColorMode = COLOR_MODE_COLOR;
+    @Orientation int mOrientation = ORIENTATION_LANDSCAPE;
 
     /**
      * Gets whether the system supports printing.
@@ -123,786 +148,12 @@
     }
 
     /**
-     * Interface implemented by classes that support printing
-     */
-    interface PrintHelperVersionImpl {
-
-        void setScaleMode(int scaleMode);
-
-        int getScaleMode();
-
-        void setColorMode(int colorMode);
-
-        int getColorMode();
-
-        void setOrientation(int orientation);
-
-        int getOrientation();
-
-        void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
-                @Nullable OnPrintFinishCallback callback);
-
-        void printBitmap(@NonNull String jobName, @NonNull Uri imageFile,
-                @Nullable OnPrintFinishCallback callback)
-                throws FileNotFoundException;
-    }
-
-    /**
-     * Implementation used when we do not support printing
-     */
-    private static final class PrintHelperStub implements PrintHelperVersionImpl {
-        @ScaleMode int mScaleMode = SCALE_MODE_FILL;
-        @ColorMode int mColorMode = COLOR_MODE_COLOR;
-        @Orientation int mOrientation = ORIENTATION_LANDSCAPE;
-
-        @Override
-        public void setScaleMode(@ScaleMode int scaleMode) {
-            mScaleMode = scaleMode;
-        }
-
-        @ScaleMode
-        @Override
-        public int getScaleMode() {
-            return mScaleMode;
-        }
-
-        @ColorMode
-        @Override
-        public int getColorMode() {
-            return mColorMode;
-        }
-
-        @Override
-        public void setColorMode(@ColorMode int colorMode) {
-            mColorMode = colorMode;
-        }
-
-        @Override
-        public void setOrientation(@Orientation int orientation) {
-            mOrientation = orientation;
-        }
-
-        @Orientation
-        @Override
-        public int getOrientation() {
-            return mOrientation;
-        }
-
-        @Override
-        public void printBitmap(String jobName, Bitmap bitmap, OnPrintFinishCallback callback) {
-        }
-
-        @Override
-        public void printBitmap(String jobName, Uri imageFile, OnPrintFinishCallback callback) {
-        }
-    }
-
-    /**
-     * Kitkat specific PrintManager API implementation.
-     */
-    @RequiresApi(19)
-    private static class PrintHelperApi19 implements PrintHelperVersionImpl{
-        private static final String LOG_TAG = "PrintHelperApi19";
-        // will be <= 300 dpi on A4 (8.3×11.7) paper (worst case of 150 dpi)
-        private static final int MAX_PRINT_SIZE = 3500;
-        final Context mContext;
-        BitmapFactory.Options mDecodeOptions = null;
-        private final Object mLock = new Object();
-
-        /**
-         * Whether the PrintActivity respects the suggested orientation
-         */
-        protected boolean mPrintActivityRespectsOrientation;
-
-        /**
-         * Whether the print subsystem handles min margins correctly. If not the print helper needs
-         * to fake this.
-         */
-        protected boolean mIsMinMarginsHandlingCorrect;
-
-        @ScaleMode int mScaleMode = SCALE_MODE_FILL;
-
-        @ColorMode int mColorMode = COLOR_MODE_COLOR;
-
-        @Orientation int mOrientation;
-
-        PrintHelperApi19(Context context) {
-            mPrintActivityRespectsOrientation = true;
-            mIsMinMarginsHandlingCorrect = true;
-
-            mContext = context;
-        }
-
-        /**
-         * Selects whether the image will fill the paper and be cropped
-         * <p/>
-         * {@link #SCALE_MODE_FIT}
-         * or whether the image will be scaled but leave white space
-         * {@link #SCALE_MODE_FILL}.
-         *
-         * @param scaleMode {@link #SCALE_MODE_FIT} or
-         *                  {@link #SCALE_MODE_FILL}
-         */
-        @Override
-        public void setScaleMode(@ScaleMode int scaleMode) {
-            mScaleMode = scaleMode;
-        }
-
-        /**
-         * Returns the scale mode with which the image will fill the paper.
-         *
-         * @return The scale Mode: {@link #SCALE_MODE_FIT} or
-         * {@link #SCALE_MODE_FILL}
-         */
-        @ScaleMode
-        @Override
-        public int getScaleMode() {
-            return mScaleMode;
-        }
-
-        /**
-         * Sets whether the image will be printed in color (default)
-         * {@link #COLOR_MODE_COLOR} or in back and white
-         * {@link #COLOR_MODE_MONOCHROME}.
-         *
-         * @param colorMode The color mode which is one of
-         *                  {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}.
-         */
-        @Override
-        public void setColorMode(@ColorMode int colorMode) {
-            mColorMode = colorMode;
-        }
-
-        /**
-         * Sets whether to select landscape (default), {@link #ORIENTATION_LANDSCAPE}
-         * or portrait {@link #ORIENTATION_PORTRAIT}
-         * @param orientation The page orientation which is one of
-         *                    {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
-         */
-        @Override
-        public void setOrientation(@Orientation int orientation) {
-            mOrientation = orientation;
-        }
-
-        /**
-         * Gets the page orientation with which the image will be printed.
-         *
-         * @return The preferred orientation which is one of
-         * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}
-         */
-        @Orientation
-        @Override
-        public int getOrientation() {
-            /// Unset defaults to landscape but might turn image
-            if (mOrientation == 0) {
-                return ORIENTATION_LANDSCAPE;
-            }
-            return mOrientation;
-        }
-
-        /**
-         * Gets the color mode with which the image will be printed.
-         *
-         * @return The color mode which is one of {@link #COLOR_MODE_COLOR}
-         * and {@link #COLOR_MODE_MONOCHROME}.
-         */
-        @ColorMode
-        @Override
-        public int getColorMode() {
-            return mColorMode;
-        }
-
-        /**
-         * Check if the supplied bitmap should best be printed on a portrait orientation paper.
-         *
-         * @param bitmap The bitmap to be printed.
-         * @return true iff the picture should best be printed on a portrait orientation paper.
-         */
-        private static boolean isPortrait(Bitmap bitmap) {
-            return bitmap.getWidth() <= bitmap.getHeight();
-        }
-
-        /**
-         * Create a build with a copy from the other print attributes.
-         *
-         * @param other The other print attributes
-         *
-         * @return A builder that will build print attributes that match the other attributes
-         */
-        protected PrintAttributes.Builder copyAttributes(PrintAttributes other) {
-            PrintAttributes.Builder b = (new PrintAttributes.Builder())
-                    .setMediaSize(other.getMediaSize())
-                    .setResolution(other.getResolution())
-                    .setMinMargins(other.getMinMargins());
-
-            if (other.getColorMode() != 0) {
-                b.setColorMode(other.getColorMode());
-            }
-
-            return b;
-        }
-
-        /**
-         * Prints a bitmap.
-         *
-         * @param jobName The print job name.
-         * @param bitmap  The bitmap to print.
-         * @param callback Optional callback to observe when printing is finished.
-         */
-        @Override
-        public void printBitmap(final String jobName, final Bitmap bitmap,
-                final OnPrintFinishCallback callback) {
-            if (bitmap == null) {
-                return;
-            }
-
-            final int fittingMode = mScaleMode; // grab the fitting mode at time of call
-            PrintManager printManager =
-                    (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
-            PrintAttributes.MediaSize mediaSize;
-            if (isPortrait(bitmap)) {
-                mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
-            } else {
-                mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
-            }
-            PrintAttributes attr = new PrintAttributes.Builder()
-                    .setMediaSize(mediaSize)
-                    .setColorMode(mColorMode)
-                    .build();
-
-            printManager.print(jobName,
-                    new PrintDocumentAdapter() {
-                        private PrintAttributes mAttributes;
-
-                        @Override
-                        public void onLayout(PrintAttributes oldPrintAttributes,
-                                PrintAttributes newPrintAttributes,
-                                CancellationSignal cancellationSignal,
-                                LayoutResultCallback layoutResultCallback,
-                                Bundle bundle) {
-
-                            mAttributes = newPrintAttributes;
-
-                            PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
-                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
-                                    .setPageCount(1)
-                                    .build();
-                            boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
-                            layoutResultCallback.onLayoutFinished(info, changed);
-                        }
-
-                        @Override
-                        public void onWrite(PageRange[] pageRanges,
-                                ParcelFileDescriptor fileDescriptor,
-                                CancellationSignal cancellationSignal,
-                                WriteResultCallback writeResultCallback) {
-                            writeBitmap(mAttributes, fittingMode, bitmap, fileDescriptor,
-                                    cancellationSignal, writeResultCallback);
-                        }
-
-                        @Override
-                        public void onFinish() {
-                            if (callback != null) {
-                                callback.onFinish();
-                            }
-                        }
-                    }, attr);
-        }
-
-        /**
-         * Calculates the transform the print an Image to fill the page
-         *
-         * @param imageWidth  with of bitmap
-         * @param imageHeight height of bitmap
-         * @param content     The output page dimensions
-         * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs
-         *                    {@link #SCALE_MODE_FIT}
-         * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call
-         */
-        private Matrix getMatrix(int imageWidth, int imageHeight, RectF content,
-                @ScaleMode int fittingMode) {
-            Matrix matrix = new Matrix();
-
-            // Compute and apply scale to fill the page.
-            float scale = content.width() / imageWidth;
-            if (fittingMode == SCALE_MODE_FILL) {
-                scale = Math.max(scale, content.height() / imageHeight);
-            } else {
-                scale = Math.min(scale, content.height() / imageHeight);
-            }
-            matrix.postScale(scale, scale);
-
-            // Center the content.
-            final float translateX = (content.width()
-                    - imageWidth * scale) / 2;
-            final float translateY = (content.height()
-                    - imageHeight * scale) / 2;
-            matrix.postTranslate(translateX, translateY);
-            return matrix;
-        }
-
-        /**
-         * Write a bitmap for a PDF document.
-         *
-         * @param attributes          The print attributes
-         * @param fittingMode         How to fit the bitmap
-         * @param bitmap              The bitmap to write
-         * @param fileDescriptor      The file to write to
-         * @param cancellationSignal  Signal cancelling operation
-         * @param writeResultCallback Callback to call once written
-         */
-        private void writeBitmap(final PrintAttributes attributes, final int fittingMode,
-                final Bitmap bitmap, final ParcelFileDescriptor fileDescriptor,
-                final CancellationSignal cancellationSignal,
-                final PrintDocumentAdapter.WriteResultCallback writeResultCallback) {
-            final PrintAttributes pdfAttributes;
-            if (mIsMinMarginsHandlingCorrect) {
-                pdfAttributes = attributes;
-            } else {
-                // If the handling of any margin != 0 is broken, strip the margins and add them to
-                // the bitmap later
-                pdfAttributes = copyAttributes(attributes)
-                        .setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0)).build();
-            }
-
-            (new AsyncTask<Void, Void, Throwable>() {
-                @Override
-                protected Throwable doInBackground(Void... params) {
-                    try {
-                        if (cancellationSignal.isCanceled()) {
-                            return null;
-                        }
-
-                        PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
-                                pdfAttributes);
-
-                        Bitmap maybeGrayscale = convertBitmapForColorMode(bitmap,
-                                pdfAttributes.getColorMode());
-
-                        if (cancellationSignal.isCanceled()) {
-                            return null;
-                        }
-
-                        try {
-                            PdfDocument.Page page = pdfDocument.startPage(1);
-
-                            RectF contentRect;
-                            if (mIsMinMarginsHandlingCorrect) {
-                                contentRect = new RectF(page.getInfo().getContentRect());
-                            } else {
-                                // Create dummy doc that has the margins to compute correctly sized
-                                // content rectangle
-                                PrintedPdfDocument dummyDocument = new PrintedPdfDocument(mContext,
-                                        attributes);
-                                PdfDocument.Page dummyPage = dummyDocument.startPage(1);
-                                contentRect = new RectF(dummyPage.getInfo().getContentRect());
-                                dummyDocument.finishPage(dummyPage);
-                                dummyDocument.close();
-                            }
-
-                            // Resize bitmap
-                            Matrix matrix = getMatrix(
-                                    maybeGrayscale.getWidth(), maybeGrayscale.getHeight(),
-                                    contentRect, fittingMode);
-
-                            if (mIsMinMarginsHandlingCorrect) {
-                                // The pdfDocument takes care of the positioning and margins
-                            } else {
-                                // Move it to the correct position.
-                                matrix.postTranslate(contentRect.left, contentRect.top);
-
-                                // Cut off margins
-                                page.getCanvas().clipRect(contentRect);
-                            }
-
-                            // Draw the bitmap.
-                            page.getCanvas().drawBitmap(maybeGrayscale, matrix, null);
-
-                            // Finish the page.
-                            pdfDocument.finishPage(page);
-
-                            if (cancellationSignal.isCanceled()) {
-                                return null;
-                            }
-
-                            // Write the document.
-                            pdfDocument.writeTo(
-                                    new FileOutputStream(fileDescriptor.getFileDescriptor()));
-                            return null;
-                        } finally {
-                            pdfDocument.close();
-
-                            if (fileDescriptor != null) {
-                                try {
-                                    fileDescriptor.close();
-                                } catch (IOException ioe) {
-                                    // ignore
-                                }
-                            }
-                            // If we created a new instance for grayscaling, then recycle it here.
-                            if (maybeGrayscale != bitmap) {
-                                maybeGrayscale.recycle();
-                            }
-                        }
-                    } catch (Throwable t) {
-                        return t;
-                    }
-                }
-
-                @Override
-                protected void onPostExecute(Throwable throwable) {
-                    if (cancellationSignal.isCanceled()) {
-                        // Cancelled.
-                        writeResultCallback.onWriteCancelled();
-                    } else if (throwable == null) {
-                        // Done.
-                        writeResultCallback.onWriteFinished(
-                                new PageRange[] { PageRange.ALL_PAGES });
-                    } else {
-                        // Failed.
-                        Log.e(LOG_TAG, "Error writing printed content", throwable);
-                        writeResultCallback.onWriteFailed(null);
-                    }
-                }
-            }).execute();
-        }
-
-        /**
-         * Prints an image located at the Uri. Image types supported are those of
-         * <code>BitmapFactory.decodeStream</code> (JPEG, GIF, PNG, BMP, WEBP)
-         *
-         * @param jobName   The print job name.
-         * @param imageFile The <code>Uri</code> pointing to an image to print.
-         * @param callback Optional callback to observe when printing is finished.
-         * @throws FileNotFoundException if <code>Uri</code> is not pointing to a valid image.
-         */
-        @Override
-        public void printBitmap(final String jobName, final Uri imageFile,
-                final OnPrintFinishCallback callback)
-                throws FileNotFoundException {
-            final int fittingMode = mScaleMode;
-
-            PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() {
-                private PrintAttributes mAttributes;
-                AsyncTask<Uri, Boolean, Bitmap> mLoadBitmap;
-                Bitmap mBitmap = null;
-
-                @Override
-                public void onLayout(final PrintAttributes oldPrintAttributes,
-                        final PrintAttributes newPrintAttributes,
-                        final CancellationSignal cancellationSignal,
-                        final LayoutResultCallback layoutResultCallback,
-                        Bundle bundle) {
-
-                    synchronized (this) {
-                        mAttributes = newPrintAttributes;
-                    }
-
-                    if (cancellationSignal.isCanceled()) {
-                        layoutResultCallback.onLayoutCancelled();
-                        return;
-                    }
-                    // we finished the load
-                    if (mBitmap != null) {
-                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
-                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
-                                .setPageCount(1)
-                                .build();
-                        boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
-                        layoutResultCallback.onLayoutFinished(info, changed);
-                        return;
-                    }
-
-                    mLoadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() {
-                        @Override
-                        protected void onPreExecute() {
-                            // First register for cancellation requests.
-                            cancellationSignal.setOnCancelListener(
-                                    new CancellationSignal.OnCancelListener() {
-                                        @Override
-                                        public void onCancel() { // on different thread
-                                            cancelLoad();
-                                            cancel(false);
-                                        }
-                                    });
-                        }
-
-                        @Override
-                        protected Bitmap doInBackground(Uri... uris) {
-                            try {
-                                return loadConstrainedBitmap(imageFile);
-                            } catch (FileNotFoundException e) {
-                          /* ignore */
-                            }
-                            return null;
-                        }
-
-                        @Override
-                        protected void onPostExecute(Bitmap bitmap) {
-                            super.onPostExecute(bitmap);
-
-                            // If orientation was not set by the caller, try to fit the bitmap on
-                            // the current paper by potentially rotating the bitmap by 90 degrees.
-                            if (bitmap != null
-                                    && (!mPrintActivityRespectsOrientation || mOrientation == 0)) {
-                                PrintAttributes.MediaSize mediaSize;
-
-                                synchronized (this) {
-                                    mediaSize = mAttributes.getMediaSize();
-                                }
-
-                                if (mediaSize != null) {
-                                    if (mediaSize.isPortrait() != isPortrait(bitmap)) {
-                                        Matrix rotation = new Matrix();
-
-                                        rotation.postRotate(90);
-                                        bitmap = Bitmap.createBitmap(bitmap, 0, 0,
-                                                bitmap.getWidth(), bitmap.getHeight(), rotation,
-                                                true);
-                                    }
-                                }
-                            }
-
-                            mBitmap = bitmap;
-                            if (bitmap != null) {
-                                PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
-                                        .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
-                                        .setPageCount(1)
-                                        .build();
-
-                                boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
-
-                                layoutResultCallback.onLayoutFinished(info, changed);
-
-                            } else {
-                                layoutResultCallback.onLayoutFailed(null);
-                            }
-                            mLoadBitmap = null;
-                        }
-
-                        @Override
-                        protected void onCancelled(Bitmap result) {
-                            // Task was cancelled, report that.
-                            layoutResultCallback.onLayoutCancelled();
-                            mLoadBitmap = null;
-                        }
-                    }.execute();
-                }
-
-                private void cancelLoad() {
-                    synchronized (mLock) { // prevent race with set null below
-                        if (mDecodeOptions != null) {
-                            mDecodeOptions.requestCancelDecode();
-                            mDecodeOptions = null;
-                        }
-                    }
-                }
-
-                @Override
-                public void onFinish() {
-                    super.onFinish();
-                    cancelLoad();
-                    if (mLoadBitmap != null) {
-                        mLoadBitmap.cancel(true);
-                    }
-                    if (callback != null) {
-                        callback.onFinish();
-                    }
-                    if (mBitmap != null) {
-                        mBitmap.recycle();
-                        mBitmap = null;
-                    }
-                }
-
-                @Override
-                public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
-                        CancellationSignal cancellationSignal,
-                        WriteResultCallback writeResultCallback) {
-                    writeBitmap(mAttributes, fittingMode, mBitmap, fileDescriptor,
-                            cancellationSignal, writeResultCallback);
-                }
-            };
-
-            PrintManager printManager =
-                    (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
-            PrintAttributes.Builder builder = new PrintAttributes.Builder();
-            builder.setColorMode(mColorMode);
-
-            if (mOrientation == ORIENTATION_LANDSCAPE || mOrientation == 0) {
-                builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE);
-            } else if (mOrientation == ORIENTATION_PORTRAIT) {
-                builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
-            }
-            PrintAttributes attr = builder.build();
-
-            printManager.print(jobName, printDocumentAdapter, attr);
-        }
-
-        /**
-         * Loads a bitmap while limiting its size
-         *
-         * @param uri           location of a valid image
-         * @return the Bitmap
-         * @throws FileNotFoundException if the Uri does not point to an image
-         */
-        private Bitmap loadConstrainedBitmap(Uri uri)
-                throws FileNotFoundException {
-            if (uri == null || mContext == null) {
-                throw new IllegalArgumentException("bad argument to getScaledBitmap");
-            }
-            // Get width and height of stored bitmap
-            BitmapFactory.Options opt = new BitmapFactory.Options();
-            opt.inJustDecodeBounds = true;
-            loadBitmap(uri, opt);
-
-            int w = opt.outWidth;
-            int h = opt.outHeight;
-
-            // If bitmap cannot be decoded, return null
-            if (w <= 0 || h <= 0) {
-                return null;
-            }
-
-            // Find best downsampling size
-            int imageSide = Math.max(w, h);
-
-            int sampleSize = 1;
-            while (imageSide > MAX_PRINT_SIZE) {
-                imageSide >>>= 1;
-                sampleSize <<= 1;
-            }
-
-            // Make sure sample size is reasonable
-            if (sampleSize <= 0 || 0 >= (Math.min(w, h) / sampleSize)) {
-                return null;
-            }
-            BitmapFactory.Options decodeOptions;
-            synchronized (mLock) { // prevent race with set null below
-                mDecodeOptions = new BitmapFactory.Options();
-                mDecodeOptions.inMutable = true;
-                mDecodeOptions.inSampleSize = sampleSize;
-                decodeOptions = mDecodeOptions;
-            }
-            try {
-                return loadBitmap(uri, decodeOptions);
-            } finally {
-                synchronized (mLock) {
-                    mDecodeOptions = null;
-                }
-            }
-        }
-
-        /**
-         * Returns the bitmap from the given uri loaded using the given options.
-         * Returns null on failure.
-         */
-        private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException {
-            if (uri == null || mContext == null) {
-                throw new IllegalArgumentException("bad argument to loadBitmap");
-            }
-            InputStream is = null;
-            try {
-                is = mContext.getContentResolver().openInputStream(uri);
-                return BitmapFactory.decodeStream(is, null, o);
-            } finally {
-                if (is != null) {
-                    try {
-                        is.close();
-                    } catch (IOException t) {
-                        Log.w(LOG_TAG, "close fail ", t);
-                    }
-                }
-            }
-        }
-
-        private Bitmap convertBitmapForColorMode(Bitmap original, @ColorMode int colorMode) {
-            if (colorMode != COLOR_MODE_MONOCHROME) {
-                return original;
-            }
-            // Create a grayscale bitmap
-            Bitmap grayscale = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
-                    Bitmap.Config.ARGB_8888);
-            Canvas c = new Canvas(grayscale);
-            Paint p = new Paint();
-            ColorMatrix cm = new ColorMatrix();
-            cm.setSaturation(0);
-            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
-            p.setColorFilter(f);
-            c.drawBitmap(original, 0, 0, p);
-            c.setBitmap(null);
-
-            return grayscale;
-        }
-    }
-
-    /**
-     * Api20 specific PrintManager API implementation.
-     */
-    @RequiresApi(20)
-    private static class PrintHelperApi20 extends PrintHelperApi19 {
-        PrintHelperApi20(Context context) {
-            super(context);
-
-
-            // There is a bug in the PrintActivity that causes it to ignore the orientation
-            mPrintActivityRespectsOrientation = false;
-        }
-    }
-
-    /**
-     * Api23 specific PrintManager API implementation.
-     */
-    @RequiresApi(23)
-    private static class PrintHelperApi23 extends PrintHelperApi20 {
-        @Override
-        protected PrintAttributes.Builder copyAttributes(PrintAttributes other) {
-            PrintAttributes.Builder b = super.copyAttributes(other);
-
-            if (other.getDuplexMode() != 0) {
-                b.setDuplexMode(other.getDuplexMode());
-            }
-
-            return b;
-        }
-
-        PrintHelperApi23(Context context) {
-            super(context);
-
-            mIsMinMarginsHandlingCorrect = false;
-        }
-    }
-
-    /**
-     * Api24 specific PrintManager API implementation.
-     */
-    @RequiresApi(24)
-    private static class PrintHelperApi24 extends PrintHelperApi23 {
-        PrintHelperApi24(Context context) {
-            super(context);
-
-            mIsMinMarginsHandlingCorrect = true;
-            mPrintActivityRespectsOrientation = true;
-        }
-    }
-
-    /**
      * Constructs the PrintHelper that can be used to print images.
      *
      * @param context A context for accessing system resources.
      */
     public PrintHelper(@NonNull Context context) {
-        if (Build.VERSION.SDK_INT >= 24) {
-            mImpl = new PrintHelperApi24(context);
-        } else if (Build.VERSION.SDK_INT >= 23) {
-            mImpl = new PrintHelperApi23(context);
-        } else if (Build.VERSION.SDK_INT >= 20) {
-            mImpl = new PrintHelperApi20(context);
-        } else if (Build.VERSION.SDK_INT >= 19) {
-            mImpl = new PrintHelperApi19(context);
-        } else {
-            // System does not support printing.
-            mImpl = new PrintHelperStub();
-        }
+        mContext = context;
     }
 
     /**
@@ -915,7 +166,7 @@
      *                  {@link #SCALE_MODE_FILL}
      */
     public void setScaleMode(@ScaleMode int scaleMode) {
-        mImpl.setScaleMode(scaleMode);
+        mScaleMode = scaleMode;
     }
 
     /**
@@ -926,7 +177,7 @@
      */
     @ScaleMode
     public int getScaleMode() {
-        return mImpl.getScaleMode();
+        return mScaleMode;
     }
 
     /**
@@ -938,7 +189,7 @@
      * {@link #COLOR_MODE_COLOR} and {@link #COLOR_MODE_MONOCHROME}.
      */
     public void setColorMode(@ColorMode int colorMode) {
-        mImpl.setColorMode(colorMode);
+        mColorMode = colorMode;
     }
 
     /**
@@ -949,7 +200,7 @@
      */
     @ColorMode
     public int getColorMode() {
-        return mImpl.getColorMode();
+        return mColorMode;
     }
 
     /**
@@ -960,7 +211,7 @@
      *                    {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
      */
     public void setOrientation(int orientation) {
-        mImpl.setOrientation(orientation);
+        mOrientation = orientation;
     }
 
     /**
@@ -970,7 +221,11 @@
      * {@link #ORIENTATION_LANDSCAPE} or {@link #ORIENTATION_PORTRAIT}.
      */
     public int getOrientation() {
-        return mImpl.getOrientation();
+        // Unset defaults to landscape but might turn image
+        if (Build.VERSION.SDK_INT >= 19 && mOrientation == 0) {
+            return ORIENTATION_LANDSCAPE;
+        }
+        return mOrientation;
     }
 
 
@@ -981,7 +236,7 @@
      * @param bitmap  The bitmap to print.
      */
     public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap) {
-        mImpl.printBitmap(jobName, bitmap, null);
+        printBitmap(jobName, bitmap, null);
     }
 
     /**
@@ -991,9 +246,63 @@
      * @param bitmap  The bitmap to print.
      * @param callback Optional callback to observe when printing is finished.
      */
-    public void printBitmap(@NonNull String jobName, @NonNull Bitmap bitmap,
-            @Nullable OnPrintFinishCallback callback) {
-        mImpl.printBitmap(jobName, bitmap, callback);
+    public void printBitmap(@NonNull final String jobName, @NonNull final Bitmap bitmap,
+            @Nullable final OnPrintFinishCallback callback) {
+        if (Build.VERSION.SDK_INT < 19 || bitmap == null) {
+            return;
+        }
+
+        final int fittingMode = mScaleMode; // grab the fitting mode at time of call
+        PrintManager printManager =
+                (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
+        PrintAttributes.MediaSize mediaSize;
+        if (isPortrait(bitmap)) {
+            mediaSize = PrintAttributes.MediaSize.UNKNOWN_PORTRAIT;
+        } else {
+            mediaSize = PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE;
+        }
+        PrintAttributes attr = new PrintAttributes.Builder()
+                .setMediaSize(mediaSize)
+                .setColorMode(mColorMode)
+                .build();
+
+        printManager.print(jobName,
+                new PrintDocumentAdapter() {
+                    private PrintAttributes mAttributes;
+
+                    @Override
+                    public void onLayout(PrintAttributes oldPrintAttributes,
+                            PrintAttributes newPrintAttributes,
+                            CancellationSignal cancellationSignal,
+                            LayoutResultCallback layoutResultCallback,
+                            Bundle bundle) {
+
+                        mAttributes = newPrintAttributes;
+
+                        PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
+                                .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
+                                .setPageCount(1)
+                                .build();
+                        boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
+                        layoutResultCallback.onLayoutFinished(info, changed);
+                    }
+
+                    @Override
+                    public void onWrite(PageRange[] pageRanges,
+                            ParcelFileDescriptor fileDescriptor,
+                            CancellationSignal cancellationSignal,
+                            WriteResultCallback writeResultCallback) {
+                        writeBitmap(mAttributes, fittingMode, bitmap, fileDescriptor,
+                                cancellationSignal, writeResultCallback);
+                    }
+
+                    @Override
+                    public void onFinish() {
+                        if (callback != null) {
+                            callback.onFinish();
+                        }
+                    }
+                }, attr);
     }
 
     /**
@@ -1007,7 +316,7 @@
      */
     public void printBitmap(@NonNull String jobName, @NonNull Uri imageFile)
             throws FileNotFoundException {
-        mImpl.printBitmap(jobName, imageFile, null);
+        printBitmap(jobName, imageFile, null);
     }
 
     /**
@@ -1020,9 +329,460 @@
      * @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(@NonNull String jobName, @NonNull Uri imageFile,
-            @Nullable OnPrintFinishCallback callback)
+    public void printBitmap(@NonNull final String jobName, @NonNull final Uri imageFile,
+            @Nullable final OnPrintFinishCallback callback)
             throws FileNotFoundException {
-        mImpl.printBitmap(jobName, imageFile, callback);
+        if (Build.VERSION.SDK_INT < 19) {
+            return;
+        }
+
+        final int fittingMode = mScaleMode;
+
+        PrintDocumentAdapter printDocumentAdapter = new PrintDocumentAdapter() {
+            private PrintAttributes mAttributes;
+            AsyncTask<Uri, Boolean, Bitmap> mLoadBitmap;
+            Bitmap mBitmap = null;
+
+            @Override
+            public void onLayout(final PrintAttributes oldPrintAttributes,
+                    final PrintAttributes newPrintAttributes,
+                    final CancellationSignal cancellationSignal,
+                    final LayoutResultCallback layoutResultCallback,
+                    Bundle bundle) {
+
+                synchronized (this) {
+                    mAttributes = newPrintAttributes;
+                }
+
+                if (cancellationSignal.isCanceled()) {
+                    layoutResultCallback.onLayoutCancelled();
+                    return;
+                }
+                // we finished the load
+                if (mBitmap != null) {
+                    PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
+                            .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
+                            .setPageCount(1)
+                            .build();
+                    boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
+                    layoutResultCallback.onLayoutFinished(info, changed);
+                    return;
+                }
+
+                mLoadBitmap = new AsyncTask<Uri, Boolean, Bitmap>() {
+                    @Override
+                    protected void onPreExecute() {
+                        // First register for cancellation requests.
+                        cancellationSignal.setOnCancelListener(
+                                new CancellationSignal.OnCancelListener() {
+                                    @Override
+                                    public void onCancel() { // on different thread
+                                        cancelLoad();
+                                        cancel(false);
+                                    }
+                                });
+                    }
+
+                    @Override
+                    protected Bitmap doInBackground(Uri... uris) {
+                        try {
+                            return loadConstrainedBitmap(imageFile);
+                        } catch (FileNotFoundException e) {
+                          /* ignore */
+                        }
+                        return null;
+                    }
+
+                    @Override
+                    protected void onPostExecute(Bitmap bitmap) {
+                        super.onPostExecute(bitmap);
+
+                        // If orientation was not set by the caller, try to fit the bitmap on
+                        // the current paper by potentially rotating the bitmap by 90 degrees.
+                        if (bitmap != null
+                                && (!PRINT_ACTIVITY_RESPECTS_ORIENTATION || mOrientation == 0)) {
+                            PrintAttributes.MediaSize mediaSize;
+
+                            synchronized (this) {
+                                mediaSize = mAttributes.getMediaSize();
+                            }
+
+                            if (mediaSize != null) {
+                                if (mediaSize.isPortrait() != isPortrait(bitmap)) {
+                                    Matrix rotation = new Matrix();
+
+                                    rotation.postRotate(90);
+                                    bitmap = Bitmap.createBitmap(bitmap, 0, 0,
+                                            bitmap.getWidth(), bitmap.getHeight(), rotation,
+                                            true);
+                                }
+                            }
+                        }
+
+                        mBitmap = bitmap;
+                        if (bitmap != null) {
+                            PrintDocumentInfo info = new PrintDocumentInfo.Builder(jobName)
+                                    .setContentType(PrintDocumentInfo.CONTENT_TYPE_PHOTO)
+                                    .setPageCount(1)
+                                    .build();
+
+                            boolean changed = !newPrintAttributes.equals(oldPrintAttributes);
+
+                            layoutResultCallback.onLayoutFinished(info, changed);
+
+                        } else {
+                            layoutResultCallback.onLayoutFailed(null);
+                        }
+                        mLoadBitmap = null;
+                    }
+
+                    @Override
+                    protected void onCancelled(Bitmap result) {
+                        // Task was cancelled, report that.
+                        layoutResultCallback.onLayoutCancelled();
+                        mLoadBitmap = null;
+                    }
+                }.execute();
+            }
+
+            private void cancelLoad() {
+                synchronized (mLock) { // prevent race with set null below
+                    if (mDecodeOptions != null) {
+                        mDecodeOptions.requestCancelDecode();
+                        mDecodeOptions = null;
+                    }
+                }
+            }
+
+            @Override
+            public void onFinish() {
+                super.onFinish();
+                cancelLoad();
+                if (mLoadBitmap != null) {
+                    mLoadBitmap.cancel(true);
+                }
+                if (callback != null) {
+                    callback.onFinish();
+                }
+                if (mBitmap != null) {
+                    mBitmap.recycle();
+                    mBitmap = null;
+                }
+            }
+
+            @Override
+            public void onWrite(PageRange[] pageRanges, ParcelFileDescriptor fileDescriptor,
+                    CancellationSignal cancellationSignal,
+                    WriteResultCallback writeResultCallback) {
+                writeBitmap(mAttributes, fittingMode, mBitmap, fileDescriptor,
+                        cancellationSignal, writeResultCallback);
+            }
+        };
+
+        PrintManager printManager =
+                (PrintManager) mContext.getSystemService(Context.PRINT_SERVICE);
+        PrintAttributes.Builder builder = new PrintAttributes.Builder();
+        builder.setColorMode(mColorMode);
+
+        if (mOrientation == ORIENTATION_LANDSCAPE || mOrientation == 0) {
+            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_LANDSCAPE);
+        } else if (mOrientation == ORIENTATION_PORTRAIT) {
+            builder.setMediaSize(PrintAttributes.MediaSize.UNKNOWN_PORTRAIT);
+        }
+        PrintAttributes attr = builder.build();
+
+        printManager.print(jobName, printDocumentAdapter, attr);
+    }
+
+    /**
+     * Check if the supplied bitmap should best be printed on a portrait orientation paper.
+     *
+     * @param bitmap The bitmap to be printed.
+     * @return true iff the picture should best be printed on a portrait orientation paper.
+     */
+    private static boolean isPortrait(Bitmap bitmap) {
+        return bitmap.getWidth() <= bitmap.getHeight();
+    }
+
+    /**
+     * Create a build with a copy from the other print attributes.
+     *
+     * @param other The other print attributes
+     *
+     * @return A builder that will build print attributes that match the other attributes
+     */
+    @RequiresApi(19)
+    private static PrintAttributes.Builder copyAttributes(PrintAttributes other) {
+        PrintAttributes.Builder b = (new PrintAttributes.Builder())
+                .setMediaSize(other.getMediaSize())
+                .setResolution(other.getResolution())
+                .setMinMargins(other.getMinMargins());
+
+        if (other.getColorMode() != 0) {
+            b.setColorMode(other.getColorMode());
+        }
+
+        if (Build.VERSION.SDK_INT >= 23) {
+            if (other.getDuplexMode() != 0) {
+                b.setDuplexMode(other.getDuplexMode());
+            }
+        }
+
+        return b;
+    }
+
+    /**
+     * Calculates the transform the print an Image to fill the page
+     *
+     * @param imageWidth  with of bitmap
+     * @param imageHeight height of bitmap
+     * @param content     The output page dimensions
+     * @param fittingMode The mode of fitting {@link #SCALE_MODE_FILL} vs
+     *                    {@link #SCALE_MODE_FIT}
+     * @return Matrix to be used in canvas.drawBitmap(bitmap, matrix, null) call
+     */
+    private static Matrix getMatrix(int imageWidth, int imageHeight, RectF content,
+            @ScaleMode int fittingMode) {
+        Matrix matrix = new Matrix();
+
+        // Compute and apply scale to fill the page.
+        float scale = content.width() / imageWidth;
+        if (fittingMode == SCALE_MODE_FILL) {
+            scale = Math.max(scale, content.height() / imageHeight);
+        } else {
+            scale = Math.min(scale, content.height() / imageHeight);
+        }
+        matrix.postScale(scale, scale);
+
+        // Center the content.
+        final float translateX = (content.width()
+                - imageWidth * scale) / 2;
+        final float translateY = (content.height()
+                - imageHeight * scale) / 2;
+        matrix.postTranslate(translateX, translateY);
+        return matrix;
+    }
+
+    /**
+     * Write a bitmap for a PDF document.
+     *
+     * @param attributes          The print attributes
+     * @param fittingMode         How to fit the bitmap
+     * @param bitmap              The bitmap to write
+     * @param fileDescriptor      The file to write to
+     * @param cancellationSignal  Signal cancelling operation
+     * @param writeResultCallback Callback to call once written
+     */
+    @RequiresApi(19)
+    private void writeBitmap(final PrintAttributes attributes, final int fittingMode,
+            final Bitmap bitmap, final ParcelFileDescriptor fileDescriptor,
+            final CancellationSignal cancellationSignal,
+            final PrintDocumentAdapter.WriteResultCallback writeResultCallback) {
+        final PrintAttributes pdfAttributes;
+        if (IS_MIN_MARGINS_HANDLING_CORRECT) {
+            pdfAttributes = attributes;
+        } else {
+            // If the handling of any margin != 0 is broken, strip the margins and add them to
+            // the bitmap later
+            pdfAttributes = copyAttributes(attributes)
+                    .setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0)).build();
+        }
+
+        (new AsyncTask<Void, Void, Throwable>() {
+            @Override
+            protected Throwable doInBackground(Void... params) {
+                try {
+                    if (cancellationSignal.isCanceled()) {
+                        return null;
+                    }
+
+                    PrintedPdfDocument pdfDocument = new PrintedPdfDocument(mContext,
+                            pdfAttributes);
+
+                    Bitmap maybeGrayscale = convertBitmapForColorMode(bitmap,
+                            pdfAttributes.getColorMode());
+
+                    if (cancellationSignal.isCanceled()) {
+                        return null;
+                    }
+
+                    try {
+                        PdfDocument.Page page = pdfDocument.startPage(1);
+
+                        RectF contentRect;
+                        if (IS_MIN_MARGINS_HANDLING_CORRECT) {
+                            contentRect = new RectF(page.getInfo().getContentRect());
+                        } else {
+                            // Create dummy doc that has the margins to compute correctly sized
+                            // content rectangle
+                            PrintedPdfDocument dummyDocument = new PrintedPdfDocument(mContext,
+                                    attributes);
+                            PdfDocument.Page dummyPage = dummyDocument.startPage(1);
+                            contentRect = new RectF(dummyPage.getInfo().getContentRect());
+                            dummyDocument.finishPage(dummyPage);
+                            dummyDocument.close();
+                        }
+
+                        // Resize bitmap
+                        Matrix matrix = getMatrix(
+                                maybeGrayscale.getWidth(), maybeGrayscale.getHeight(),
+                                contentRect, fittingMode);
+
+                        if (IS_MIN_MARGINS_HANDLING_CORRECT) {
+                            // The pdfDocument takes care of the positioning and margins
+                        } else {
+                            // Move it to the correct position.
+                            matrix.postTranslate(contentRect.left, contentRect.top);
+
+                            // Cut off margins
+                            page.getCanvas().clipRect(contentRect);
+                        }
+
+                        // Draw the bitmap.
+                        page.getCanvas().drawBitmap(maybeGrayscale, matrix, null);
+
+                        // Finish the page.
+                        pdfDocument.finishPage(page);
+
+                        if (cancellationSignal.isCanceled()) {
+                            return null;
+                        }
+
+                        // Write the document.
+                        pdfDocument.writeTo(
+                                new FileOutputStream(fileDescriptor.getFileDescriptor()));
+                        return null;
+                    } finally {
+                        pdfDocument.close();
+
+                        if (fileDescriptor != null) {
+                            try {
+                                fileDescriptor.close();
+                            } catch (IOException ioe) {
+                                // ignore
+                            }
+                        }
+                        // If we created a new instance for grayscaling, then recycle it here.
+                        if (maybeGrayscale != bitmap) {
+                            maybeGrayscale.recycle();
+                        }
+                    }
+                } catch (Throwable t) {
+                    return t;
+                }
+            }
+
+            @Override
+            protected void onPostExecute(Throwable throwable) {
+                if (cancellationSignal.isCanceled()) {
+                    // Cancelled.
+                    writeResultCallback.onWriteCancelled();
+                } else if (throwable == null) {
+                    // Done.
+                    writeResultCallback.onWriteFinished(
+                            new PageRange[] { PageRange.ALL_PAGES });
+                } else {
+                    // Failed.
+                    Log.e(LOG_TAG, "Error writing printed content", throwable);
+                    writeResultCallback.onWriteFailed(null);
+                }
+            }
+        }).execute();
+    }
+
+    /**
+     * Loads a bitmap while limiting its size
+     *
+     * @param uri           location of a valid image
+     * @return the Bitmap
+     * @throws FileNotFoundException if the Uri does not point to an image
+     */
+    private Bitmap loadConstrainedBitmap(Uri uri)
+            throws FileNotFoundException {
+        if (uri == null || mContext == null) {
+            throw new IllegalArgumentException("bad argument to getScaledBitmap");
+        }
+        // Get width and height of stored bitmap
+        BitmapFactory.Options opt = new BitmapFactory.Options();
+        opt.inJustDecodeBounds = true;
+        loadBitmap(uri, opt);
+
+        int w = opt.outWidth;
+        int h = opt.outHeight;
+
+        // If bitmap cannot be decoded, return null
+        if (w <= 0 || h <= 0) {
+            return null;
+        }
+
+        // Find best downsampling size
+        int imageSide = Math.max(w, h);
+
+        int sampleSize = 1;
+        while (imageSide > MAX_PRINT_SIZE) {
+            imageSide >>>= 1;
+            sampleSize <<= 1;
+        }
+
+        // Make sure sample size is reasonable
+        if (sampleSize <= 0 || 0 >= (Math.min(w, h) / sampleSize)) {
+            return null;
+        }
+        BitmapFactory.Options decodeOptions;
+        synchronized (mLock) { // prevent race with set null below
+            mDecodeOptions = new BitmapFactory.Options();
+            mDecodeOptions.inMutable = true;
+            mDecodeOptions.inSampleSize = sampleSize;
+            decodeOptions = mDecodeOptions;
+        }
+        try {
+            return loadBitmap(uri, decodeOptions);
+        } finally {
+            synchronized (mLock) {
+                mDecodeOptions = null;
+            }
+        }
+    }
+
+    /**
+     * Returns the bitmap from the given uri loaded using the given options.
+     * Returns null on failure.
+     */
+    private Bitmap loadBitmap(Uri uri, BitmapFactory.Options o) throws FileNotFoundException {
+        if (uri == null || mContext == null) {
+            throw new IllegalArgumentException("bad argument to loadBitmap");
+        }
+        InputStream is = null;
+        try {
+            is = mContext.getContentResolver().openInputStream(uri);
+            return BitmapFactory.decodeStream(is, null, o);
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException t) {
+                    Log.w(LOG_TAG, "close fail ", t);
+                }
+            }
+        }
+    }
+
+    private static Bitmap convertBitmapForColorMode(Bitmap original, @ColorMode int colorMode) {
+        if (colorMode != COLOR_MODE_MONOCHROME) {
+            return original;
+        }
+        // Create a grayscale bitmap
+        Bitmap grayscale = Bitmap.createBitmap(original.getWidth(), original.getHeight(),
+                Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(grayscale);
+        Paint p = new Paint();
+        ColorMatrix cm = new ColorMatrix();
+        cm.setSaturation(0);
+        ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
+        p.setColorFilter(f);
+        c.drawBitmap(original, 0, 0, p);
+        c.setBitmap(null);
+
+        return grayscale;
     }
 }
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
new file mode 100644
index 0000000..fd32902
--- /dev/null
+++ b/room/common/api/current.txt
@@ -0,0 +1,112 @@
+package androidx.room {
+
+  public abstract class ColumnInfo implements java.lang.annotation.Annotation {
+    field public static final int BINARY = 2; // 0x2
+    field public static final int BLOB = 5; // 0x5
+    field public static final java.lang.String INHERIT_FIELD_NAME = "[field-name]";
+    field public static final int INTEGER = 3; // 0x3
+    field public static final int LOCALIZED = 5; // 0x5
+    field public static final int NOCASE = 3; // 0x3
+    field public static final int REAL = 4; // 0x4
+    field public static final int RTRIM = 4; // 0x4
+    field public static final int TEXT = 2; // 0x2
+    field public static final int UNDEFINED = 1; // 0x1
+    field public static final int UNICODE = 6; // 0x6
+    field public static final int UNSPECIFIED = 1; // 0x1
+  }
+
+  public static abstract class ColumnInfo.Collate implements java.lang.annotation.Annotation {
+  }
+
+  public static abstract class ColumnInfo.SQLiteTypeAffinity implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Dao implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Database implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Delete implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Embedded implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Entity implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class ForeignKey implements java.lang.annotation.Annotation {
+    field public static final int CASCADE = 5; // 0x5
+    field public static final int NO_ACTION = 1; // 0x1
+    field public static final int RESTRICT = 2; // 0x2
+    field public static final int SET_DEFAULT = 4; // 0x4
+    field public static final int SET_NULL = 3; // 0x3
+  }
+
+  public static abstract class ForeignKey.Action implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Ignore implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Index implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Insert implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class OnConflictStrategy implements java.lang.annotation.Annotation {
+    field public static final int ABORT = 3; // 0x3
+    field public static final int FAIL = 4; // 0x4
+    field public static final int IGNORE = 5; // 0x5
+    field public static final int REPLACE = 1; // 0x1
+    field public static final int ROLLBACK = 2; // 0x2
+  }
+
+  public abstract class PrimaryKey implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Query implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class RawQuery implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Relation implements java.lang.annotation.Annotation {
+  }
+
+  public class RoomWarnings {
+    ctor public RoomWarnings();
+    field public static final java.lang.String CANNOT_CREATE_VERIFICATION_DATABASE = "ROOM_CANNOT_CREATE_VERIFICATION_DATABASE";
+    field public static final java.lang.String CURSOR_MISMATCH = "ROOM_CURSOR_MISMATCH";
+    field public static final java.lang.String DEFAULT_CONSTRUCTOR = "ROOM_DEFAULT_CONSTRUCTOR";
+    field public static final java.lang.String INDEX_FROM_EMBEDDED_ENTITY_IS_DROPPED = "ROOM_EMBEDDED_ENTITY_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
+    field public static final java.lang.String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final java.lang.String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
+    field public static final java.lang.String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
+    field public static final java.lang.String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
+    field public static final java.lang.String PRIMARY_KEY_FROM_EMBEDDED_IS_DROPPED = "ROOM_EMBEDDED_PRIMARY_KEY_IS_DROPPED";
+    field public static final java.lang.String RELATION_QUERY_WITHOUT_TRANSACTION = "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
+    field public static final java.lang.String RELATION_TYPE_MISMATCH = "ROOM_RELATION_TYPE_MISMATCH";
+  }
+
+  public abstract class SkipQueryVerification implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Transaction implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TypeConverter implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class TypeConverters implements java.lang.annotation.Annotation {
+  }
+
+  public abstract class Update implements java.lang.annotation.Annotation {
+  }
+
+}
+
diff --git a/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt b/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
index 8ff200b..5cf3476 100644
--- a/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/ext/javapoet_ext.kt
@@ -88,7 +88,7 @@
 
 object ArchTypeNames {
     val APP_EXECUTOR: ClassName =
-            ClassName.get("androidx.executor", "ArchTaskExecutor")
+            ClassName.get("androidx.arch.core.executor", "ArchTaskExecutor")
 }
 
 object PagingTypeNames {
diff --git a/room/compiler/src/test/kotlin/androidx/room/testing/test_util.kt b/room/compiler/src/test/kotlin/androidx/room/testing/test_util.kt
index 5c11114..345f94a 100644
--- a/room/compiler/src/test/kotlin/androidx/room/testing/test_util.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/testing/test_util.kt
@@ -134,7 +134,7 @@
 
 /**
  * Create mocks of [Element] and [TypeMirror] so that they can be used for instantiating a fake
- * [android.arch.persistence.room.vo.Field].
+ * [androidx.room.vo.Field].
  */
 fun mockElementAndType(): Pair<Element, TypeMirror> {
     val element = mock(Element::class.java)
diff --git a/room/guava/src/main/java/androidx/room/guava/GuavaRoom.java b/room/guava/src/main/java/androidx/room/guava/GuavaRoom.java
index 2f9c078..be483aa 100644
--- a/room/guava/src/main/java/androidx/room/guava/GuavaRoom.java
+++ b/room/guava/src/main/java/androidx/room/guava/GuavaRoom.java
@@ -18,7 +18,7 @@
 import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
 
 import androidx.annotation.RestrictTo;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.room.RoomSQLiteQuery;
 
 import com.google.common.util.concurrent.FutureCallback;
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/BooksDaoTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/BooksDaoTest.kt
index d49f6f9..d73bc96 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/BooksDaoTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/BooksDaoTest.kt
@@ -18,7 +18,7 @@
 
 import android.database.sqlite.SQLiteConstraintException
 import android.support.test.filters.SmallTest
-import androidx.executor.ArchTaskExecutor
+import androidx.arch.core.executor.ArchTaskExecutor
 import androidx.room.integration.kotlintestapp.vo.Author
 import androidx.room.integration.kotlintestapp.vo.Book
 import androidx.room.integration.kotlintestapp.vo.BookWithPublisher
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/TestDatabaseTest.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/TestDatabaseTest.kt
index 1751992..0f213188 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/TestDatabaseTest.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/test/TestDatabaseTest.kt
@@ -17,7 +17,7 @@
 package androidx.room.integration.kotlintestapp.test
 
 import android.support.test.InstrumentationRegistry
-import androidx.executor.testing.InstantTaskExecutorRule
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
 import androidx.room.Room
 import androidx.room.integration.kotlintestapp.TestDatabase
 import androidx.room.integration.kotlintestapp.dao.BooksDao
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/paging/DataSourceFactoryTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/paging/DataSourceFactoryTest.java
index f30b5b4..92a43b7 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/paging/DataSourceFactoryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/paging/DataSourceFactoryTest.java
@@ -26,8 +26,8 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/FunnyNamedDaoTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/FunnyNamedDaoTest.java
index 0583cff..9d0da7f 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/FunnyNamedDaoTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/FunnyNamedDaoTest.java
@@ -25,7 +25,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.room.integration.testapp.vo.FunnyNamedEntity;
 
 import org.junit.Rule;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/InvalidationTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/InvalidationTest.java
index ef53250..fe66855 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/InvalidationTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/InvalidationTest.java
@@ -27,7 +27,7 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import androidx.annotation.NonNull;
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.room.InvalidationTracker;
 import androidx.room.Room;
 import androidx.room.integration.testapp.TestDatabase;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LiveDataQueryTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LiveDataQueryTest.java
index 9e59962..2b32a62 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LiveDataQueryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/LiveDataQueryTest.java
@@ -29,8 +29,8 @@
 import android.support.test.runner.AndroidJUnit4;
 
 import androidx.annotation.Nullable;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/QueryTransactionTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/QueryTransactionTest.java
index cb8f81f..152141d 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/QueryTransactionTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/QueryTransactionTest.java
@@ -24,8 +24,8 @@
 import android.support.test.filters.SmallTest;
 
 import androidx.annotation.NonNull;
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LiveData;
 import androidx.paging.DataSource;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RawQueryTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RawQueryTest.java
index 76d4bfc..e577c5b 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RawQueryTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RawQueryTest.java
@@ -26,7 +26,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import androidx.executor.testing.CountingTaskExecutorRule;
+import androidx.arch.core.executor.testing.CountingTaskExecutorRule;
 import androidx.lifecycle.LiveData;
 import androidx.room.integration.testapp.dao.RawDao;
 import androidx.room.integration.testapp.vo.NameAndLastName;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2Test.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2Test.java
index 3d7b4e4..9878cd2 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2Test.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2Test.java
@@ -23,8 +23,8 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import androidx.executor.ArchTaskExecutor;
-import androidx.executor.TaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.TaskExecutor;
 import androidx.room.EmptyResultSetException;
 import androidx.room.integration.testapp.vo.Pet;
 import androidx.room.integration.testapp.vo.User;
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java
index d9b8f9c..992d8f8 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/RxJava2WithInstantTaskExecutorTest.java
@@ -20,7 +20,7 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
-import androidx.executor.testing.InstantTaskExecutorRule;
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule;
 import androidx.room.Room;
 import androidx.room.integration.testapp.TestDatabase;
 import androidx.room.integration.testapp.vo.User;
diff --git a/room/integration-tests/testapp/src/main/java/androidx/room/integration/testapp/CustomerViewModel.java b/room/integration-tests/testapp/src/main/java/androidx/room/integration/testapp/CustomerViewModel.java
index a8f3a68..eca2552 100644
--- a/room/integration-tests/testapp/src/main/java/androidx/room/integration/testapp/CustomerViewModel.java
+++ b/room/integration-tests/testapp/src/main/java/androidx/room/integration/testapp/CustomerViewModel.java
@@ -19,7 +19,7 @@
 import android.app.Application;
 
 import androidx.annotation.WorkerThread;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.lifecycle.AndroidViewModel;
 import androidx.lifecycle.LiveData;
 import androidx.paging.DataSource;
diff --git a/room/runtime/src/main/java/androidx/room/InvalidationTracker.java b/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
index bec0999..801f5a3 100644
--- a/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
+++ b/room/runtime/src/main/java/androidx/room/InvalidationTracker.java
@@ -28,7 +28,7 @@
 import androidx.arch.core.internal.SafeIterableMap;
 import androidx.collection.ArrayMap;
 import androidx.collection.ArraySet;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.sqlite.db.SupportSQLiteDatabase;
 import androidx.sqlite.db.SupportSQLiteStatement;
 
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 457c112..d89cf00 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -31,7 +31,7 @@
 import androidx.annotation.WorkerThread;
 import androidx.collection.SparseArrayCompat;
 import androidx.core.app.ActivityManagerCompat;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 import androidx.room.migration.Migration;
 import androidx.sqlite.db.SimpleSQLiteQuery;
 import androidx.sqlite.db.SupportSQLiteDatabase;
diff --git a/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java b/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
index 22599b1..f4ffd24 100644
--- a/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
+++ b/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
@@ -35,7 +35,7 @@
 import android.database.sqlite.SQLiteException;
 
 import androidx.annotation.NonNull;
-import androidx.executor.JunitTaskExecutorRule;
+import androidx.arch.core.executor.JunitTaskExecutorRule;
 import androidx.sqlite.db.SupportSQLiteDatabase;
 import androidx.sqlite.db.SupportSQLiteOpenHelper;
 import androidx.sqlite.db.SupportSQLiteStatement;
diff --git a/room/rxjava2/src/main/java/androidx/room/RxRoom.java b/room/rxjava2/src/main/java/androidx/room/RxRoom.java
index b13e774..d2ba8bf 100644
--- a/room/rxjava2/src/main/java/androidx/room/RxRoom.java
+++ b/room/rxjava2/src/main/java/androidx/room/RxRoom.java
@@ -18,7 +18,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
-import androidx.executor.ArchTaskExecutor;
+import androidx.arch.core.executor.ArchTaskExecutor;
 
 import java.util.Set;
 import java.util.concurrent.Callable;
diff --git a/room/rxjava2/src/test/java/androidx/room/RxRoomTest.java b/room/rxjava2/src/test/java/androidx/room/RxRoomTest.java
index abf16d9..15a89bf 100644
--- a/room/rxjava2/src/test/java/androidx/room/RxRoomTest.java
+++ b/room/rxjava2/src/test/java/androidx/room/RxRoomTest.java
@@ -25,7 +25,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import androidx.executor.JunitTaskExecutorRule;
+import androidx.arch.core.executor.JunitTaskExecutorRule;
 
 import org.hamcrest.CoreMatchers;
 import org.junit.Before;
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 379b991..8f94bb9 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
@@ -19,6 +19,7 @@
 import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
 
 import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
+import static androidx.slice.builders.ListBuilder.INFINITY;
 import static androidx.slice.builders.ListBuilder.LARGE_IMAGE;
 import static androidx.slice.builders.ListBuilder.SMALL_IMAGE;
 
@@ -26,17 +27,18 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.provider.Settings;
 import android.text.SpannableString;
+import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.style.ForegroundColorSpan;
 import android.util.SparseArray;
 
 import androidx.annotation.NonNull;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceProvider;
 import androidx.slice.builders.GridRowBuilder;
@@ -46,6 +48,7 @@
 
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Examples of using slice template builders.
@@ -139,86 +142,100 @@
 
     private Slice createWeather(Uri sliceUri) {
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
-                "open weather app"), Icon.createWithResource(getContext(), R.drawable.weather_1),
+                "open weather app"),
+                IconCompat.createWithResource(getContext(), R.drawable.weather_1),
                 "Weather is happening!");
-        return new ListBuilder(getContext(), sliceUri).addGrid(gb -> gb
-                .setPrimaryAction(primaryAction)
-                .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
-                                SMALL_IMAGE)
-                        .addText("MON")
-                        .addTitleText("69\u00B0"))
-                .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_2),
-                                SMALL_IMAGE)
-                        .addText("TUE")
-                        .addTitleText("71\u00B0"))
-                .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_3),
-                                SMALL_IMAGE)
-                        .addText("WED")
-                        .addTitleText("76\u00B0"))
-                .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_4),
-                                SMALL_IMAGE)
-                        .addText("THU")
-                        .addTitleText("72\u00B0"))
-                .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
-                                SMALL_IMAGE)
-                        .addText("FRI")
-                        .addTitleText("68\u00B0")))
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
+                .addGrid(gb -> gb
+                        .setPrimaryAction(primaryAction)
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.weather_1),
+                                        SMALL_IMAGE)
+                                .addText("MON")
+                                .addTitleText("69\u00B0"))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.weather_2),
+                                        SMALL_IMAGE)
+                                .addText("TUE")
+                                .addTitleText("71\u00B0"))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.weather_3),
+                                        SMALL_IMAGE)
+                                .addText("WED")
+                                .addTitleText("76\u00B0"))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.weather_4),
+                                        SMALL_IMAGE)
+                                .addText("THU")
+                                .addTitleText("72\u00B0"))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.weather_1),
+                                        SMALL_IMAGE)
+                                .addText("FRI")
+                                .addTitleText("68\u00B0")))
                 .build();
     }
 
     private Slice createGallery(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xff4285F4)
                 .addRow(b -> b
-                    .setTitle("Family trip to Hawaii")
-                    .setSubtitle("Sep 30, 2017 - Oct 2, 2017"))
+                        .setTitle("Family trip to Hawaii")
+                        .setSubtitle("Sep 30, 2017 - Oct 2, 2017"))
                 .addAction(new SliceAction(
                         getBroadcastIntent(ACTION_TOAST, "cast photo album"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_cast),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_cast),
                         "Cast photo album"))
                 .addAction(new SliceAction(
                         getBroadcastIntent(ACTION_TOAST, "share photo album"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_share),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_share),
                         "Share photo album"))
                 .addGrid(b -> b
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
-                            LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
-                                LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
-                                LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
-                                LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
-                                LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
-                                LARGE_IMAGE))
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
-                                LARGE_IMAGE))
-                    .addSeeMoreAction(getBroadcastIntent(ACTION_TOAST, "see your gallery"))
-                    .setContentDescription("Images from your trip to Hawaii"))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_1),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_2),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_3),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_4),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_2),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_3),
+                                        LARGE_IMAGE))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.slices_4),
+                                        LARGE_IMAGE))
+                        .addSeeMoreAction(getBroadcastIntent(ACTION_TOAST, "see your gallery"))
+                        .setContentDescription("Images from your trip to Hawaii"))
                 .build();
     }
 
     private Slice createCatSlice(Uri sliceUri, boolean customSeeMore) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY);
         GridRowBuilder gb = new GridRowBuilder(b);
         PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "See cats you follow");
         if (customSeeMore) {
             GridRowBuilder.CellBuilder cb = new GridRowBuilder.CellBuilder(gb);
-            cb.addImage(Icon.createWithResource(getContext(), R.drawable.ic_right_caret),
+            cb.addImage(IconCompat.createWithResource(getContext(), R.drawable.ic_right_caret),
                     ICON_IMAGE);
             cb.setContentIntent(pi);
             cb.addTitleText("All cats");
@@ -227,59 +244,62 @@
             gb.addSeeMoreAction(pi);
         }
         gb.addCell(new GridRowBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.cat_1), SMALL_IMAGE)
-                    .addTitleText("Oreo"))
+                .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_1),
+                        SMALL_IMAGE)
+                .addTitleText("Oreo"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_2),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_2),
                                 SMALL_IMAGE)
                         .addTitleText("Silver"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_3),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_3),
                                 SMALL_IMAGE)
                         .addTitleText("Drake"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_5),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_5),
                                 SMALL_IMAGE)
                         .addTitleText("Olive"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_4),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_4),
                                 SMALL_IMAGE)
                         .addTitleText("Lady Marmalade"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_6),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_6),
                                 SMALL_IMAGE)
                         .addTitleText("Grapefruit"));
         return b.addGridRow(gb).build();
     }
 
     private Slice createContact2(Uri sliceUri) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY);
         ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b);
         GridRowBuilder gb = new GridRowBuilder(b);
         return b.setColor(0xff3949ab)
                 .addRow(rb
                         .setTitle("Mady Pitza")
                         .setSubtitle("Frequently contacted contact")
-                        .addEndItem(Icon.createWithResource(getContext(), R.drawable.mady),
+                        .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.mady),
                                 SMALL_IMAGE))
                 .addGridRow(gb
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                                .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call),
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_call),
                                         ICON_IMAGE)
                                 .addText("Call")
                                 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                                .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text),
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_text),
                                         ICON_IMAGE)
                                 .addText("Text")
                                 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                                .addImage(Icon.createWithResource(getContext(),
+                                .addImage(IconCompat.createWithResource(getContext(),
                                         R.drawable.ic_video), ICON_IMAGE)
                                 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
                                 .addText("Video"))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                                .addImage(Icon.createWithResource(getContext(),
+                                .addImage(IconCompat.createWithResource(getContext(),
                                         R.drawable.ic_email), ICON_IMAGE)
                                 .addText("Email")
                                 .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
@@ -292,35 +312,40 @@
                 Calendar.getInstance().getTimeInMillis(),
                 DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
-                "See contact info"), Icon.createWithResource(getContext(),
+                "See contact info"), IconCompat.createWithResource(getContext(),
                 R.drawable.mady), SMALL_IMAGE, "Mady");
 
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xff3949ab)
                 .setHeader(b -> b
                         .setTitle("Mady Pitza")
                         .setSummarySubtitle("Called " + lastCalledString)
                         .setPrimaryAction(primaryAction))
                 .addRow(b -> b
-                        .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_call),
+                        .setTitleItem(
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_call),
                                 ICON_IMAGE)
                         .setTitle("314-259-2653")
                         .setSubtitle("Call lasted 1 hr 17 min")
                         .addEndItem(lastCalled))
                 .addRow(b -> b
-                        .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_text),
+                        .setTitleItem(
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_text),
                                 ICON_IMAGE)
                         .setTitle("You: Coooooool see you then")
                         .addEndItem(System.currentTimeMillis() - 40 * DateUtils.MINUTE_IN_MILLIS))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "call"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_call), "Call mady"))
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_call),
+                        "Call mady"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "text"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_text), "Text mady"))
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_text),
+                        "Text mady"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "video"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_video),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_video),
                         "Video call mady"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "email"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_email), "Email mady"))
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_email),
+                        "Email mady"))
                 .build();
     }
 
@@ -330,7 +355,7 @@
                 .add(b -> b
                         .addText("yo home \uD83C\uDF55, I emailed you the info")
                         .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
-                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                        .addSource(IconCompat.createWithResource(getContext(), R.drawable.mady)))
                 .add(b -> b
                         .addText("just bought my tickets")
                         .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
@@ -338,53 +363,54 @@
                         .addText("yay! can't wait for getContext() weekend!\n"
                                 + "\uD83D\uDE00")
                         .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
-                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                        .addSource(IconCompat.createWithResource(getContext(), R.drawable.mady)))
                 .build();
 
     }
 
     private Slice createNoteSlice(Uri sliceUri) {
         // TODO: Remote input.
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xfff4b400)
                 .addRow(b -> b.setTitle("Create new note"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_create),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_create),
                         "Create note"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_voice),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_voice),
                         "Voice note"))
                 .addAction(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_camera),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_camera),
                         "Photo note"))
                 .build();
     }
 
     private Slice createReservationSlice(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xffFF5252)
                 .setHeader(b -> b
-                    .setTitle("Upcoming trip to Seattle")
-                    .setSubtitle("Feb 1 - 19 | 2 guests"))
+                        .setTitle("Upcoming trip to Seattle")
+                        .setSubtitle("Feb 1 - 19 | 2 guests"))
                 .addAction(new SliceAction(
                         getBroadcastIntent(ACTION_TOAST, "show location on map"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_location),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_location),
                         "Show reservation location"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "contact host"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_text),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_text),
                         "Contact host"))
                 .addGrid(b -> b
-                    .addCell(cb -> cb
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.reservation),
-                            LARGE_IMAGE)
-                        .setContentDescription("Image of your reservation in Seattle")))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.reservation),
+                                        LARGE_IMAGE)
+                                .setContentDescription("Image of your reservation in Seattle")))
                 .addGrid(b -> b
-                    .addCell(cb -> cb
-                        .addTitleText("Check In")
-                        .addText("12:00 PM, Feb 1"))
-                    .addCell(cb -> cb
-                        .addTitleText("Check Out")
-                        .addText("11:00 AM, Feb 19")))
+                        .addCell(cb -> cb
+                                .addTitleText("Check In")
+                                .addText("12:00 PM, Feb 1"))
+                        .addCell(cb -> cb
+                                .addTitleText("Check Out")
+                                .addText("11:00 AM, Feb 19")))
                 .build();
     }
 
@@ -398,55 +424,55 @@
         workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
 
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, "get ride"),
-                Icon.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
-        return new ListBuilder(getContext(), sliceUri)
+                IconCompat.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
+        return new ListBuilder(getContext(), sliceUri, -TimeUnit.MINUTES.toMillis(2))
                 .setColor(0xff0F9D58)
                 .setHeader(b -> b
-                    .setTitle("Get ride")
-                    .setSubtitle(headerSubtitle)
-                    .setSummarySubtitle("Ride to work in 12 min | Ride home in 1 hour 45 min")
-                    .setPrimaryAction(primaryAction))
+                        .setTitle("Get ride")
+                        .setSubtitle(headerSubtitle)
+                        .setSummarySubtitle("Ride to work in 12 min | Ride home in 1 hour 45 min")
+                        .setPrimaryAction(primaryAction))
                 .addRow(b -> b
-                    .setTitle("Work")
-                    .setSubtitle(workSubtitle)
-                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"),
-                            Icon.createWithResource(getContext(), R.drawable.ic_work),
-                            "Get ride to work")))
+                        .setTitle("Work")
+                        .setSubtitle(workSubtitle)
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_work),
+                                "Get ride to work")))
                 .addRow(b -> b
-                    .setTitle("Home")
-                    .setSubtitle(homeSubtitle)
-                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
-                            Icon.createWithResource(getContext(), R.drawable.ic_home),
-                            "Get ride home")))
+                        .setTitle("Home")
+                        .setSubtitle(homeSubtitle)
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_home),
+                                "Get ride home")))
                 .build();
     }
 
     private Slice createCustomToggleSlice(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xffff4081)
                 .addRow(b -> b
-                    .setTitle("Custom toggle")
-                    .setSubtitle("It can support two states")
-                    .setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST,
-                            "star toggled"),
-                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
-                            "Toggle star", true /* isChecked */)))
+                        .setTitle("Custom toggle")
+                        .setSubtitle("It can support two states")
+                        .setPrimaryAction(new SliceAction(getBroadcastIntent(ACTION_TOAST,
+                                "star toggled"),
+                                IconCompat.createWithResource(getContext(), R.drawable.toggle_star),
+                                "Toggle star", true /* isChecked */)))
                 .build();
     }
 
     private Slice createTwoCustomToggleSlices(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xffff4081)
                 .addRow(b -> b
                         .setTitle("2 toggles")
                         .setSubtitle("each supports two states")
                         .addEndItem(new SliceAction(
                                 getBroadcastIntent(ACTION_TOAST, "first star toggled"),
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                IconCompat.createWithResource(getContext(), R.drawable.toggle_star),
                                 "Toggle star", true /* isChecked */))
                         .addEndItem(new SliceAction(
                                 getBroadcastIntent(ACTION_TOAST, "second star toggled"),
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                IconCompat.createWithResource(getContext(), R.drawable.toggle_star),
                                 "Toggle star", false /* isChecked */)))
                 .build();
     }
@@ -476,32 +502,32 @@
         // 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");
+                IconCompat.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
         String toggleCDString = wifiEnabled ? "Turn wifi off" : "Turn wifi on";
         String sliceCDString = wifiEnabled ? "Wifi connected to " + state
                 : "Wifi disconnected, 10 networks available";
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri)
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xff4285f4)
                 .setHeader(b -> b
-                    .setTitle("Wi-fi")
-                    .setSubtitle(state)
-                    .setContentDescription(sliceCDString)
-                    .setPrimaryAction(primaryAction))
+                        .setTitle("Wi-fi")
+                        .setSubtitle(state)
+                        .setContentDescription(sliceCDString)
+                        .setPrimaryAction(primaryAction))
                 .addAction((new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
                         toggleCDString, finalWifiEnabled)));
 
         // Add fake wifi networks
-        int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+        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);
+            IconCompat icon = IconCompat.createWithResource(getContext(), iconId);
             final String networkName = "Network" + i;
             ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb);
             rb.setTitleItem(icon, ICON_IMAGE).setTitle(networkName);
             boolean locked = i % 3 == 0;
             if (locked) {
-                rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock),
+                rb.addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_lock),
                         ICON_IMAGE);
                 rb.setContentDescription("Connect to " + networkName + ", password needed");
             } else {
@@ -514,14 +540,15 @@
         }
 
         // Add keywords
-        String[] keywords = new String[] {"internet", "wifi", "data", "network"};
+        String[] keywords = new String[]{"internet", "wifi", "data", "network"};
         lb.setKeywords(Arrays.asList(keywords));
 
         // 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),
+                    .addEndItem(
+                            IconCompat.createWithResource(getContext(), R.drawable.ic_right_caret),
                             SMALL_IMAGE)
                     .setPrimaryAction(primaryAction));
         } else {
@@ -531,11 +558,12 @@
     }
 
     private Slice createStarRatingInputRange(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xffff4081)
                 .addInputRange(c -> c
                         .setTitle("Star rating")
-                        .setThumb(Icon.createWithResource(getContext(), R.drawable.ic_star_on))
+                        .setThumb(
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_star_on))
                         .setAction(getBroadcastIntent(ACTION_TOAST_RANGE_VALUE, null))
                         .setMax(5)
                         .setValue(3)
@@ -544,7 +572,7 @@
     }
 
     private Slice createDownloadProgressRange(Uri sliceUri) {
-        return new ListBuilder(getContext(), sliceUri)
+        return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setColor(0xffff4081)
                 .addRange(c -> c
                         .setTitle("Download progress")
@@ -577,27 +605,35 @@
             update(1500, mListSummaries, 1, "12 miles | 12 min | $9.00", sliceUri, r);
             update(1700, mListSummaries, 2, "5 miles | 10 min | $8.00", sliceUri, r);
         }
-        Slice s = new ListBuilder(getContext(), sliceUri)
+        CharSequence work = mListSummaries.get(0, "");
+        CharSequence home = mListSummaries.get(1, "");
+        CharSequence school = mListSummaries.get(2, "");
+        Slice s = new ListBuilder(getContext(), sliceUri, -TimeUnit.MINUTES.toMillis(50))
                 .addRow(b -> b
                         .setTitle("Work")
-                        .setSubtitle(mListSummaries.get(0, ""), updating)
-                        .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_work),
+                        .setSubtitle(work,
+                                updating || TextUtils.isEmpty(work))
+                        .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.ic_work),
                                 ICON_IMAGE))
                 .addRow(b -> b
                         .setTitle("Home")
-                        .setSubtitle(mListSummaries.get(1, ""), updating)
+                        .setSubtitle(mListSummaries.get(1, ""),
+                                updating || TextUtils.isEmpty(home))
                         .addEndItem(
-                                Icon.createWithResource(getContext(), R.drawable.ic_home),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                                 ICON_IMAGE))
                 .addRow(b -> b
                         .setTitle("School")
-                        .setSubtitle(mListSummaries.get(2, ""), updating)
-                        .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_school),
+                        .setSubtitle(mListSummaries.get(2, ""),
+                                updating || TextUtils.isEmpty(school))
+                        .addEndItem(
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_school),
                                 ICON_IMAGE))
                 .build();
         return s;
     }
 
+    // TODO: Should test large image grids
     private Slice createLoadingGridSlice(Uri sliceUri) {
         boolean updating = mGridLastUpdate == 0
                 || mGridLastUpdate < (System.currentTimeMillis() - 10 * System.currentTimeMillis());
@@ -610,27 +646,40 @@
             update(1500, mGridSummaries, 3, "33 min", sliceUri, r);
             update(1000, mGridSummaries, 4, "12 min", sliceUri, r);
         }
-        Slice s = new ListBuilder(getContext(), sliceUri)
+        CharSequence title = mGridSummaries.get(0, "");
+        CharSequence subtitle = mGridSummaries.get(1, "");
+        CharSequence home = mGridSummaries.get(2, "");
+        CharSequence work = mGridSummaries.get(3, "");
+        CharSequence school = mGridSummaries.get(4, "");
+        Slice s = new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setHeader(hb -> hb
-                        .setTitle(mGridSummaries.get(0, ""), updating)
-                        .setSubtitle(mGridSummaries.get(1, ""), updating))
+                        .setTitle(title,
+                                updating || TextUtils.isEmpty(title))
+                        .setSubtitle(subtitle,
+                                updating || TextUtils.isEmpty(subtitle)))
                 .addGrid(gb -> gb
-                    .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_home),
-                                    ICON_IMAGE)
-                            .addTitleText("Home")
-                            .addText(mGridSummaries.get(2, ""), updating))
-                    .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_work),
-                                    ICON_IMAGE)
-                            .addTitleText("Work")
-                            .addText(mGridSummaries.get(3, ""), updating))
-                    .addCell(cb -> cb
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_school),
-                                    ICON_IMAGE)
-                            .addTitleText("School")
-                            .addText(mGridSummaries.get(4, ""), updating)))
-                    .build();
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_home),
+                                        ICON_IMAGE)
+                                .addTitleText("Home")
+                                .addText(home,
+                                        updating || TextUtils.isEmpty(home)))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_work),
+                                        ICON_IMAGE)
+                                .addTitleText("Work")
+                                .addText(work,
+                                        updating || TextUtils.isEmpty(work)))
+                        .addCell(cb -> cb
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_school),
+                                        ICON_IMAGE)
+                                .addTitleText("School")
+                                .addText(school,
+                                        updating || TextUtils.isEmpty(school))))
+                .build();
         return s;
     }
 
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
index 666f7d2..bdf0b49 100644
--- a/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
+++ b/samples/ViewPager2Demos/src/main/java/com/example/androidx/viewpager2/CardFragmentActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
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
index 02b52f8..563f73d 100644
--- 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
@@ -1,5 +1,5 @@
 /*
- * Copyright 2018 The Android Open Source Project
+ * 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.
diff --git a/settings.gradle b/settings.gradle
index 3e6c4c7..581897d 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -40,7 +40,7 @@
 includeProject(":car", "car")
 includeProject(":cardview", "cardview")
 includeProject(":collection", "collection")
-includeProject(":collection-ktx", "collection-ktx")
+includeProject(":collection-ktx", "collection/ktx")
 includeProject(":contentpaging", "content")
 includeProject(":coordinatorlayout", "coordinatorlayout")
 includeProject(":core", "compat")
@@ -68,7 +68,7 @@
 includeProject(":media", "media")
 includeProject(":mediarouter", "mediarouter")
 includeProject(":palette", "palette")
-includeProject(":palette-ktx", "palette-ktx")
+includeProject(":palette-ktx", "palette/ktx")
 includeProject(":percentlayout", "percent")
 includeProject(":preference", "preference")
 includeProject(":print", "print")
diff --git a/slices/builders/api/current.txt b/slices/builders/api/current.txt
index ed3d684..3ff195a 100644
--- a/slices/builders/api/current.txt
+++ b/slices/builders/api/current.txt
@@ -19,8 +19,10 @@
     ctor public GridBuilder.CellBuilder(androidx.slice.builders.GridBuilder, android.net.Uri);
     method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon);
     method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, boolean);
-    method public androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int);
-    method public androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int);
+    method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int, boolean);
+    method public androidx.slice.builders.GridBuilder.CellBuilder addImage(androidx.core.graphics.drawable.IconCompat, int);
+    method public androidx.slice.builders.GridBuilder.CellBuilder addImage(androidx.core.graphics.drawable.IconCompat, int, boolean);
     method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon);
     method public deprecated androidx.slice.builders.GridBuilder.CellBuilder addLargeImage(android.graphics.drawable.Icon, boolean);
     method public androidx.slice.builders.GridBuilder.CellBuilder addText(java.lang.CharSequence);
@@ -45,8 +47,8 @@
   public static final class GridRowBuilder.CellBuilder extends androidx.slice.builders.TemplateSliceBuilder {
     ctor public GridRowBuilder.CellBuilder(androidx.slice.builders.GridRowBuilder);
     ctor public GridRowBuilder.CellBuilder(androidx.slice.builders.GridRowBuilder, android.net.Uri);
-    method public androidx.slice.builders.GridRowBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int);
-    method public androidx.slice.builders.GridRowBuilder.CellBuilder addImage(android.graphics.drawable.Icon, int, boolean);
+    method public androidx.slice.builders.GridRowBuilder.CellBuilder addImage(androidx.core.graphics.drawable.IconCompat, int);
+    method public androidx.slice.builders.GridRowBuilder.CellBuilder addImage(androidx.core.graphics.drawable.IconCompat, int, boolean);
     method public androidx.slice.builders.GridRowBuilder.CellBuilder addText(java.lang.CharSequence);
     method public androidx.slice.builders.GridRowBuilder.CellBuilder addText(java.lang.CharSequence, boolean);
     method public androidx.slice.builders.GridRowBuilder.CellBuilder addTitleText(java.lang.CharSequence);
@@ -56,7 +58,8 @@
   }
 
   public class ListBuilder extends androidx.slice.builders.TemplateSliceBuilder {
-    ctor public ListBuilder(android.content.Context, android.net.Uri);
+    ctor public deprecated ListBuilder(android.content.Context, android.net.Uri);
+    ctor public ListBuilder(android.content.Context, android.net.Uri, long);
     method public androidx.slice.builders.ListBuilder addAction(androidx.slice.builders.SliceAction);
     method public deprecated androidx.slice.builders.ListBuilder addGrid(androidx.slice.builders.GridBuilder);
     method public deprecated androidx.slice.builders.ListBuilder addGrid(java.util.function.Consumer<androidx.slice.builders.GridBuilder>);
@@ -71,12 +74,15 @@
     method public androidx.slice.builders.ListBuilder addSeeMoreAction(android.app.PendingIntent);
     method public androidx.slice.builders.ListBuilder addSeeMoreRow(androidx.slice.builders.ListBuilder.RowBuilder);
     method public androidx.slice.builders.ListBuilder addSeeMoreRow(java.util.function.Consumer<androidx.slice.builders.ListBuilder.RowBuilder>);
+    method public androidx.slice.builders.ListBuilder setColor(int);
     method public androidx.slice.builders.ListBuilder setHeader(androidx.slice.builders.ListBuilder.HeaderBuilder);
     method public androidx.slice.builders.ListBuilder setHeader(java.util.function.Consumer<androidx.slice.builders.ListBuilder.HeaderBuilder>);
     method public androidx.slice.builders.ListBuilder setKeywords(java.util.List<java.lang.String>);
     field public static final int ICON_IMAGE = 0; // 0x0
+    field public static final long INFINITY = -1L; // 0xffffffffffffffffL
     field public static final int LARGE_IMAGE = 2; // 0x2
     field public static final int SMALL_IMAGE = 1; // 0x1
+    field public static final int UNKNOWN_IMAGE = 3; // 0x3
   }
 
   public static class ListBuilder.HeaderBuilder extends androidx.slice.builders.TemplateSliceBuilder {
@@ -96,7 +102,8 @@
     method public androidx.slice.builders.ListBuilder.InputRangeBuilder setAction(android.app.PendingIntent);
     method public androidx.slice.builders.ListBuilder.InputRangeBuilder setContentDescription(java.lang.CharSequence);
     method public androidx.slice.builders.ListBuilder.InputRangeBuilder setMax(int);
-    method public androidx.slice.builders.ListBuilder.InputRangeBuilder setThumb(android.graphics.drawable.Icon);
+    method public deprecated androidx.slice.builders.ListBuilder.InputRangeBuilder setThumb(android.graphics.drawable.Icon);
+    method public androidx.slice.builders.ListBuilder.InputRangeBuilder setThumb(androidx.core.graphics.drawable.IconCompat);
     method public androidx.slice.builders.ListBuilder.InputRangeBuilder setTitle(java.lang.CharSequence);
     method public androidx.slice.builders.ListBuilder.InputRangeBuilder setValue(int);
   }
@@ -116,8 +123,12 @@
     method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(long);
     method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon);
     method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, boolean);
-    method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, int);
-    method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, int);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.core.graphics.drawable.IconCompat);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.core.graphics.drawable.IconCompat, boolean);
+    method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.core.graphics.drawable.IconCompat, int);
+    method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.core.graphics.drawable.IconCompat, int, boolean);
     method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.slice.builders.SliceAction);
     method public androidx.slice.builders.ListBuilder.RowBuilder addEndItem(androidx.slice.builders.SliceAction, boolean);
     method public androidx.slice.builders.ListBuilder.RowBuilder setContentDescription(java.lang.CharSequence);
@@ -129,23 +140,32 @@
     method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(long);
     method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon);
     method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, boolean);
-    method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, int);
-    method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, int);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(android.graphics.drawable.Icon, int, boolean);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.core.graphics.drawable.IconCompat);
+    method public deprecated androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.core.graphics.drawable.IconCompat, boolean);
+    method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.core.graphics.drawable.IconCompat, int);
+    method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.core.graphics.drawable.IconCompat, int, boolean);
     method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.slice.builders.SliceAction);
     method public androidx.slice.builders.ListBuilder.RowBuilder setTitleItem(androidx.slice.builders.SliceAction, boolean);
   }
 
-  public class SliceAction {
-    ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence);
-    ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, int, java.lang.CharSequence);
-    ctor public SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence, boolean);
+  public class SliceAction implements androidx.slice.core.SliceAction {
+    ctor public deprecated SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence);
+    ctor public deprecated SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, int, java.lang.CharSequence);
+    ctor public deprecated SliceAction(android.app.PendingIntent, android.graphics.drawable.Icon, java.lang.CharSequence, boolean);
+    ctor public SliceAction(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat, java.lang.CharSequence);
+    ctor public SliceAction(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat, int, java.lang.CharSequence);
+    ctor public SliceAction(android.app.PendingIntent, androidx.core.graphics.drawable.IconCompat, java.lang.CharSequence, boolean);
     ctor public SliceAction(android.app.PendingIntent, java.lang.CharSequence, boolean);
     method public android.app.PendingIntent getAction();
     method public java.lang.CharSequence getContentDescription();
-    method public android.graphics.drawable.Icon getIcon();
+    method public androidx.core.graphics.drawable.IconCompat getIcon();
+    method public int getImageMode();
     method public int getPriority();
     method public java.lang.CharSequence getTitle();
     method public boolean isChecked();
+    method public boolean isDefaultToggle();
     method public boolean isToggle();
     method public androidx.slice.builders.SliceAction setChecked(boolean);
     method public androidx.slice.builders.SliceAction setContentDescription(java.lang.CharSequence);
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 96c24f0..1bf4c29 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -25,6 +25,7 @@
 dependencies {
     implementation(project(":slices-core"))
     implementation project(":annotation")
+    implementation project(path: ':core')
 }
 
 supportLibrary {
diff --git a/slices/builders/src/main/java/androidx/slice/builders/GridBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/GridBuilder.java
index 87e7ddb..bd6dbf4 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/GridBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/GridBuilder.java
@@ -27,6 +27,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.builders.impl.TemplateBuilderImpl;
 
 import java.util.function.Consumer;
@@ -333,14 +334,7 @@
         }
 
         /**
-         * Adds an image to the cell. There can be at most one image, the first one added
-         * will be used, others will be ignored.
-         * <p>
-         * Use this method to specify content that will appear in the template once it's been
-         * loaded.
-         * </p>
-         * @param isLoading indicates whether the app is doing work to load the added content in the
-         *                  background or not.
+         * @deprecated TO BE REMOVED
          */
         @NonNull
         @Deprecated
@@ -349,6 +343,26 @@
         }
 
         /**
+         * @deprecated TO BE REMOVED
+         */
+        @NonNull
+        @Deprecated
+        public CellBuilder addImage(@NonNull Icon image, @ListBuilder.ImageMode int imageMode) {
+            return addImage(image, imageMode, false /* isLoading */);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED
+         */
+        @NonNull
+        @Deprecated
+        public CellBuilder addImage(@Nullable Icon image, @ListBuilder.ImageMode int imageMode,
+                boolean isLoading) {
+            mImpl.addImage(IconCompat.createFromIcon(image), imageMode, isLoading);
+            return this;
+        }
+
+        /**
          * Adds an image to the cell. There can be at most one image, the first one added will be
          * used, others will be ignored.
          *
@@ -360,7 +374,8 @@
          * @see ListBuilder#LARGE_IMAGE
          */
         @NonNull
-        public CellBuilder addImage(@NonNull Icon image, @ListBuilder.ImageMode int imageMode) {
+        public CellBuilder addImage(@NonNull IconCompat image,
+                @ListBuilder.ImageMode int imageMode) {
             return addImage(image, imageMode, false /* isLoading */);
         }
 
@@ -381,7 +396,8 @@
          * @see ListBuilder#LARGE_IMAGE
          */
         @NonNull
-        public CellBuilder addImage(@Nullable Icon image, @ListBuilder.ImageMode int imageMode,
+        public CellBuilder addImage(@Nullable IconCompat image,
+                @ListBuilder.ImageMode int imageMode,
                 boolean isLoading) {
             mImpl.addImage(image, imageMode, isLoading);
             return this;
diff --git a/slices/builders/src/main/java/androidx/slice/builders/GridRowBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
index e8b8836..6213a4f 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/GridRowBuilder.java
@@ -19,7 +19,6 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
 
@@ -27,6 +26,7 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.builders.impl.TemplateBuilderImpl;
 
 import java.util.function.Consumer;
@@ -277,7 +277,8 @@
          * @see ListBuilder#LARGE_IMAGE
          */
         @NonNull
-        public CellBuilder addImage(@NonNull Icon image, @ListBuilder.ImageMode int imageMode) {
+        public CellBuilder addImage(@NonNull IconCompat image,
+                @ListBuilder.ImageMode int imageMode) {
             return addImage(image, imageMode, false /* isLoading */);
         }
 
@@ -298,8 +299,8 @@
          * @see ListBuilder#LARGE_IMAGE
          */
         @NonNull
-        public CellBuilder addImage(@Nullable Icon image, @ListBuilder.ImageMode int imageMode,
-                boolean isLoading) {
+        public CellBuilder addImage(@Nullable IconCompat image,
+                @ListBuilder.ImageMode int imageMode, boolean isLoading) {
             mImpl.addImage(image, imageMode, isLoading);
             return this;
         }
diff --git a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
index bec2af9..29d43ac 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/ListBuilder.java
@@ -31,10 +31,12 @@
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.SliceSpecs;
 import androidx.slice.builders.impl.ListBuilderBasicImpl;
 import androidx.slice.builders.impl.ListBuilderV1Impl;
 import androidx.slice.builders.impl.TemplateBuilderImpl;
+import androidx.slice.core.SliceHints;
 
 import java.util.List;
 import java.util.function.Consumer;
@@ -68,31 +70,58 @@
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     @IntDef({
-            LARGE_IMAGE, SMALL_IMAGE, ICON_IMAGE
+            LARGE_IMAGE, SMALL_IMAGE, ICON_IMAGE, UNKNOWN_IMAGE
     })
     public @interface ImageMode{}
 
     /**
      * Indicates that an image should be presented as an icon and it can be tinted.
      */
-    public static final int ICON_IMAGE = 0;
+    public static final int ICON_IMAGE = SliceHints.ICON_IMAGE;
     /**
      * Indicates that an image should be presented in a smaller size and it shouldn't be tinted.
      */
-    public static final int SMALL_IMAGE = 1;
+    public static final int SMALL_IMAGE = SliceHints.SMALL_IMAGE;
     /**
      * Indicates that an image presented in a larger size and it shouldn't be tinted.
      */
-    public static final int LARGE_IMAGE = 2;
+    public static final int LARGE_IMAGE = SliceHints.LARGE_IMAGE;
+    /**
+     * Indicates that an image mode is unknown.
+     */
+    public static final int UNKNOWN_IMAGE = SliceHints.UNKNOWN_IMAGE;
+
+    /**
+     * Constant representing infinity.
+     */
+    public static final long INFINITY = SliceHints.INFINITY;
 
     /**
      * Create a builder which will construct a slice that will display rows of content.
      * @param uri Uri to tag for this slice.
+     *
+     * @deprecated TO BE REMOVED; use {@link #ListBuilder(Context, Uri, long)}.
      */
+    @Deprecated
     public ListBuilder(@NonNull Context context, @NonNull Uri uri) {
         super(context, uri);
     }
 
+    /**
+     * Create a builder which will construct a slice that will display rows of content.
+     * <p>
+     * A slice requires an associated time-to-live, i.e. how long the data contained in the slice
+     * can remain fresh. If your slice has content that is not time sensitive, set a TTL of
+     * {@link #INFINITY}.
+     *
+     * @param uri Uri to tag for this slice.
+     * @param ttl the length in milliseconds that the content in this slice can live for.
+     */
+    public ListBuilder(@NonNull Context context, @NonNull Uri uri, long ttl) {
+        super(context, uri);
+        mImpl.setTtl(ttl);
+    }
+
     @Override
     void setImpl(TemplateBuilderImpl impl) {
         mImpl = (androidx.slice.builders.impl.ListBuilder) impl;
@@ -206,10 +235,17 @@
     }
 
     /**
-     * Sets the color to tint items displayed by this template (e.g. icons).
-     * @hide
+     * Sets the color to use on tintable items within the list builder.
+     * Things that might be tinted are:
+     * <ul>
+     *     <li>Any {@link SliceAction}s within your slice.
+     *     </li>
+     *     <li>UI controls such as {@link android.widget.Switch}s or {@link android.widget.SeekBar}s
+     *     </li>
+     *     <li>Tinting the {@link androidx.slice.widget.SliceView#MODE_SHORTCUT} representation
+     *     </li>
+     * </ul>
      */
-    @RestrictTo(LIBRARY_GROUP)
     @NonNull
     public ListBuilder setColor(@ColorInt int color) {
         mImpl.setColor(color);
@@ -455,10 +491,18 @@
         }
 
         /**
-         * Set the {@link Icon} to be displayed as the thumb on the input range.
+         * @deprecated TO BE REMOVED
          */
         @NonNull
         public InputRangeBuilder setThumb(@NonNull Icon thumb) {
+            return setThumb(IconCompat.createFromIcon(thumb));
+        }
+
+        /**
+         * Set the {@link Icon} to be displayed as the thumb on the input range.
+         */
+        @NonNull
+        public InputRangeBuilder setThumb(@NonNull IconCompat thumb) {
             mImpl.setThumb(thumb);
             return this;
         }
@@ -550,6 +594,45 @@
         }
 
         /**
+         * @deprecated TO BE REMOVED.
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder setTitleItem(@NonNull Icon icon) {
+            return setTitleItem(icon, ICON_IMAGE);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED.
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder setTitleItem(@Nullable Icon icon, boolean isLoading) {
+            return setTitleItem(icon, ICON_IMAGE, isLoading);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED.
+         */
+        @Deprecated
+        public RowBuilder setTitleItem(@NonNull Icon icon, @ImageMode int imageMode) {
+            mImpl.setTitleItem(IconCompat.createFromIcon(icon), imageMode, false /* isLoading */);
+            return this;
+        }
+
+        /**
+         * @deprecated TO BE REMOVED.
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder setTitleItem(@Nullable Icon icon, @ImageMode int imageMode,
+                boolean isLoading) {
+            mImpl.setTitleItem(IconCompat.createFromIcon(icon), imageMode,
+                    isLoading /* isLoading */);
+            return this;
+        }
+
+        /**
          * Sets the title item to be the provided icon. There can only be one title item, this
          * will replace any other title items that may have been set.
          *
@@ -557,7 +640,7 @@
          */
         @Deprecated
         @NonNull
-        public RowBuilder setTitleItem(@NonNull Icon icon) {
+        public RowBuilder setTitleItem(@NonNull IconCompat icon) {
             return setTitleItem(icon, ICON_IMAGE);
         }
 
@@ -575,7 +658,7 @@
          */
         @Deprecated
         @NonNull
-        public RowBuilder setTitleItem(@Nullable Icon icon, boolean isLoading) {
+        public RowBuilder setTitleItem(@Nullable IconCompat icon, boolean isLoading) {
             return setTitleItem(icon, ICON_IMAGE, isLoading);
         }
 
@@ -590,7 +673,7 @@
          * @see #SMALL_IMAGE
          * @see #LARGE_IMAGE
          */
-        public RowBuilder setTitleItem(@NonNull Icon icon, @ImageMode int imageMode) {
+        public RowBuilder setTitleItem(@NonNull IconCompat icon, @ImageMode int imageMode) {
             mImpl.setTitleItem(icon, imageMode, false /* isLoading */);
             return this;
         }
@@ -612,7 +695,7 @@
          * @see #LARGE_IMAGE
          */
         @NonNull
-        public RowBuilder setTitleItem(@Nullable Icon icon, @ImageMode int imageMode,
+        public RowBuilder setTitleItem(@Nullable IconCompat icon, @ImageMode int imageMode,
                 boolean isLoading) {
             mImpl.setTitleItem(icon, imageMode, isLoading /* isLoading */);
             return this;
@@ -715,6 +798,50 @@
         }
 
         /**
+         * @deprecated TO BE REMOVED
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder addEndItem(@NonNull Icon icon) {
+            return addEndItem(icon, ICON_IMAGE, false /* isLoading */);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder addEndItem(@NonNull Icon icon, boolean isLoading) {
+            return addEndItem(icon, ICON_IMAGE, isLoading);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder addEndItem(@NonNull Icon icon, @ImageMode int imageMode) {
+            return addEndItem(icon, imageMode, false /* isLoading */);
+        }
+
+        /**
+         * @deprecated TO BE REMOVED
+         */
+        @Deprecated
+        @NonNull
+        public RowBuilder addEndItem(@Nullable Icon icon, @ImageMode int imageMode,
+                boolean isLoading) {
+            if (mHasEndActionOrToggle) {
+                throw new IllegalArgumentException("Trying to add an icon to end items when an"
+                        + "action has already been added. End items cannot have a mixture of "
+                        + "actions and icons.");
+            }
+            mImpl.addEndItem(IconCompat.createFromIcon(icon), imageMode, isLoading);
+            mHasEndImage = true;
+            return this;
+        }
+
+        /**
          * Adds an icon to be displayed at the end of the row. A mixture of icons and actions
          * is not permitted. If an action has already been added this will throw
          * {@link IllegalArgumentException}.
@@ -723,7 +850,7 @@
          */
         @Deprecated
         @NonNull
-        public RowBuilder addEndItem(@NonNull Icon icon) {
+        public RowBuilder addEndItem(@NonNull IconCompat icon) {
             return addEndItem(icon, ICON_IMAGE, false /* isLoading */);
         }
 
@@ -742,7 +869,7 @@
          */
         @Deprecated
         @NonNull
-        public RowBuilder addEndItem(@NonNull Icon icon, boolean isLoading) {
+        public RowBuilder addEndItem(@NonNull IconCompat icon, boolean isLoading) {
             return addEndItem(icon, ICON_IMAGE, isLoading);
         }
 
@@ -757,7 +884,7 @@
          * @see #LARGE_IMAGE
          */
         @NonNull
-        public RowBuilder addEndItem(@NonNull Icon icon, @ImageMode int imageMode) {
+        public RowBuilder addEndItem(@NonNull IconCompat icon, @ImageMode int imageMode) {
             return addEndItem(icon, imageMode, false /* isLoading */);
         }
 
@@ -777,7 +904,7 @@
          * @see #LARGE_IMAGE
          */
         @NonNull
-        public RowBuilder addEndItem(@Nullable Icon icon, @ImageMode int imageMode,
+        public RowBuilder addEndItem(@Nullable IconCompat icon, @ImageMode int imageMode,
                 boolean isLoading) {
             if (mHasEndActionOrToggle) {
                 throw new IllegalArgumentException("Trying to add an icon to end items when an"
@@ -823,7 +950,7 @@
                         + "in a row, set a custom icon for each toggle.");
             }
             mImpl.addEndItem(action, isLoading);
-            mHasDefaultToggle = action.isDefaultToggle();
+            mHasDefaultToggle = action.getImpl().isDefaultToggle();
             mHasEndActionOrToggle = true;
             return this;
         }
diff --git a/slices/builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
index 32134d3..c3f1f92 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/MessagingSliceBuilder.java
@@ -23,12 +23,11 @@
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Build;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
-
-import java.util.function.Consumer;
-
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.SliceSpecs;
 import androidx.slice.builders.impl.MessagingBasicImpl;
 import androidx.slice.builders.impl.MessagingBuilder;
@@ -36,6 +35,8 @@
 import androidx.slice.builders.impl.MessagingV1Impl;
 import androidx.slice.builders.impl.TemplateBuilderImpl;
 
+import java.util.function.Consumer;
+
 /**
  * Builder to construct slice content in a messaging format.
  * @hide
@@ -120,6 +121,14 @@
         }
 
         /**
+         * Add the icon used to display contact in the messaging experience
+         */
+        public MessageBuilder addSource(IconCompat source) {
+            mImpl.addSource(source.toIcon());
+            return this;
+        }
+
+        /**
          * Add the text to be used for this message.
          */
         public MessageBuilder addText(CharSequence text) {
diff --git a/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java b/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
index 00adbd4..e4e28f5 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/SliceAction.java
@@ -16,14 +16,6 @@
 
 package androidx.slice.builders;
 
-import static android.app.slice.Slice.HINT_NO_TINT;
-import static android.app.slice.Slice.HINT_SELECTED;
-import static android.app.slice.Slice.HINT_SHORTCUT;
-import static android.app.slice.Slice.HINT_TITLE;
-import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
-import static android.app.slice.Slice.SUBTYPE_PRIORITY;
-import static android.app.slice.Slice.SUBTYPE_TOGGLE;
-
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
 
@@ -34,21 +26,43 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
+import androidx.slice.core.SliceActionImpl;
 
 /**
  * Class representing an action, supports tappable icons, custom toggle icons, and default toggles.
  */
-public class SliceAction {
+public class SliceAction implements androidx.slice.core.SliceAction {
 
-    private PendingIntent mAction;
-    private Icon mIcon;
-    private int mImageMode;
-    private CharSequence mTitle;
-    private CharSequence mContentDescription;
-    private boolean mIsToggle;
-    private boolean mIsChecked;
-    private int mPriority = -1;
+    private SliceActionImpl mSliceAction;
+
+    /**
+     * @deprecated TO BE REMOVED
+     */
+    @Deprecated
+    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+            @NonNull CharSequence actionTitle) {
+        this(action, actionIcon, ICON_IMAGE, actionTitle);
+    }
+
+    /**
+     * @deprecated TO BE REMOVED
+     */
+    @Deprecated
+    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+            @ListBuilder.ImageMode int imageMode, @NonNull CharSequence actionTitle) {
+        this(action, IconCompat.createFromIcon(actionIcon), imageMode, actionTitle);
+    }
+
+    /**
+     * @deprecated TO BE REMOVED
+     */
+    @Deprecated
+    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+            @NonNull CharSequence actionTitle, boolean isChecked) {
+        this(action, IconCompat.createFromIcon(actionIcon), actionTitle, isChecked);
+    }
 
     /**
      * Construct a SliceAction representing a tappable icon.
@@ -58,7 +72,7 @@
      * @param actionTitle the title for this action, also used for content description if one hasn't
      *                    been set via {@link #setContentDescription(CharSequence)}.
      */
-    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+    public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
             @NonNull CharSequence actionTitle) {
         this(action, actionIcon, ICON_IMAGE, actionTitle);
     }
@@ -80,12 +94,9 @@
      * @see ListBuilder#SMALL_IMAGE
      * @see ListBuilder#LARGE_IMAGE
      */
-    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+    public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
             @ListBuilder.ImageMode int imageMode, @NonNull CharSequence actionTitle) {
-        mAction = action;
-        mIcon = actionIcon;
-        mTitle = actionTitle;
-        mImageMode = imageMode;
+        mSliceAction = new SliceActionImpl(action, actionIcon, imageMode, actionTitle);
     }
 
     /**
@@ -98,11 +109,9 @@
      *                    been set via {@link #setContentDescription(CharSequence)}.
      * @param isChecked the state of the toggle.
      */
-    public SliceAction(@NonNull PendingIntent action, @NonNull Icon actionIcon,
+    public SliceAction(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
             @NonNull CharSequence actionTitle, boolean isChecked) {
-        this(action, actionIcon, ICON_IMAGE, actionTitle);
-        mIsChecked = isChecked;
-        mIsToggle = true;
+        mSliceAction = new SliceActionImpl(action, actionIcon, actionTitle, isChecked);
     }
 
     /**
@@ -115,19 +124,16 @@
      */
     public SliceAction(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
             boolean isChecked) {
-        mAction = action;
-        mTitle = actionTitle;
-        mIsToggle = true;
-        mIsChecked = isChecked;
-
+        mSliceAction = new SliceActionImpl(action, actionTitle, isChecked);
     }
 
     /**
      * @param description the content description for this action.
      */
-    @Nullable
+    @NonNull
+    @Override
     public SliceAction setContentDescription(@NonNull CharSequence description) {
-        mContentDescription = description;
+        mSliceAction.setContentDescription(description);
         return this;
     }
 
@@ -135,16 +141,20 @@
      * @param isChecked whether the state of this action is checked or not; only used for toggle
      *                  actions.
      */
+    @NonNull
+    @Override
     public SliceAction setChecked(boolean isChecked) {
-        mIsChecked = isChecked;
+        mSliceAction.setChecked(isChecked);
         return this;
     }
 
     /**
      * Sets the priority of this action, with the lowest priority having the highest ranking.
      */
+    @NonNull
+    @Override
     public SliceAction setPriority(@IntRange(from = 0) int priority) {
-        mPriority = priority;
+        mSliceAction.setPriority(priority);
         return this;
     }
 
@@ -152,8 +162,9 @@
      * @return the {@link PendingIntent} associated with this action.
      */
     @NonNull
+    @Override
     public PendingIntent getAction() {
-        return mAction;
+        return mSliceAction.getAction();
     }
 
     /**
@@ -161,53 +172,67 @@
      * represented is a default toggle.
      */
     @Nullable
-    public Icon getIcon() {
-        return mIcon;
+    @Override
+    public IconCompat getIcon() {
+        return mSliceAction.getIcon();
     }
 
     /**
      * @return the title for this action.
      */
     @NonNull
+    @Override
     public CharSequence getTitle() {
-        return mTitle;
+        return mSliceAction.getTitle();
     }
 
     /**
      * @return the content description to use for this action.
      */
     @Nullable
+    @Override
     public CharSequence getContentDescription() {
-        return mContentDescription;
+        return mSliceAction.getContentDescription();
     }
 
     /**
      * @return the priority associated with this action, -1 if unset.
      */
+    @Override
     public int getPriority() {
-        return mPriority;
+        return mSliceAction.getPriority();
     }
 
     /**
      * @return whether this action represents a toggle (i.e. has a checked and unchecked state).
      */
+    @Override
     public boolean isToggle() {
-        return mIsToggle;
+        return mSliceAction.isToggle();
     }
 
     /**
      * @return whether the state of this action is checked or not; only used for toggle actions.
      */
+    @Override
     public boolean isChecked() {
-        return mIsChecked;
+        return mSliceAction.isChecked();
     }
 
     /**
-     * @hide
+     * @return the image mode to use for this action.
      */
-    @RestrictTo(LIBRARY)
+    @Override
+    public @ListBuilder.ImageMode int getImageMode() {
+        return mSliceAction.getImageMode();
+    }
+
+    /**
+     * @return whether this action is a toggle using the standard switch control.
+     */
+    @Override
     public boolean isDefaultToggle() {
-        return mIsToggle && mIcon == null;
+        return mSliceAction.isDefaultToggle();
     }
 
     /**
@@ -219,28 +244,15 @@
     @RestrictTo(LIBRARY)
     @NonNull
     public Slice buildSlice(@NonNull Slice.Builder builder) {
-        Slice.Builder sb = new Slice.Builder(builder);
-        if (mIcon != null) {
-            @Slice.SliceHint String[] hints = mImageMode == ICON_IMAGE
-                    ? new String[] {}
-                    : new String[] {HINT_NO_TINT};
-            sb.addIcon(mIcon, null, hints);
-        }
-        if (mTitle != null) {
-            sb.addText(mTitle, null, HINT_TITLE);
-        }
-        if (mContentDescription != null) {
-            sb.addText(mContentDescription, SUBTYPE_CONTENT_DESCRIPTION);
-        }
-        if (mIsToggle && mIsChecked) {
-            sb.addHints(HINT_SELECTED);
-        }
-        if (mPriority != -1) {
-            sb.addInt(mPriority, SUBTYPE_PRIORITY);
-        }
-        String subtype = mIsToggle ? SUBTYPE_TOGGLE : null;
-        builder.addHints(HINT_SHORTCUT);
-        builder.addAction(mAction, sb.build(), subtype);
-        return builder.build();
+        return mSliceAction.buildSlice(builder);
+    }
+
+    /**
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @NonNull
+    public SliceActionImpl getImpl() {
+        return mSliceAction;
     }
 }
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilder.java
index b5eefff..9b59945 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilder.java
@@ -19,12 +19,12 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.builders.SliceAction;
 
 /**
@@ -123,12 +123,11 @@
         /**
          * Adds an image to the cell. There can be at most one image, the first one added
          * will be used, others will be ignored.
-         *
-         * @param image the image to display in the cell.
+         *  @param image the image to display in the cell.
          * @param imageMode the mode that image should be displayed in.
          */
         @NonNull
-        void addImage(@NonNull Icon image, int imageMode);
+        void addImage(@NonNull IconCompat image, int imageMode);
 
         /**
          * Adds an image to the cell. There can be at most one image, the first one added
@@ -139,7 +138,7 @@
          * until updated.l.
          */
         @NonNull
-        void addImage(@NonNull Icon image, int imageMode, boolean isLoading);
+        void addImage(@NonNull IconCompat image, int imageMode, boolean isLoading);
 
         /**
          * Sets the action to be invoked if the user taps on this cell in the row.
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderBasicImpl.java
index dcd8791..e1a0752 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderBasicImpl.java
@@ -19,12 +19,12 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.builders.SliceAction;
 
@@ -141,14 +141,14 @@
          */
         @NonNull
         @Override
-        public void addImage(@NonNull Icon image, int imageMode) {
+        public void addImage(@NonNull IconCompat image, int imageMode) {
         }
 
         /**
          */
         @NonNull
         @Override
-        public void addImage(@Nullable Icon image, int imageMode, boolean isLoading) {
+        public void addImage(@Nullable IconCompat image, int imageMode, boolean isLoading) {
         }
 
         /**
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
index 0c077ba..29158b4 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/GridRowBuilderListV1Impl.java
@@ -31,12 +31,12 @@
 import static androidx.slice.builders.ListBuilder.LARGE_IMAGE;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.builders.SliceAction;
 
@@ -193,7 +193,7 @@
          */
         @NonNull
         @Override
-        public void addImage(@NonNull Icon image, int imageMode) {
+        public void addImage(@NonNull IconCompat image, int imageMode) {
             addImage(image, imageMode, false /* isLoading */);
         }
 
@@ -201,7 +201,7 @@
          */
         @NonNull
         @Override
-        public void addImage(@Nullable Icon image, int imageMode, boolean isLoading) {
+        public void addImage(@Nullable IconCompat image, int imageMode, boolean isLoading) {
             ArrayList<String> hints = new ArrayList<>();
             if (imageMode != ICON_IMAGE) {
                 hints.add(HINT_NO_TINT);
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
index da4fb69..0ebd32b 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilder.java
@@ -19,12 +19,12 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.builders.SliceAction;
 
 import java.util.List;
@@ -100,6 +100,14 @@
     void setKeywords(List<String> keywords);
 
     /**
+     * Sets the time-to-live for this slice, i.e. how long the data contained in the slice
+     * can remain fresh.
+     *
+     * @param ttl the length in milliseconds that this content can live for.
+     */
+    void setTtl(long ttl);
+
+    /**
      * Create a builder that implements {@link RowBuilder}.
      */
     TemplateBuilderImpl createRowBuilder();
@@ -163,9 +171,9 @@
         void setAction(@NonNull PendingIntent action);
 
         /**
-         * Set the {@link Icon} to be displayed as the thumb on the input range.
+         * Set the {@link IconCompat} to be displayed as the thumb on the input range.
          */
-        void setThumb(@NonNull Icon thumb);
+        void setThumb(@NonNull IconCompat thumb);
     }
 
     /**
@@ -184,11 +192,10 @@
         /**
          * Sets the title item to be the provided icon. There can only be one title item, this
          * will replace any other title items that may have been set.
-         *
-         * @param icon the image to display.
+         *  @param icon the image to display.
          * @param imageMode the mode that image should be displayed in.
          */
-        void setTitleItem(Icon icon, int imageMode);
+        void setTitleItem(IconCompat icon, int imageMode);
 
         /**
          * Sets the title item to be the provided icon. There can only be one title item, this
@@ -197,12 +204,11 @@
          * When set to true, the parameter {@code isLoading} indicates that the app is doing work
          * to load this content in the background, in this case the template displays a placeholder
          * until updated.
-         *
-         * @param icon the image to display.
+         *  @param icon the image to display.
          * @param imageMode the mode that image should be displayed in.
          * @param isLoading whether this content is being loaded in the background.
          */
-        void setTitleItem(Icon icon, int imageMode, boolean isLoading);
+        void setTitleItem(IconCompat icon, int imageMode, boolean isLoading);
 
         /**
          * Sets the title item to be a tappable icon. There can only be one title item, this will
@@ -260,11 +266,10 @@
 
         /**
          * Adds an icon to be displayed at the end of the row.
-         *
-         * @param icon the image to display.
+         *  @param icon the image to display.
          * @param imageMode the mode that image should be displayed in.
          */
-        void addEndItem(Icon icon, int imageMode);
+        void addEndItem(IconCompat icon, int imageMode);
 
         /**
          * Adds an icon to be displayed at the end of the row.
@@ -272,12 +277,11 @@
          * When set to true, the parameter {@code isLoading} indicates that the app is doing work
          * to load this content in the background, in this case the template displays a placeholder
          * until updated.
-         *
-         * @param icon the image to display.
+         *  @param icon the image to display.
          * @param imageMode the mode that image should be displayed in.
          * @param isLoading whether this content is being loaded in the background.
          */
-        void addEndItem(Icon icon, int imageMode, boolean isLoading);
+        void addEndItem(IconCompat icon, int imageMode, boolean isLoading);
 
         /**
          * Adds a tappable icon to be displayed at the end of the row.
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
index e9a659d..204defa 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/ListBuilderBasicImpl.java
@@ -20,12 +20,12 @@
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceSpec;
 import androidx.slice.builders.SliceAction;
@@ -114,6 +114,12 @@
     /**
      */
     @Override
+    public void setTtl(long ttl) {
+    }
+
+    /**
+     */
+    @Override
     public TemplateBuilderImpl createRowBuilder() {
         return new RowBuilderImpl(this);
     }
@@ -207,14 +213,14 @@
         /**
          */
         @Override
-        public void setTitleItem(Icon icon, int imageMode) {
+        public void setTitleItem(IconCompat icon, int imageMode) {
 
         }
 
         /**
          */
         @Override
-        public void setTitleItem(Icon icon, int imageMode, boolean isLoading) {
+        public void setTitleItem(IconCompat icon, int imageMode, boolean isLoading) {
 
         }
 
@@ -274,14 +280,14 @@
         /**
          */
         @Override
-        public void addEndItem(Icon icon, int imageMode) {
+        public void addEndItem(IconCompat icon, int imageMode) {
 
         }
 
         /**
          */
         @Override
-        public void addEndItem(Icon icon, int imageMode, boolean isLoading) {
+        public void addEndItem(IconCompat icon, int imageMode, boolean isLoading) {
 
         }
 
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 6671024..e85fbb1 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
@@ -31,19 +31,23 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
+import static androidx.slice.builders.ListBuilder.INFINITY;
 import static androidx.slice.builders.ListBuilder.LARGE_IMAGE;
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
 import static androidx.slice.core.SliceHints.SUBTYPE_MAX;
+import static androidx.slice.core.SliceHints.SUBTYPE_MILLIS;
 import static androidx.slice.core.SliceHints.SUBTYPE_RANGE;
 import static androidx.slice.core.SliceHints.SUBTYPE_VALUE;
 
 import android.app.PendingIntent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
 import androidx.slice.SliceSpec;
@@ -71,6 +75,7 @@
      */
     @Override
     public void apply(Slice.Builder builder) {
+        builder.addTimestamp(System.currentTimeMillis(), SUBTYPE_MILLIS, HINT_LAST_UPDATED);
         if (mSliceHeader != null) {
             builder.addSubSlice(mSliceHeader);
         }
@@ -202,7 +207,7 @@
     public static class InputRangeBuilderImpl
             extends RangeBuilderImpl implements InputRangeBuilder {
         private PendingIntent mAction;
-        private Icon mThumb;
+        private IconCompat mThumb;
 
         public InputRangeBuilderImpl(Slice.Builder sb) {
             super(sb);
@@ -214,7 +219,7 @@
         }
 
         @Override
-        public void setThumb(@NonNull Icon thumb) {
+        public void setThumb(@NonNull IconCompat thumb) {
             mThumb = thumb;
         }
 
@@ -254,6 +259,14 @@
     /**
      */
     @Override
+    public void setTtl(long ttl) {
+        long expiry = ttl == INFINITY ? INFINITY : System.currentTimeMillis() + ttl;
+        getBuilder().addTimestamp(expiry, SUBTYPE_MILLIS, HINT_TTL);
+    }
+
+    /**
+     */
+    @Override
     public TemplateBuilderImpl createRowBuilder() {
         return new RowBuilderImpl(this);
     }
@@ -338,7 +351,7 @@
          */
         @NonNull
         @Override
-        public void setTitleItem(Icon icon, int imageMode) {
+        public void setTitleItem(IconCompat icon, int imageMode) {
             setTitleItem(icon, imageMode, false /* isLoading */);
         }
 
@@ -346,7 +359,7 @@
          */
         @NonNull
         @Override
-        public void setTitleItem(Icon icon, int imageMode, boolean isLoading) {
+        public void setTitleItem(IconCompat icon, int imageMode, boolean isLoading) {
             ArrayList<String> hints = new ArrayList<>();
             if (imageMode != ICON_IMAGE) {
                 hints.add(HINT_NO_TINT);
@@ -441,7 +454,7 @@
          */
         @NonNull
         @Override
-        public void addEndItem(Icon icon, int imageMode) {
+        public void addEndItem(IconCompat icon, int imageMode) {
             addEndItem(icon, imageMode, false /* isLoading */);
         }
 
@@ -449,7 +462,7 @@
          */
         @NonNull
         @Override
-        public void addEndItem(Icon icon, int imageMode, boolean isLoading) {
+        public void addEndItem(IconCompat icon, int imageMode, boolean isLoading) {
             ArrayList<String> hints = new ArrayList<>();
             if (imageMode != ICON_IMAGE) {
                 hints.add(HINT_NO_TINT);
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
index 8d3bf59..c999594 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBasicImpl.java
@@ -19,8 +19,9 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.graphics.drawable.Icon;
-import androidx.annotation.RestrictTo;
 
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceSpec;
 
@@ -44,7 +45,7 @@
     public void apply(Slice.Builder builder) {
         if (mLastMessage != null) {
             if (mLastMessage.mIcon != null) {
-                builder.addIcon(mLastMessage.mIcon, null);
+                builder.addIcon(IconCompat.createFromIcon(mLastMessage.mIcon), null);
             }
             if (mLastMessage.mText != null) {
                 builder.addText(mLastMessage.mText, null);
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
index c1b8a85..dd66616 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingBuilder.java
@@ -19,6 +19,7 @@
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 
 import android.graphics.drawable.Icon;
+
 import androidx.annotation.RestrictTo;
 
 /**
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
index b44f25b..e47871a 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingListV1Impl.java
@@ -17,12 +17,13 @@
 package androidx.slice.builders.impl;
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
-
+import static androidx.slice.builders.ListBuilder.INFINITY;
 import static androidx.slice.builders.ListBuilder.SMALL_IMAGE;
 
 import android.graphics.drawable.Icon;
-import androidx.annotation.RestrictTo;
 
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceSpec;
 
@@ -39,6 +40,7 @@
     public MessagingListV1Impl(Slice.Builder b, SliceSpec spec) {
         super(b, spec);
         mListBuilder = new ListBuilderV1Impl(b, spec);
+        mListBuilder.setTtl(INFINITY);
     }
 
     /**
@@ -84,7 +86,7 @@
          */
         @Override
         public void addSource(Icon source) {
-            mListBuilder.setTitleItem(source, SMALL_IMAGE);
+            mListBuilder.setTitleItem(IconCompat.createFromIcon(source), SMALL_IMAGE);
         }
 
         /**
diff --git a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
index 36ecd0c..e601491 100644
--- a/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
+++ b/slices/builders/src/main/java/androidx/slice/builders/impl/MessagingV1Impl.java
@@ -19,8 +19,9 @@
 import static android.app.slice.Slice.SUBTYPE_MESSAGE;
 
 import android.graphics.drawable.Icon;
-import androidx.annotation.RestrictTo;
 
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceSpec;
 
@@ -71,7 +72,8 @@
          */
         @Override
         public void addSource(Icon source) {
-            getBuilder().addIcon(source, android.app.slice.Slice.SUBTYPE_SOURCE);
+            getBuilder().addIcon(IconCompat.createFromIcon(source),
+                    android.app.slice.Slice.SUBTYPE_SOURCE);
         }
 
         /**
diff --git a/slices/core/api/current.txt b/slices/core/api/current.txt
index c1668ab..acc5cbd 100644
--- a/slices/core/api/current.txt
+++ b/slices/core/api/current.txt
@@ -16,7 +16,7 @@
     method public android.app.PendingIntent getAction();
     method public java.lang.String getFormat();
     method public java.util.List<java.lang.String> getHints();
-    method public android.graphics.drawable.Icon getIcon();
+    method public androidx.core.graphics.drawable.IconCompat getIcon();
     method public int getInt();
     method public androidx.slice.Slice getSlice();
     method public java.lang.String getSubType();
@@ -36,3 +36,22 @@
 
 }
 
+package androidx.slice.core {
+
+  public abstract interface SliceAction {
+    method public abstract android.app.PendingIntent getAction();
+    method public abstract java.lang.CharSequence getContentDescription();
+    method public abstract androidx.core.graphics.drawable.IconCompat getIcon();
+    method public abstract int getImageMode();
+    method public abstract int getPriority();
+    method public abstract java.lang.CharSequence getTitle();
+    method public abstract boolean isChecked();
+    method public abstract boolean isDefaultToggle();
+    method public abstract boolean isToggle();
+    method public abstract androidx.slice.core.SliceAction setChecked(boolean);
+    method public abstract androidx.slice.core.SliceAction setContentDescription(java.lang.CharSequence);
+    method public abstract androidx.slice.core.SliceAction setPriority(int);
+  }
+
+}
+
diff --git a/slices/core/src/androidTest/java/androidx/slice/SliceTest.java b/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
index 563473a..041c8fe 100644
--- a/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
+++ b/slices/core/src/androidTest/java/androidx/slice/SliceTest.java
@@ -38,12 +38,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.core.test.R;
 
 import org.junit.Test;
@@ -120,8 +120,14 @@
 
         SliceItem item = s.getItems().get(0);
         assertEquals(FORMAT_IMAGE, item.getFormat());
-        assertEquals(Icon.createWithResource(mContext, R.drawable.size_48x48).toString(),
-                item.getIcon().toString());
+        assertEquivalent(IconCompat.createWithResource(mContext, R.drawable.size_48x48),
+                item.getIcon());
+    }
+
+    private void assertEquivalent(IconCompat first, IconCompat second) {
+        assertEquals(first.getType(), second.getType());
+        assertEquals(first.getResId(), second.getResId());
+        assertEquals(first.getResPackage(), second.getResPackage());
     }
 
     @Test
diff --git a/slices/core/src/androidTest/java/androidx/slice/SliceTestProvider.java b/slices/core/src/androidTest/java/androidx/slice/SliceTestProvider.java
index ab68646..d6f1628 100644
--- a/slices/core/src/androidTest/java/androidx/slice/SliceTestProvider.java
+++ b/slices/core/src/androidTest/java/androidx/slice/SliceTestProvider.java
@@ -23,9 +23,9 @@
 
 import android.app.PendingIntent;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice.Builder;
 import androidx.slice.core.test.R;
 
@@ -49,7 +49,7 @@
                 return new Slice.Builder(sliceUri).addText("Expected text", "text").build();
             case "/icon":
                 return new Slice.Builder(sliceUri).addIcon(
-                        Icon.createWithResource(getContext(), R.drawable.size_48x48),
+                        IconCompat.createWithResource(getContext(), R.drawable.size_48x48),
                         "icon").build();
             case "/action":
                 Builder builder = new Builder(sliceUri);
@@ -65,7 +65,7 @@
                 return new Slice.Builder(sliceUri)
                         .addHints(HINT_LIST)
                         .addText("Text", null, HINT_TITLE)
-                        .addIcon(Icon.createWithResource(getContext(), R.drawable.size_48x48),
+                        .addIcon(IconCompat.createWithResource(getContext(), R.drawable.size_48x48),
                                 null, HINT_NO_TINT, HINT_LARGE)
                         .build();
         }
diff --git a/slices/core/src/main/java/androidx/slice/Slice.java b/slices/core/src/main/java/androidx/slice/Slice.java
index d27d246..84c7df7 100644
--- a/slices/core/src/main/java/androidx/slice/Slice.java
+++ b/slices/core/src/main/java/androidx/slice/Slice.java
@@ -38,12 +38,13 @@
 
 import static androidx.slice.SliceConvert.unwrap;
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
 
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.app.slice.SliceManager;
 import android.content.Context;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcelable;
@@ -54,6 +55,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.annotation.StringDef;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.core.os.BuildCompat;
 import androidx.slice.compat.SliceProviderCompat;
 
@@ -84,7 +86,7 @@
     @RestrictTo(Scope.LIBRARY)
     @StringDef({HINT_TITLE, HINT_LIST, HINT_LIST_ITEM, HINT_LARGE, HINT_ACTIONS, HINT_SELECTED,
             HINT_HORIZONTAL, HINT_NO_TINT, HINT_PARTIAL, HINT_SUMMARY, HINT_SEE_MORE,
-            HINT_SHORTCUT, HINT_KEY_WORDS})
+            HINT_SHORTCUT, HINT_KEY_WORDS, HINT_TTL, HINT_LAST_UPDATED})
     public @interface SliceHint{ }
 
     private final SliceItem[] mItems;
@@ -292,7 +294,7 @@
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addIcon(Icon icon, @Nullable String subType,
+        public Builder addIcon(IconCompat icon, @Nullable String subType,
                 @SliceHint String... hints) {
             mItems.add(new SliceItem(icon, FORMAT_IMAGE, subType, hints));
             return this;
@@ -303,7 +305,7 @@
          * @param subType Optional template-specific type information
          * @see {@link SliceItem#getSubType()}
          */
-        public Builder addIcon(Icon icon, @Nullable String subType,
+        public Builder addIcon(IconCompat icon, @Nullable String subType,
                 @SliceHint List<String> hints) {
             return addIcon(icon, subType, hints.toArray(new String[hints.size()]));
         }
diff --git a/slices/core/src/main/java/androidx/slice/SliceConvert.java b/slices/core/src/main/java/androidx/slice/SliceConvert.java
index 58531fa..1d89b8e 100644
--- a/slices/core/src/main/java/androidx/slice/SliceConvert.java
+++ b/slices/core/src/main/java/androidx/slice/SliceConvert.java
@@ -27,6 +27,7 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.collection.ArraySet;
+import androidx.core.graphics.drawable.IconCompat;
 
 import java.util.List;
 import java.util.Set;
@@ -51,7 +52,7 @@
                     builder.addSubSlice(unwrap(item.getSlice()), item.getSubType());
                     break;
                 case FORMAT_IMAGE:
-                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    builder.addIcon(item.getIcon().toIcon(), item.getSubType(), item.getHints());
                     break;
                 case FORMAT_REMOTE_INPUT:
                     builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
@@ -102,7 +103,8 @@
                     builder.addSubSlice(wrap(item.getSlice()), item.getSubType());
                     break;
                 case FORMAT_IMAGE:
-                    builder.addIcon(item.getIcon(), item.getSubType(), item.getHints());
+                    builder.addIcon(IconCompat.createFromIcon(item.getIcon()),
+                            item.getSubType(), item.getHints());
                     break;
                 case FORMAT_REMOTE_INPUT:
                     builder.addRemoteInput(item.getRemoteInput(), item.getSubType(),
diff --git a/slices/core/src/main/java/androidx/slice/SliceItem.java b/slices/core/src/main/java/androidx/slice/SliceItem.java
index e059124..067772e 100644
--- a/slices/core/src/main/java/androidx/slice/SliceItem.java
+++ b/slices/core/src/main/java/androidx/slice/SliceItem.java
@@ -26,16 +26,17 @@
 
 import android.app.PendingIntent;
 import android.app.RemoteInput;
-import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Pair;
+
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.annotation.RestrictTo.Scope;
 import androidx.annotation.StringDef;
-import android.text.TextUtils;
-import android.util.Pair;
+import androidx.core.graphics.drawable.IconCompat;
 
 import java.util.Arrays;
 import java.util.List;
@@ -178,9 +179,8 @@
     /**
      * @return The icon held by this {@link android.app.slice.SliceItem#FORMAT_IMAGE} SliceItem
      */
-    @RequiresApi(23)
-    public Icon getIcon() {
-        return (Icon) mObj;
+    public IconCompat getIcon() {
+        return (IconCompat) mObj;
     }
 
     /**
@@ -292,6 +292,8 @@
     private void writeObj(Bundle dest, Object obj, String type) {
         switch (type) {
             case FORMAT_IMAGE:
+                dest.putBundle(OBJ, ((IconCompat) obj).toBundle());
+                break;
             case FORMAT_REMOTE_INPUT:
                 dest.putParcelable(OBJ, (Parcelable) obj);
                 break;
@@ -317,6 +319,7 @@
     private static Object readObj(String type, Bundle in) {
         switch (type) {
             case FORMAT_IMAGE:
+                return IconCompat.createFromBundle(in.getBundle(OBJ));
             case FORMAT_REMOTE_INPUT:
                 return in.getParcelable(OBJ);
             case FORMAT_SLICE:
diff --git a/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java b/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
index 07bce69..1e2c8f1 100644
--- a/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
+++ b/slices/core/src/main/java/androidx/slice/compat/SliceProviderCompat.java
@@ -31,6 +31,7 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Handler;
@@ -339,7 +340,11 @@
             // Manager will kill this process shortly anyway.
             return null;
         } finally {
-            provider.close();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+                provider.close();
+            } else {
+                provider.release();
+            }
         }
     }
 
diff --git a/slices/core/src/main/java/androidx/slice/core/SliceAction.java b/slices/core/src/main/java/androidx/slice/core/SliceAction.java
new file mode 100644
index 0000000..c73c6b9
--- /dev/null
+++ b/slices/core/src/main/java/androidx/slice/core/SliceAction.java
@@ -0,0 +1,97 @@
+/*
+ * 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.slice.core;
+
+import android.app.PendingIntent;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.IconCompat;
+
+/**
+ * Interface for a slice action, supports tappable icons, custom toggle icons, and default toggles.
+ */
+public interface SliceAction {
+
+    /**
+     * @param description the content description for this action.
+     */
+    @Nullable
+    SliceAction setContentDescription(@NonNull CharSequence description);
+
+    /**
+     * @param isChecked whether the state of this action is checked or not; only used for toggle
+     *                  actions.
+     */
+    SliceAction setChecked(boolean isChecked);
+
+    /**
+     * Sets the priority of this action, with the lowest priority having the highest ranking.
+     */
+    SliceAction setPriority(@IntRange(from = 0) int priority);
+
+    /**
+     * @return the {@link PendingIntent} associated with this action.
+     */
+    @NonNull
+    PendingIntent getAction();
+
+    /**
+     * @return the {@link IconCompat} to display for this action. This can be null when the action
+     * represented is a default toggle.
+     */
+    @Nullable
+    IconCompat getIcon();
+
+    /**
+     * @return the title for this action.
+     */
+    @NonNull
+    CharSequence getTitle();
+
+    /**
+     * @return the content description to use for this action.
+     */
+    @Nullable
+    CharSequence getContentDescription();
+
+    /**
+     * @return the priority associated with this action, -1 if unset.
+     */
+    int getPriority();
+
+    /**
+     * @return whether this action represents a toggle (i.e. has a checked and unchecked state).
+     */
+    boolean isToggle();
+
+    /**
+     * @return whether the state of this action is checked or not; only used for toggle actions.
+     */
+    boolean isChecked();
+
+    /**
+     * @return the image mode to use for this action.
+     */
+    @SliceHints.ImageMode int getImageMode();
+
+    /**
+     * @return whether this action is a toggle using the standard switch control.
+     */
+    boolean isDefaultToggle();
+}
diff --git a/slices/core/src/main/java/androidx/slice/core/SliceActionImpl.java b/slices/core/src/main/java/androidx/slice/core/SliceActionImpl.java
new file mode 100644
index 0000000..b5ca913
--- /dev/null
+++ b/slices/core/src/main/java/androidx/slice/core/SliceActionImpl.java
@@ -0,0 +1,332 @@
+/*
+ * 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.slice.core;
+
+import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_SELECTED;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.Slice.HINT_TITLE;
+import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
+import static android.app.slice.Slice.SUBTYPE_PRIORITY;
+import static android.app.slice.Slice.SUBTYPE_TOGGLE;
+import static android.app.slice.SliceItem.FORMAT_ACTION;
+import static android.app.slice.SliceItem.FORMAT_IMAGE;
+import static android.app.slice.SliceItem.FORMAT_INT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
+import static androidx.slice.core.SliceHints.ICON_IMAGE;
+import static androidx.slice.core.SliceHints.LARGE_IMAGE;
+import static androidx.slice.core.SliceHints.SMALL_IMAGE;
+import static androidx.slice.core.SliceHints.UNKNOWN_IMAGE;
+
+import android.app.PendingIntent;
+import android.graphics.drawable.Icon;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+
+/**
+ * Class representing an action, supports tappable icons, custom toggle icons, and default toggles.
+ * @hide
+ */
+@RestrictTo(LIBRARY_GROUP)
+public class SliceActionImpl implements SliceAction {
+
+    private PendingIntent mAction;
+    private IconCompat mIcon;
+    private int mImageMode = UNKNOWN_IMAGE;
+    private CharSequence mTitle;
+    private CharSequence mContentDescription;
+    private boolean mIsToggle;
+    private boolean mIsChecked;
+    private int mPriority = -1;
+    private SliceItem mSliceItem;
+
+    /**
+     * Construct a SliceAction representing a tappable icon.
+     *
+     * @param action the pending intent to invoke for this action.
+     * @param actionIcon the icon to display for this action.
+     * @param actionTitle the title for this action, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     */
+    public SliceActionImpl(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
+            @NonNull CharSequence actionTitle) {
+        this(action, actionIcon, ICON_IMAGE, actionTitle);
+    }
+
+    /**
+     * Construct a SliceAction representing a tappable icon. Use this method to specify the
+     * format of the image, {@link SliceHints#ICON_IMAGE} will be presented as a tintable icon.
+     * Note that there is no difference between {@link SliceHints#SMALL_IMAGE} and
+     * {@link SliceHints#LARGE_IMAGE} for actions; these will just be represented as an
+     * non-tintable image.
+     *
+     * @param action the pending intent to invoke for this action.
+     * @param actionIcon the icon to display for this action.
+     * @param imageMode the mode this icon should be displayed in.
+     * @param actionTitle the title for this action, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     *
+     * @see SliceHints#ICON_IMAGE
+     * @see SliceHints#SMALL_IMAGE
+     * @see SliceHints#LARGE_IMAGE
+     */
+    public SliceActionImpl(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
+            @SliceHints.ImageMode int imageMode, @NonNull CharSequence actionTitle) {
+        mAction = action;
+        mIcon = actionIcon;
+        mTitle = actionTitle;
+        mImageMode = imageMode;
+    }
+
+    /**
+     * Construct a SliceAction representing a custom toggle icon.
+     *
+     * @param action the pending intent to invoke for this toggle.
+     * @param actionIcon the icon to display for this toggle, should have a checked and unchecked
+     *                   state.
+     * @param actionTitle the title for this toggle, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     * @param isChecked the state of the toggle.
+     */
+    public SliceActionImpl(@NonNull PendingIntent action, @NonNull IconCompat actionIcon,
+            @NonNull CharSequence actionTitle, boolean isChecked) {
+        this(action, actionIcon, ICON_IMAGE, actionTitle);
+        mIsChecked = isChecked;
+        mIsToggle = true;
+    }
+
+    /**
+     * Construct a SliceAction representing a default toggle.
+     *
+     * @param action the pending intent to invoke for this toggle.
+     * @param actionTitle the title for this toggle, also used for content description if one hasn't
+     *                    been set via {@link #setContentDescription(CharSequence)}.
+     * @param isChecked the state of the toggle.
+     */
+    public SliceActionImpl(@NonNull PendingIntent action, @NonNull CharSequence actionTitle,
+            boolean isChecked) {
+        mAction = action;
+        mTitle = actionTitle;
+        mIsToggle = true;
+        mIsChecked = isChecked;
+    }
+
+    /**
+     * Constructs a SliceAction based off of a {@link SliceItem}. Expects a specific format
+     * for the item.
+     *
+     * @param slice the slice item to construct the action out of.
+     *
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    public SliceActionImpl(SliceItem slice) {
+        mSliceItem = slice;
+        if (slice.hasHint(HINT_SHORTCUT) && FORMAT_SLICE.equals(slice.getFormat())) {
+            SliceItem actionItem = SliceQuery.find(slice, FORMAT_ACTION);
+            if (actionItem == null) {
+                // Can't have action slice without action
+                return;
+            }
+            mAction = actionItem.getAction();
+            SliceItem iconItem = SliceQuery.find(actionItem.getSlice(), FORMAT_IMAGE);
+            if (iconItem != null) {
+                mIcon = iconItem.getIcon();
+                mImageMode = iconItem.hasHint(HINT_NO_TINT)
+                        ? iconItem.hasHint(HINT_LARGE) ? LARGE_IMAGE : SMALL_IMAGE
+                        : ICON_IMAGE;
+            }
+            SliceItem titleItem = SliceQuery.find(actionItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
+                    null /* nonHints */);
+            if (titleItem != null) {
+                mTitle = titleItem.getText();
+            }
+            SliceItem cdItem = SliceQuery.findSubtype(actionItem.getSlice(), FORMAT_TEXT,
+                    SUBTYPE_CONTENT_DESCRIPTION);
+            if (cdItem != null) {
+                mContentDescription = cdItem.getText();
+            }
+            mIsToggle = SUBTYPE_TOGGLE.equals(actionItem.getSubType());
+            if (mIsToggle) {
+                mIsChecked = actionItem.hasHint(HINT_SELECTED);
+            }
+            SliceItem priority = SliceQuery.findSubtype(actionItem.getSlice(), FORMAT_INT,
+                    SUBTYPE_PRIORITY);
+            mPriority = priority != null ? priority.getInt() : -1;
+        } else if (FORMAT_ACTION.equals(slice.getFormat())) {
+            mAction = slice.getAction();
+        }
+    }
+
+    /**
+     * @param description the content description for this action.
+     */
+    @Nullable
+    @Override
+    public SliceActionImpl setContentDescription(@NonNull CharSequence description) {
+        mContentDescription = description;
+        return this;
+    }
+
+    /**
+     * @param isChecked whether the state of this action is checked or not; only used for toggle
+     *                  actions.
+     */
+    @Override
+    public SliceActionImpl setChecked(boolean isChecked) {
+        mIsChecked = isChecked;
+        return this;
+    }
+
+    /**
+     * Sets the priority of this action, with the lowest priority having the highest ranking.
+     */
+    @Override
+    public SliceActionImpl setPriority(@IntRange(from = 0) int priority) {
+        mPriority = priority;
+        return this;
+    }
+
+    /**
+     * @return the {@link PendingIntent} associated with this action.
+     */
+    @NonNull
+    @Override
+    public PendingIntent getAction() {
+        return mAction;
+    }
+
+    /**
+     * @return the {@link Icon} to display for this action. This can be null when the action
+     * represented is a default toggle.
+     */
+    @Nullable
+    @Override
+    public IconCompat getIcon() {
+        return mIcon;
+    }
+
+    /**
+     * @return the title for this action.
+     */
+    @NonNull
+    @Override
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * @return the content description to use for this action.
+     */
+    @Nullable
+    @Override
+    public CharSequence getContentDescription() {
+        return mContentDescription;
+    }
+
+    /**
+     * @return the priority associated with this action, -1 if unset.
+     */
+    @Override
+    public int getPriority() {
+        return mPriority;
+    }
+
+    /**
+     * @return whether this action represents a toggle (i.e. has a checked and unchecked state).
+     */
+    @Override
+    public boolean isToggle() {
+        return mIsToggle;
+    }
+
+    /**
+     * @return whether the state of this action is checked or not; only used for toggle actions.
+     */
+    @Override
+    public boolean isChecked() {
+        return mIsChecked;
+    }
+
+    /**
+     * @return the image mode to use for this action.
+     */
+    @Override
+    public @SliceHints.ImageMode int getImageMode() {
+        return mImageMode;
+    }
+
+    /**
+     * @return whether this action is a toggle using the standard switch control.
+     */
+    @Override
+    public boolean isDefaultToggle() {
+        return mIsToggle && mIcon == null;
+    }
+
+    /**
+     * @return the SliceItem used to construct this action, this is only populated if the action was
+     * constructed with {@link #SliceActionImpl(SliceItem)}.
+     */
+    @Nullable
+    public SliceItem getSliceItem() {
+        return mSliceItem;
+    }
+
+    /**
+     * @param builder this should be a new builder that has any additional hints the action might
+     *                need.
+     * @return the slice representation of this action.
+     */
+    @NonNull
+    public Slice buildSlice(@NonNull Slice.Builder builder) {
+        Slice.Builder sb = new Slice.Builder(builder);
+        if (mIcon != null) {
+            @Slice.SliceHint String[] hints = mImageMode == ICON_IMAGE
+                    ? new String[] {}
+                    : new String[] {HINT_NO_TINT};
+            sb.addIcon(mIcon, null, hints);
+        }
+        if (mTitle != null) {
+            sb.addText(mTitle, null, HINT_TITLE);
+        }
+        if (mContentDescription != null) {
+            sb.addText(mContentDescription, SUBTYPE_CONTENT_DESCRIPTION);
+        }
+        if (mIsToggle && mIsChecked) {
+            sb.addHints(HINT_SELECTED);
+        }
+        if (mPriority != -1) {
+            sb.addInt(mPriority, SUBTYPE_PRIORITY);
+        }
+        String subtype = mIsToggle ? SUBTYPE_TOGGLE : null;
+        builder.addHints(HINT_SHORTCUT);
+        builder.addAction(mAction, sb.build(), subtype);
+        return builder.build();
+    }
+}
diff --git a/slices/core/src/main/java/androidx/slice/core/SliceHints.java b/slices/core/src/main/java/androidx/slice/core/SliceHints.java
index a1ffb42..acbdfc6 100644
--- a/slices/core/src/main/java/androidx/slice/core/SliceHints.java
+++ b/slices/core/src/main/java/androidx/slice/core/SliceHints.java
@@ -18,6 +18,7 @@
 
 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.RestrictTo;
 
 /**
@@ -61,4 +62,46 @@
      */
     public static final String HINT_KEY_WORDS = "key_words";
 
+    /**
+     * Hint indicating an item representing a time-to-live for the content.
+     */
+    public static final String HINT_TTL = "ttl";
+
+    /**
+     * Hint indicating an item representing when the content was created or last updated.
+     */
+    public static final String HINT_LAST_UPDATED = "last_updated";
+
+    /**
+     * Subtype to tag an item as representing a time in milliseconds since midnight,
+     * January 1, 1970 UTC.
+     */
+    public static final String SUBTYPE_MILLIS = "millis";
+
+    @IntDef({
+            LARGE_IMAGE, SMALL_IMAGE, ICON_IMAGE, UNKNOWN_IMAGE
+    })
+    public @interface ImageMode{}
+
+    /**
+     * Indicates that an image should be presented as an icon and it can be tinted.
+     */
+    public static final int ICON_IMAGE = 0;
+    /**
+     * Indicates that an image should be presented in a smaller size and it shouldn't be tinted.
+     */
+    public static final int SMALL_IMAGE = 1;
+    /**
+     * Indicates that an image presented in a larger size and it shouldn't be tinted.
+     */
+    public static final int LARGE_IMAGE = 2;
+    /**
+     * Indicates that an image mode is unknown.
+     */
+    public static final int UNKNOWN_IMAGE = 3;
+
+    /**
+     * Constant representing infinity.
+     */
+    public static final long INFINITY = -1;
 }
diff --git a/slices/view/api/current.txt b/slices/view/api/current.txt
index c176d3e..0936bbf 100644
--- a/slices/view/api/current.txt
+++ b/slices/view/api/current.txt
@@ -16,15 +16,27 @@
     method public abstract void onSliceUpdated(androidx.slice.Slice);
   }
 
+  public class SliceMetadata {
+    method public static androidx.slice.SliceMetadata from(android.content.Context, androidx.slice.Slice);
+    method public long getExpiry();
+    method public long getLastUpdatedTime();
+    method public int getLoadingState();
+    method public java.util.List<androidx.slice.SliceItem> getSliceActions();
+    method public java.util.List<java.lang.String> getSliceKeywords();
+    field public static final int LOADED_ALL = 2; // 0x2
+    field public static final int LOADED_NONE = 0; // 0x0
+    field public static final int LOADED_PARTIAL = 1; // 0x1
+  }
+
   public class SliceUtils {
-    method public static int getLoadingState(androidx.slice.Slice);
-    method public static java.util.List<androidx.slice.SliceItem> getSliceActions(androidx.slice.Slice);
-    method public static java.util.List<java.lang.String> getSliceKeywords(androidx.slice.Slice);
+    method public static deprecated int getLoadingState(androidx.slice.Slice);
+    method public static deprecated java.util.List<androidx.slice.SliceItem> getSliceActions(androidx.slice.Slice);
+    method public static deprecated java.util.List<java.lang.String> getSliceKeywords(androidx.slice.Slice);
     method public static androidx.slice.Slice parseSlice(java.io.InputStream, java.lang.String) throws java.io.IOException;
     method public static void serializeSlice(androidx.slice.Slice, android.content.Context, java.io.OutputStream, java.lang.String, androidx.slice.SliceUtils.SerializeOptions) throws java.io.IOException;
-    field public static final int LOADING_ALL = 0; // 0x0
-    field public static final int LOADING_COMPLETE = 2; // 0x2
-    field public static final int LOADING_PARTIAL = 1; // 0x1
+    field public static final deprecated int LOADING_ALL = 0; // 0x0
+    field public static final deprecated int LOADING_COMPLETE = 2; // 0x2
+    field public static final deprecated int LOADING_PARTIAL = 1; // 0x1
   }
 
   public static class SliceUtils.SerializeOptions {
diff --git a/slices/view/src/androidTest/java/androidx/slice/SliceMetadataTest.java b/slices/view/src/androidTest/java/androidx/slice/SliceMetadataTest.java
new file mode 100644
index 0000000..c416b30
--- /dev/null
+++ b/slices/view/src/androidTest/java/androidx/slice/SliceMetadataTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.slice;
+
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_TITLE;
+
+import static androidx.slice.SliceMetadata.LOADED_ALL;
+import static androidx.slice.SliceMetadata.LOADED_NONE;
+import static androidx.slice.SliceMetadata.LOADED_PARTIAL;
+import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertNull;
+
+import android.content.Context;
+import android.net.Uri;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import androidx.slice.core.SliceHints;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link SliceMetadata}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SliceMetadataTest {
+
+    private final Context mContext = InstrumentationRegistry.getContext();
+
+    @Test
+    public void testKeywords() {
+        Uri uri = Uri.parse("content://pkg/slice");
+        Slice keywordSlice = new Slice.Builder(uri)
+                .addHints(HINT_KEY_WORDS)
+                .addText("keyword1", null)
+                .addText("keyword2", null)
+                .addText("keyword3", null).build();
+        Slice slice = new Slice.Builder(uri)
+                .addText("Some text", null, HINT_TITLE)
+                .addText("Some other text", null)
+                .addSubSlice(keywordSlice)
+                .build();
+
+        SliceMetadata sliceInfo1 = SliceMetadata.from(mContext, slice);
+        List<String> sliceKeywords = sliceInfo1.getSliceKeywords();
+        String[] expectedList = new String[] {"keyword1", "keyword2", "keyword3"};
+        assertArrayEquals(expectedList, sliceKeywords.toArray());
+
+        // Make sure it doesn't find keywords that aren't there
+        Slice slice2 = new Slice.Builder(uri)
+                .addText("Some text", null, HINT_TITLE)
+                .addText("Some other text", null).build();
+
+        SliceMetadata sliceInfo2 = SliceMetadata.from(mContext, slice2);
+        List<String> slice2Keywords = sliceInfo2.getSliceKeywords();
+        assertNull(slice2Keywords);
+
+        // Make sure empty list if specified to have no keywords
+        Slice noKeywordSlice = new Slice.Builder(uri).addHints(HINT_KEY_WORDS).build();
+        Slice slice3 = new Slice.Builder(uri)
+                .addText("Some text", null, HINT_TITLE)
+                .addSubSlice(noKeywordSlice)
+                .build();
+
+        SliceMetadata sliceMetadata3 = SliceMetadata.from(mContext, slice3);
+        List<String> slice3Keywords = sliceMetadata3.getSliceKeywords();
+        assertTrue(slice3Keywords.isEmpty());
+    }
+
+    @Test
+    public void testGetLoadingState() {
+        Uri uri = Uri.parse("content://pkg/slice");
+        Slice s1 = new Slice.Builder(uri).build();
+        SliceMetadata sliceInfo1 = SliceMetadata.from(mContext, s1);
+        int actualState1 = sliceInfo1.getLoadingState();
+        assertEquals(LOADED_NONE, actualState1);
+
+        Slice s2 = new Slice.Builder(uri).addText(null, null, HINT_PARTIAL).build();
+        SliceMetadata sliceInfo2 = SliceMetadata.from(mContext, s2);
+        int actualState2 = sliceInfo2.getLoadingState();
+        assertEquals(LOADED_PARTIAL, actualState2);
+
+        Slice s3 = new Slice.Builder(uri).addText("Text", null).build();
+        SliceMetadata sliceInfo3 = SliceMetadata.from(mContext, s3);
+        int actualState3 = sliceInfo3.getLoadingState();
+        assertEquals(LOADED_ALL, actualState3);
+    }
+
+    @Test
+    public void testGetExpiry() {
+        Uri uri = Uri.parse("content://pkg/slice");
+        long timestamp = System.currentTimeMillis();
+        long ttl = TimeUnit.DAYS.toMillis(1);
+        Slice ttlSlice = new Slice.Builder(uri)
+                .addText("Some text", null)
+                .addTimestamp(timestamp, null)
+                .addTimestamp(timestamp, null, SliceHints.HINT_LAST_UPDATED)
+                .addTimestamp(ttl, null, SliceHints.HINT_TTL)
+                .build();
+
+        SliceMetadata si1 = SliceMetadata.from(mContext, ttlSlice);
+        long retrievedTtl = si1.getExpiry();
+        assertEquals(ttl, retrievedTtl);
+
+        Slice noTtlSlice = new Slice.Builder(uri)
+                .addText("Some text", null)
+                .addTimestamp(timestamp, null).build();
+        SliceMetadata si2 = SliceMetadata.from(mContext, noTtlSlice);
+        long retrievedTtl2 = si2.getExpiry();
+        assertEquals(0, retrievedTtl2);
+    }
+
+    @Test
+    public void testGetLastUpdated() {
+        Uri uri = Uri.parse("content://pkg/slice");
+        long timestamp = System.currentTimeMillis();
+        long ttl = TimeUnit.DAYS.toMillis(1);
+        Slice ttlSlice = new Slice.Builder(uri)
+                .addText("Some text", null)
+                .addTimestamp(timestamp - 20, null)
+                .addTimestamp(timestamp, null, SliceHints.HINT_LAST_UPDATED)
+                .addTimestamp(ttl, null, SliceHints.HINT_TTL)
+                .build();
+
+        SliceMetadata si1 = SliceMetadata.from(mContext, ttlSlice);
+        long retrievedLastUpdated = si1.getLastUpdatedTime();
+        assertEquals(timestamp, retrievedLastUpdated);
+
+        Slice noTtlSlice = new Slice.Builder(uri)
+                .addText("Some text", null)
+                .addTimestamp(timestamp, null).build();
+
+        SliceMetadata si2 = SliceMetadata.from(mContext, noTtlSlice);
+        long retrievedLastUpdated2 = si2.getLastUpdatedTime();
+        assertEquals(0, retrievedLastUpdated2);
+    }
+}
diff --git a/slices/view/src/androidTest/java/androidx/slice/SliceXmlTest.java b/slices/view/src/androidTest/java/androidx/slice/SliceXmlTest.java
index ec99872..298d498 100644
--- a/slices/view/src/androidTest/java/androidx/slice/SliceXmlTest.java
+++ b/slices/view/src/androidTest/java/androidx/slice/SliceXmlTest.java
@@ -17,8 +17,6 @@
 package androidx.slice;
 
 
-import static android.app.slice.Slice.HINT_PARTIAL;
-import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
@@ -26,30 +24,22 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertTrue;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertNull;
-
-import static androidx.slice.SliceUtils.LOADING_ALL;
-import static androidx.slice.SliceUtils.LOADING_COMPLETE;
-import static androidx.slice.SliceUtils.LOADING_PARTIAL;
-import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
-
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import androidx.core.graphics.drawable.IconCompat;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
 @SmallTest
@@ -126,7 +116,7 @@
                 .addSubSlice(new Slice.Builder(Uri.parse("content://pkg/slice/sub"))
                         .addTimestamp(System.currentTimeMillis(), null, "Hint")
                         .build())
-                .addIcon(Icon.createWithBitmap(b), null)
+                .addIcon(IconCompat.createWithBitmap(b), null)
                 .addText("Some text", null)
                 .addAction(null, new Slice.Builder(Uri.parse("content://pkg/slice/sub"))
                         .addText("Action text", null)
@@ -148,57 +138,6 @@
         assertEquivalent(before, after);
     }
 
-    @Test
-    public void testKeywords() {
-        Uri uri = Uri.parse("content://pkg/slice");
-        Slice keywordSlice = new Slice.Builder(uri)
-                .addHints(HINT_KEY_WORDS)
-                .addText("keyword1", null)
-                .addText("keyword2", null)
-                .addText("keyword3", null).build();
-        Slice slice = new Slice.Builder(uri)
-                .addText("Some text", null, HINT_TITLE)
-                .addText("Some other text", null)
-                .addSubSlice(keywordSlice)
-                .build();
-
-        List<String> sliceKeywords = SliceUtils.getSliceKeywords(slice);
-        String[] expectedList = new String[] {"keyword1", "keyword2", "keyword3"};
-        assertArrayEquals(expectedList, sliceKeywords.toArray());
-
-        // Make sure it doesn't find keywords that aren't there
-        Slice slice2 = new Slice.Builder(uri)
-                .addText("Some text", null, HINT_TITLE)
-                .addText("Some other text", null).build();
-        List<String> slice2Keywords = SliceUtils.getSliceKeywords(slice2);
-        assertNull(slice2Keywords);
-
-        // Make sure empty list if specified to have no keywords
-        Slice noKeywordSlice = new Slice.Builder(uri).addHints(HINT_KEY_WORDS).build();
-        Slice slice3 = new Slice.Builder(uri)
-                .addText("Some text", null, HINT_TITLE)
-                .addSubSlice(noKeywordSlice)
-                .build();
-        List<String> slice3Keywords = SliceUtils.getSliceKeywords(slice3);
-        assertTrue(slice3Keywords.isEmpty());
-    }
-
-    @Test
-    public void testGetLoadingState() {
-        Uri uri = Uri.parse("content://pkg/slice");
-        Slice s1 = new Slice.Builder(uri).build();
-        int actualState1 = SliceUtils.getLoadingState(s1);
-        assertEquals(LOADING_ALL, actualState1);
-
-        Slice s2 = new Slice.Builder(uri).addText(null, null, HINT_PARTIAL).build();
-        int actualState2 = SliceUtils.getLoadingState(s2);
-        assertEquals(LOADING_PARTIAL, actualState2);
-
-        Slice s3 = new Slice.Builder(uri).addText("Text", null).build();
-        int actualState3 = SliceUtils.getLoadingState(s3);
-        assertEquals(LOADING_COMPLETE, actualState3);
-    }
-
     private void assertEquivalent(Slice desired, Slice actual) {
         assertEquals(desired.getUri(), actual.getUri());
         assertEquals(desired.getHints(), actual.getHints());
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 2ea8071..cf524fa 100644
--- a/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
+++ b/slices/view/src/androidTest/java/androidx/slice/render/SliceCreator.java
@@ -19,6 +19,7 @@
 import static android.text.Spanned.SPAN_EXCLUSIVE_EXCLUSIVE;
 
 import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
+import static androidx.slice.builders.ListBuilder.INFINITY;
 import static androidx.slice.builders.ListBuilder.LARGE_IMAGE;
 import static androidx.slice.builders.ListBuilder.SMALL_IMAGE;
 
@@ -26,7 +27,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.provider.Settings;
@@ -34,6 +34,7 @@
 import android.text.format.DateUtils;
 import android.text.style.ForegroundColorSpan;
 
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.builders.GridRowBuilder;
 import androidx.slice.builders.ListBuilder;
@@ -42,6 +43,7 @@
 import androidx.slice.view.test.R;
 
 import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Examples of using slice template builders.
@@ -54,9 +56,9 @@
             "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", "wifi2", "note", "ride", "toggle",
-            "toggle2", "contact", "gallery", "subscription", "subscription2", "weather",
-            "reservation"};
+    public static final String[] URI_PATHS = {"message", "wifi", "wifi2", "note", "ride",
+            "ride-ttl", "toggle", "toggle2", "contact", "gallery", "subscription", "subscription2",
+            "weather", "reservation"};
 
     private final Context mContext;
 
@@ -91,7 +93,9 @@
             case "/note":
                 return createNoteSlice(sliceUri);
             case "/ride":
-                return createRideSlice(sliceUri);
+                return createRideSlice(sliceUri, false /* showUpdated */);
+            case "/ride-ttl":
+                return createRideSlice(sliceUri, true /* showUpdated */);
             case "/toggle":
                 return createCustomToggleSlice(sliceUri);
             case "/toggle2":
@@ -114,33 +118,34 @@
 
     private Slice createWeather(Uri sliceUri) {
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
-                "open weather app"), Icon.createWithResource(getContext(), R.drawable.weather_1),
+                "open weather app"),
+                IconCompat.createWithResource(getContext(), R.drawable.weather_1),
                 "Weather is happening!");
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, -TimeUnit.HOURS.toMillis(8));
         GridRowBuilder gb = new GridRowBuilder(b);
         gb.setPrimaryAction(primaryAction);
         gb.addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
-                                SMALL_IMAGE)
-                        .addText("MON")
-                        .addTitleText("69\u00B0"))
+                .addImage(IconCompat.createWithResource(getContext(), R.drawable.weather_1),
+                        SMALL_IMAGE)
+                .addText("MON")
+                .addTitleText("69\u00B0"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_2),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.weather_2),
                                 SMALL_IMAGE)
                         .addText("TUE")
                         .addTitleText("71\u00B0"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_3),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.weather_3),
                                 SMALL_IMAGE)
                         .addText("WED")
                         .addTitleText("76\u00B0"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_4),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.weather_4),
                                 SMALL_IMAGE)
                         .addText("THU")
                         .addTitleText("72\u00B0"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.weather_1),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.weather_1),
                                 SMALL_IMAGE)
                         .addText("FRI")
                         .addTitleText("68\u00B0"));
@@ -148,41 +153,41 @@
     }
 
     private Slice createGallery(Uri sliceUri) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY);
         GridRowBuilder gb = new GridRowBuilder(b);
         PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "see more of your gallery");
         gb.addSeeMoreAction(pi);
         gb.addCell(new GridRowBuilder.CellBuilder(gb)
-                .addImage(Icon.createWithResource(getContext(), R.drawable.slices_1),
+                .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_1),
                         LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_2),
                                 LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_3),
                                 LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_4),
                                 LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_2),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_2),
                                 LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_3),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_3),
                                 LARGE_IMAGE))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.slices_4),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.slices_4),
                                 LARGE_IMAGE));
         return b.addGridRow(gb).build();
     }
 
     private Slice createSubSlice(Uri sliceUri, boolean customSeeMore) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY);
         GridRowBuilder gb = new GridRowBuilder(b);
         GridRowBuilder.CellBuilder cb = new GridRowBuilder.CellBuilder(gb);
         PendingIntent pi = getBroadcastIntent(ACTION_TOAST, "See cats you follow");
         if (customSeeMore) {
-            cb.addImage(Icon.createWithResource(getContext(), R.drawable.ic_right_caret),
+            cb.addImage(IconCompat.createWithResource(getContext(), R.drawable.ic_right_caret),
                     ICON_IMAGE);
             cb.setContentIntent(pi);
             cb.addText("All cats");
@@ -191,37 +196,37 @@
             gb.addSeeMoreAction(pi);
         }
         gb.addCell(new GridRowBuilder.CellBuilder(gb)
-                    .addImage(Icon.createWithResource(getContext(), R.drawable.cat_1),
-                            SMALL_IMAGE)
-                    .addTitleText("Oreo"))
+                .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_1),
+                        SMALL_IMAGE)
+                .addTitleText("Oreo"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_2),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_2),
                                 SMALL_IMAGE)
                         .addTitleText("Silver"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_3),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_3),
                                 SMALL_IMAGE)
                         .addTitleText("Drake"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_5),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_5),
                                 SMALL_IMAGE)
                         .addTitleText("Olive"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_4),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_4),
                                 SMALL_IMAGE)
                         .addTitleText("Lady Marmalade"))
                 .addCell(new GridRowBuilder.CellBuilder(gb)
-                        .addImage(Icon.createWithResource(getContext(), R.drawable.cat_6),
+                        .addImage(IconCompat.createWithResource(getContext(), R.drawable.cat_6),
                                 SMALL_IMAGE)
                         .addTitleText("Grapefruit"));
         return b.addGridRow(gb).build();
     }
 
     private Slice createContact(Uri sliceUri) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, INFINITY);
         ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(b);
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST,
-                "See contact info"), Icon.createWithResource(getContext(),
+                "See contact info"), IconCompat.createWithResource(getContext(),
                 R.drawable.mady), SMALL_IMAGE, "Mady");
         GridRowBuilder gb = new GridRowBuilder(b);
         return b.setColor(0xff3949ab)
@@ -231,25 +236,29 @@
                         .addEndItem(primaryAction))
                 .addGridRow(gb
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_call),
-                                    ICON_IMAGE)
-                            .addText("Call")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_call),
+                                        ICON_IMAGE)
+                                .addText("Call")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "call")))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_text),
-                                    ICON_IMAGE)
-                            .addText("Text")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_text),
+                                        ICON_IMAGE)
+                                .addText("Text")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "text")))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_video),
-                                    ICON_IMAGE)
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
-                            .addText("Video"))
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_video),
+                                        ICON_IMAGE)
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "video"))
+                                .addText("Video"))
                         .addCell(new GridRowBuilder.CellBuilder(gb)
-                            .addImage(Icon.createWithResource(getContext(), R.drawable.ic_email),
-                                    ICON_IMAGE)
-                            .addText("Email")
-                            .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
+                                .addImage(IconCompat.createWithResource(getContext(),
+                                        R.drawable.ic_email),
+                                        ICON_IMAGE)
+                                .addText("Email")
+                                .setContentIntent(getBroadcastIntent(ACTION_TOAST, "email"))))
                 .build();
     }
 
@@ -260,7 +269,7 @@
                 .add(new MessagingSliceBuilder.MessageBuilder(mb)
                         .addText("yo home \uD83C\uDF55, I emailed you the info")
                         .addTimestamp(System.currentTimeMillis() - 20 * DateUtils.MINUTE_IN_MILLIS)
-                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                        .addSource(IconCompat.createWithResource(getContext(), R.drawable.mady)))
                 .add(new MessagingSliceBuilder.MessageBuilder(mb)
                         .addText("just bought my tickets")
                         .addTimestamp(System.currentTimeMillis() - 10 * DateUtils.MINUTE_IN_MILLIS))
@@ -268,31 +277,31 @@
                         .addText("yay! can't wait for getContext() weekend!\n"
                                 + "\uD83D\uDE00")
                         .addTimestamp(System.currentTimeMillis() - 5 * DateUtils.MINUTE_IN_MILLIS)
-                        .addSource(Icon.createWithResource(getContext(), R.drawable.mady)))
+                        .addSource(IconCompat.createWithResource(getContext(), R.drawable.mady)))
                 .build();
 
     }
 
     private Slice createNoteSlice(Uri sliceUri) {
         // TODO: Remote input.
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY);
         return lb.setColor(0xfff4b400)
                 .addRow(new ListBuilder.RowBuilder(lb)
-                    .setTitle("Create new note")
-                    .setSubtitle("with this note taking app")
-                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"),
-                            Icon.createWithResource(getContext(), R.drawable.ic_create),
-                            "Create note"))
-                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"),
-                            Icon.createWithResource(getContext(), R.drawable.ic_voice),
-                            "Voice note"))
-                    .addEndItem(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"),
-                            Icon.createWithResource(getContext(), R.drawable.ic_camera),
-                            "Photo note")))
+                        .setTitle("Create new note")
+                        .setSubtitle("with this note taking app")
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "create note"),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_create),
+                                "Create note"))
+                        .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "voice note"),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_voice),
+                                "Voice note"))
+                        .addEndItem(new SliceAction(getIntent("android.media.action.IMAGE_CAPTURE"),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_camera),
+                                "Photo note")))
                 .build();
     }
 
-    private Slice createRideSlice(Uri sliceUri) {
+    private Slice createRideSlice(Uri sliceUri, boolean showUpdated) {
         final ForegroundColorSpan colorSpan = new ForegroundColorSpan(0xff0F9D58);
         SpannableString headerSubtitle = new SpannableString("Ride in 4 min");
         headerSubtitle.setSpan(colorSpan, 8, headerSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
@@ -301,8 +310,11 @@
         SpannableString workSubtitle = new SpannableString("44 miles | 1 hour 45 min | $31.41");
         workSubtitle.setSpan(colorSpan, 27, workSubtitle.length(), SPAN_EXCLUSIVE_EXCLUSIVE);
         SliceAction primaryAction = new SliceAction(getBroadcastIntent(ACTION_TOAST, "get ride"),
-                Icon.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+                IconCompat.createWithResource(getContext(), R.drawable.ic_car), "Get Ride");
+        Long ttl = showUpdated
+                ? -TimeUnit.MINUTES.toMillis(2) // negative for testing
+                : INFINITY;
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, ttl);
         return lb.setColor(0xff0F9D58)
                 .setHeader(new ListBuilder.HeaderBuilder(lb)
                         .setTitle("Get ride")
@@ -313,42 +325,43 @@
                         .setTitle("Work")
                         .setSubtitle(workSubtitle)
                         .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "work"),
-                                Icon.createWithResource(getContext(), R.drawable.ic_work),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_work),
                                 "Get ride work")))
                 .addRow(new ListBuilder.RowBuilder(lb)
                         .setTitle("Home")
                         .setSubtitle(homeSubtitle)
                         .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "home"),
-                                Icon.createWithResource(getContext(), R.drawable.ic_home),
+                                IconCompat.createWithResource(getContext(), R.drawable.ic_home),
                                 "Get ride home")))
                 .build();
     }
 
     private Slice createCustomToggleSlice(Uri sliceUri) {
-        ListBuilder b = new ListBuilder(getContext(), sliceUri);
+        ListBuilder b = new ListBuilder(getContext(), sliceUri, -TimeUnit.HOURS.toMillis(1));
         return b.setColor(0xffff4081)
                 .addRow(new ListBuilder.RowBuilder(b)
-                    .setTitle("Custom toggle")
-                    .setSubtitle("It can support two states")
-                    .addEndItem(new SliceAction(getBroadcastIntent(ACTION_TOAST, "star toggled"),
-                            Icon.createWithResource(getContext(), R.drawable.toggle_star),
-                            "Toggle star", true /* isChecked */)))
+                        .setTitle("Custom toggle")
+                        .addEndItem(
+                                new SliceAction(getBroadcastIntent(ACTION_TOAST, "star toggled"),
+                                        IconCompat.createWithResource(getContext(),
+                                                R.drawable.toggle_star),
+                                        "Toggle star", true /* isChecked */)))
                 .build();
     }
 
     private Slice createTwoCustomToggleSlices(Uri sliceUri) {
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY);
         return lb.setColor(0xffff4081)
                 .addRow(new ListBuilder.RowBuilder(lb)
                         .setTitle("2 toggles")
                         .setSubtitle("each supports two states")
                         .addEndItem(new SliceAction(
                                 getBroadcastIntent(ACTION_TOAST, "first star toggled"),
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                IconCompat.createWithResource(getContext(), R.drawable.toggle_star),
                                 "Toggle star", true /* isChecked */))
                         .addEndItem(new SliceAction(
                                 getBroadcastIntent(ACTION_TOAST, "second star toggled"),
-                                Icon.createWithResource(getContext(), R.drawable.toggle_star),
+                                IconCompat.createWithResource(getContext(), R.drawable.toggle_star),
                                 "Toggle star", false /* isChecked */)))
                 .build();
     }
@@ -375,35 +388,36 @@
                 break;
         }
         boolean finalWifiEnabled = wifiEnabled;
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY);
         SliceAction primaryAction = new SliceAction(getIntent(Settings.ACTION_WIFI_SETTINGS),
-                Icon.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
+                IconCompat.createWithResource(getContext(), R.drawable.ic_wifi), "Wi-fi Settings");
         lb.setColor(0xff4285f4);
         lb.addRow(new ListBuilder.RowBuilder(lb)
                 .setTitle("Wi-fi")
-                .setTitleItem(Icon.createWithResource(getContext(), R.drawable.ic_wifi), ICON_IMAGE)
+                .setTitleItem(IconCompat.createWithResource(getContext(), R.drawable.ic_wifi),
+                        ICON_IMAGE)
                 .setSubtitle(state)
                 .addEndItem(new SliceAction(getBroadcastIntent(ACTION_WIFI_CHANGED, null),
                         "Toggle wifi", finalWifiEnabled))
                 .setPrimaryAction(primaryAction));
 
         // Add keywords
-        String[] keywords = new String[] {"internet", "wifi", "data", "network"};
+        String[] keywords = new String[]{"internet", "wifi", "data", "network"};
         lb.setKeywords(Arrays.asList(keywords));
 
         // Add fake wifi networks
-        int[] wifiIcons = new int[] {R.drawable.ic_wifi_full, R.drawable.ic_wifi_low,
+        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);
+            IconCompat icon = IconCompat.createWithResource(getContext(), iconId);
             final String networkName = "Network" + i;
             ListBuilder.RowBuilder rb = new ListBuilder.RowBuilder(lb)
                     .setTitleItem(icon, ICON_IMAGE)
                     .setTitle("Network" + networkName);
             boolean locked = i % 3 == 0;
             if (locked) {
-                rb.addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_lock));
+                rb.addEndItem(IconCompat.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,
@@ -413,7 +427,8 @@
         if (customSeeMore) {
             lb.addSeeMoreRow(new ListBuilder.RowBuilder(lb)
                     .setTitle("See all available networks")
-                    .addEndItem(Icon.createWithResource(getContext(), R.drawable.ic_right_caret))
+                    .addEndItem(
+                            IconCompat.createWithResource(getContext(), R.drawable.ic_right_caret))
                     .setPrimaryAction(primaryAction));
         } else {
             lb.addSeeMoreAction(primaryAction.getAction());
@@ -422,29 +437,29 @@
     }
 
     private Slice createReservationSlice(Uri sliceUri) {
-        ListBuilder lb = new ListBuilder(getContext(), sliceUri);
+        ListBuilder lb = new ListBuilder(getContext(), sliceUri, INFINITY);
         GridRowBuilder gb1 = new GridRowBuilder(lb);
         gb1.addCell(new GridRowBuilder.CellBuilder(gb1)
-                .addImage(Icon.createWithResource(getContext(), R.drawable.reservation),
+                .addImage(IconCompat.createWithResource(getContext(), R.drawable.reservation),
                         LARGE_IMAGE)
                 .setContentDescription("Image of your reservation in Seattle"));
         GridRowBuilder gb2 = new GridRowBuilder(lb);
         gb2.addCell(new GridRowBuilder.CellBuilder(gb2)
-                    .addTitleText("Check In")
-                    .addText("12:00 PM, Feb 1"))
+                .addTitleText("Check In")
+                .addText("12:00 PM, Feb 1"))
                 .addCell(new GridRowBuilder.CellBuilder(gb2)
-                    .addTitleText("Check Out")
-                    .addText("11:00 AM, Feb 19"));
+                        .addTitleText("Check Out")
+                        .addText("11:00 AM, Feb 19"));
         return lb.setColor(0xffFF5252)
                 .setHeader(new ListBuilder.HeaderBuilder(lb)
                         .setTitle("Upcoming trip to Seattle")
                         .setSubtitle("Feb 1 - 19 | 2 guests"))
                 .addAction(new SliceAction(
                         getBroadcastIntent(ACTION_TOAST, "show location on map"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_location),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_location),
                         "Show reservation location"))
                 .addAction(new SliceAction(getBroadcastIntent(ACTION_TOAST, "contact host"),
-                        Icon.createWithResource(getContext(), R.drawable.ic_text),
+                        IconCompat.createWithResource(getContext(), R.drawable.ic_text),
                         "Contact host"))
                 .addGridRow(gb1)
                 .addGridRow(gb2)
diff --git a/slices/view/src/main/java/androidx/slice/SliceMetadata.java b/slices/view/src/main/java/androidx/slice/SliceMetadata.java
new file mode 100644
index 0000000..bf96854
--- /dev/null
+++ b/slices/view/src/main/java/androidx/slice/SliceMetadata.java
@@ -0,0 +1,195 @@
+/*
+ * 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.slice;
+
+import static android.app.slice.Slice.HINT_ACTIONS;
+import static android.app.slice.Slice.HINT_PARTIAL;
+import static android.app.slice.Slice.HINT_SHORTCUT;
+import static android.app.slice.SliceItem.FORMAT_SLICE;
+import static android.app.slice.SliceItem.FORMAT_TEXT;
+import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
+
+import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.RestrictTo;
+import androidx.slice.core.SliceQuery;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Utility class to parse a Slice and provide access to some information around its contents.
+ */
+public class SliceMetadata {
+
+    /**
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @IntDef({
+            LOADED_NONE, LOADED_PARTIAL, LOADED_ALL
+    })
+    public @interface SliceLoadingState{}
+
+    /**
+     * Indicates this slice is empty and waiting for content to be loaded.
+     */
+    public static final int LOADED_NONE = 0;
+    /**
+     * Indicates this slice has some content but is waiting for other content to be loaded.
+     */
+    public static final int LOADED_PARTIAL = 1;
+    /**
+     * Indicates this slice has fully loaded and is not waiting for other content.
+     */
+    public static final int LOADED_ALL = 2;
+
+    private Slice mSlice;
+    private Context mContext;
+    private long mExpiry;
+    private long mLastUpdated;
+    private List<SliceItem> mSliceActions;
+
+    /**
+     * Create a SliceMetadata object to provide access to some information around the slice and
+     * its contents.
+     *
+     * @param context the context to use for the slice.
+     * @param slice the slice to extract metadata from.
+     *
+     * @return the metadata associated with the provided slice.
+     */
+    public static SliceMetadata from(@NonNull Context context, @NonNull Slice slice) {
+        return new SliceMetadata(context, slice);
+    }
+
+    /**
+     * Create a SliceMetadata object to provide access to some information around the slice and
+     * its contents.
+     *
+     * @param context the context to use for the slice.
+     * @param slice the slice to extract metadata from.
+     */
+    private SliceMetadata(@NonNull Context context, @NonNull Slice slice) {
+        mSlice = slice;
+        mContext = context;
+        SliceItem ttlItem = SliceQuery.find(slice, FORMAT_TIMESTAMP, HINT_TTL, null);
+        if (ttlItem != null) {
+            mExpiry = ttlItem.getTimestamp();
+        }
+        SliceItem updatedItem = SliceQuery.find(slice, FORMAT_TIMESTAMP, HINT_LAST_UPDATED, null);
+        if (updatedItem != null) {
+            mLastUpdated = updatedItem.getTimestamp();
+        }
+        mSliceActions = getSliceActions(mSlice);
+    }
+
+    /**
+     * @return the group of actions associated with this slice, if they exist.
+     */
+    @Nullable
+    public List<SliceItem> getSliceActions() {
+        return mSliceActions;
+    }
+
+    /**
+     * @return the list of keywords associated with the provided slice, null if no keywords were
+     * specified or an empty list if the slice was specified to have no keywords.
+     */
+    @Nullable
+    public List<String> getSliceKeywords() {
+        SliceItem keywordGroup = SliceQuery.find(mSlice, FORMAT_SLICE, HINT_KEY_WORDS, null);
+        if (keywordGroup != null) {
+            List<SliceItem> itemList = SliceQuery.findAll(keywordGroup, FORMAT_TEXT);
+            if (itemList != null) {
+                ArrayList<String> stringList = new ArrayList<>();
+                for (int i = 0; i < itemList.size(); i++) {
+                    String keyword = (String) itemList.get(i).getText();
+                    if (!TextUtils.isEmpty(keyword)) {
+                        stringList.add(keyword);
+                    }
+                }
+                return stringList;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @return the current loading state for this slice.
+     *
+     * @see #LOADED_NONE
+     * @see #LOADED_PARTIAL
+     * @see #LOADED_ALL
+     */
+    public int getLoadingState() {
+        // Check loading state
+        boolean hasHintPartial = SliceQuery.find(mSlice, null, HINT_PARTIAL, null) != null;
+        if (mSlice.getItems().size() == 0) {
+            // Empty slice
+            return LOADED_NONE;
+        } else if (hasHintPartial) {
+            // Slice with specific content to load
+            return LOADED_PARTIAL;
+        } else {
+            // Full slice
+            return LOADED_ALL;
+        }
+    }
+
+    /**
+     * A slice contains an expiry to indicate when the content in the slice might no longer be
+     * valid.
+     *
+     * @return the time, measured in milliseconds, between the expiry time of this slice and
+     * midnight, January 1, 1970 UTC, or {@link androidx.slice.builders.ListBuilder#INFINITY} if
+     * the slice is not time-sensitive.
+     */
+    public long getExpiry() {
+        return mExpiry;
+    }
+
+    /**
+     * @return the time, measured in milliseconds, between when the slice was created or last
+     * updated, and midnight, January 1, 1970 UTC.
+     */
+    public long getLastUpdatedTime() {
+        return mLastUpdated;
+    }
+
+    /**
+     * @return the group of actions associated with the provided slice, if they exist.
+     * @hide
+     */
+    @Nullable
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public static List<SliceItem> getSliceActions(@NonNull Slice slice) {
+        SliceItem actionGroup = SliceQuery.find(slice, FORMAT_SLICE, HINT_ACTIONS, null);
+        String[] hints = new String[] {HINT_ACTIONS, HINT_SHORTCUT};
+        return (actionGroup != null)
+                ? SliceQuery.findAll(actionGroup, FORMAT_SLICE, hints, null)
+                : null;
+    }
+}
diff --git a/slices/view/src/main/java/androidx/slice/SliceUtils.java b/slices/view/src/main/java/androidx/slice/SliceUtils.java
index 62be594..40d82bc 100644
--- a/slices/view/src/main/java/androidx/slice/SliceUtils.java
+++ b/slices/view/src/main/java/androidx/slice/SliceUtils.java
@@ -25,23 +25,26 @@
 import static android.app.slice.SliceItem.FORMAT_SLICE;
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
+import static androidx.slice.SliceMetadata.LOADED_ALL;
+import static androidx.slice.SliceMetadata.LOADED_NONE;
+import static androidx.slice.SliceMetadata.LOADED_PARTIAL;
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
 
 import android.content.Context;
 import android.text.TextUtils;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
 import androidx.annotation.IntDef;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.slice.core.SliceQuery;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Utilities for dealing with slices.
  */
@@ -169,53 +172,55 @@
     }
 
     /**
-     * @hide
-     */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
-    @IntDef({
-            LOADING_ALL, LOADING_PARTIAL, LOADING_COMPLETE
-    })
-    public @interface SliceLoadingState{}
-
-    /**
      * Indicates this slice is empty and waiting for content to be loaded.
+     *
+     * @deprecated TO BE REMOVED: use {@link SliceMetadata#LOADED_NONE}
      */
+    @Deprecated
     public static final int LOADING_ALL = 0;
     /**
      * Indicates this slice has some content but is waiting for other content to be loaded.
+     *
+     * @deprecated TO BE REMOVED: use {@link SliceMetadata#LOADED_PARTIAL}
      */
+    @Deprecated
     public static final int LOADING_PARTIAL = 1;
     /**
      * Indicates this slice has fully loaded and is not waiting for other content.
+     *
+     * @deprecated TO BE REMOVED: use {@link SliceMetadata#LOADED_ALL}
      */
+    @Deprecated
     public static final int LOADING_COMPLETE = 2;
 
     /**
      * @return the current loading state of the provided {@link Slice}.
      *
-     * @see #LOADING_ALL
-     * @see #LOADING_PARTIAL
-     * @see #LOADING_COMPLETE
+     * @deprecated TO BE REMOVED: use {@link SliceMetadata#getLoadingState()}
      */
+    @Deprecated
     public static int getLoadingState(@NonNull Slice slice) {
         // Check loading state
         boolean hasHintPartial =
                 SliceQuery.find(slice, null, HINT_PARTIAL, null) != null;
         if (slice.getItems().size() == 0) {
             // Empty slice
-            return LOADING_ALL;
+            return LOADED_NONE;
         } else if (hasHintPartial) {
             // Slice with specific content to load
-            return LOADING_PARTIAL;
+            return LOADED_PARTIAL;
         } else {
             // Full slice
-            return LOADING_COMPLETE;
+            return LOADED_ALL;
         }
     }
 
     /**
      * @return the group of actions associated with the provided slice, if they exist.
+     *
+     * @deprecated TO BE REMOVED; use {@link SliceMetadata#getSliceActions()}
      */
+    @Deprecated
     @Nullable
     public static List<SliceItem> getSliceActions(@NonNull Slice slice) {
         SliceItem actionGroup = SliceQuery.find(slice, FORMAT_SLICE, HINT_ACTIONS, null);
@@ -228,7 +233,10 @@
     /**
      * @return the list of keywords associated with the provided slice, null if no keywords were
      * specified or an empty list if the slice was specified to have no keywords.
+     *
+     * @deprecated TO BE REMOVED; use {@link SliceMetadata#getSliceKeywords()}
      */
+    @Deprecated
     @Nullable
     public static List<String> getSliceKeywords(@NonNull Slice slice) {
         SliceItem keywordGroup = SliceQuery.find(slice, FORMAT_SLICE, HINT_KEY_WORDS, null);
diff --git a/slices/view/src/main/java/androidx/slice/SliceXml.java b/slices/view/src/main/java/androidx/slice/SliceXml.java
index 584ef6f..e8747be 100644
--- a/slices/view/src/main/java/androidx/slice/SliceXml.java
+++ b/slices/view/src/main/java/androidx/slice/SliceXml.java
@@ -23,13 +23,14 @@
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
 import android.net.Uri;
-import androidx.annotation.RestrictTo;
 import android.text.Html;
 import android.text.Spanned;
 import android.text.TextUtils;
 
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlPullParserFactory;
@@ -125,7 +126,7 @@
                                 int w = Integer.parseInt(split[0]);
                                 int h = Integer.parseInt(split[1]);
                                 Bitmap image = Bitmap.createBitmap(w, h, Bitmap.Config.ALPHA_8);
-                                b.addIcon(Icon.createWithBitmap(image), subtype, hints);
+                                b.addIcon(IconCompat.createWithBitmap(image), subtype, hints);
                             }
                         }
                         break;
diff --git a/slices/view/src/main/java/androidx/slice/widget/ActionContent.java b/slices/view/src/main/java/androidx/slice/widget/ActionContent.java
deleted file mode 100644
index 877492d..0000000
--- a/slices/view/src/main/java/androidx/slice/widget/ActionContent.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.slice.widget;
-
-import static android.app.slice.Slice.HINT_SELECTED;
-import static android.app.slice.Slice.HINT_SHORTCUT;
-import static android.app.slice.Slice.HINT_TITLE;
-import static android.app.slice.Slice.SUBTYPE_CONTENT_DESCRIPTION;
-import static android.app.slice.Slice.SUBTYPE_PRIORITY;
-import static android.app.slice.Slice.SUBTYPE_TOGGLE;
-import static android.app.slice.SliceItem.FORMAT_ACTION;
-import static android.app.slice.SliceItem.FORMAT_IMAGE;
-import static android.app.slice.SliceItem.FORMAT_INT;
-import static android.app.slice.SliceItem.FORMAT_SLICE;
-import static android.app.slice.SliceItem.FORMAT_TEXT;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.RestrictTo;
-import androidx.slice.SliceItem;
-import androidx.slice.core.SliceQuery;
-
-/**
- * Extracts information required to present an action button from a slice.
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-public class ActionContent {
-    private SliceItem mSliceItem;
-    private SliceItem mIconItem;
-    private SliceItem mActionItem;
-    private SliceItem mTitleItem;
-    private SliceItem mContentDescItem;
-    private boolean mIsToggle;
-    private boolean mIsChecked;
-    private int mPriority;
-
-    public ActionContent(@NonNull SliceItem slice) {
-        populate(slice);
-    }
-
-    /**
-     * @return whether this slice is a valid action.
-     */
-    private boolean populate(@NonNull SliceItem slice) {
-        mSliceItem = slice;
-        if (slice.hasHint(HINT_SHORTCUT) && FORMAT_SLICE.equals(slice.getFormat())) {
-            mActionItem = SliceQuery.find(slice, FORMAT_ACTION);
-            if (mActionItem == null) {
-                // Can't have action slice without action
-                return false;
-            }
-            mIconItem = SliceQuery.find(mActionItem.getSlice(), FORMAT_IMAGE);
-            mTitleItem = SliceQuery.find(mActionItem.getSlice(), FORMAT_TEXT, HINT_TITLE,
-                    null /* nonHints */);
-            mContentDescItem = SliceQuery.findSubtype(mActionItem.getSlice(), FORMAT_TEXT,
-                    SUBTYPE_CONTENT_DESCRIPTION);
-            mIsToggle = SUBTYPE_TOGGLE.equals(mActionItem.getSubType());
-            if (mIsToggle) {
-                mIsChecked = mActionItem.hasHint(HINT_SELECTED);
-            }
-            SliceItem priority = SliceQuery.findSubtype(mActionItem.getSlice(), FORMAT_INT,
-                    SUBTYPE_PRIORITY);
-            mPriority = priority != null ? priority.getInt() : -1;
-            return true;
-        } else if (FORMAT_ACTION.equals(slice.getFormat())) {
-            mActionItem = slice;
-        }
-        return false;
-    }
-
-    /**
-     * @return the SliceItem used to construct this ActionContent.
-     */
-    @NonNull
-    public SliceItem getSliceItem() {
-        return mSliceItem;
-    }
-
-    /**
-     * @return the pending intent associated with this action.
-     */
-    @Nullable
-    public SliceItem getActionItem() {
-        return mActionItem;
-    }
-
-    /**
-     * @return the icon associated with this action.
-     */
-    @Nullable
-    public SliceItem getIconItem() {
-        return mIconItem;
-    }
-
-    /**
-     * @return the title associated with this action.
-     */
-    @Nullable
-    public SliceItem getTitleItem() {
-        return mTitleItem;
-    }
-
-    /**
-     * @return the content description associated with this action.
-     */
-    @Nullable
-    public CharSequence getContentDescription() {
-        return mContentDescItem != null
-                ? mContentDescItem.getText()
-                : mTitleItem != null ? mTitleItem.getText() : null;
-    }
-
-    /**
-     * @return the priority associated with this action, if it exists.
-     */
-    public int getPriority() {
-        return mPriority;
-    }
-
-    /**
-     * @return Whether this action is toggleable.
-     */
-    public boolean isToggle() {
-        return mIsToggle;
-    }
-
-    /**
-     * @return Whether this action represents a custom toggle.
-     */
-    public boolean isCustomToggle() {
-        return mIconItem != null && mIsToggle;
-    }
-
-    /**
-     * @return Whether this action is 'checked' or not (i.e. if toggle is on).
-     */
-    public boolean isChecked() {
-        return mIsChecked;
-    }
-}
diff --git a/slices/view/src/main/java/androidx/slice/widget/ActionRow.java b/slices/view/src/main/java/androidx/slice/widget/ActionRow.java
index 78c4a3f..98ebfd2 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ActionRow.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ActionRow.java
@@ -20,6 +20,8 @@
 import static android.app.slice.SliceItem.FORMAT_IMAGE;
 import static android.app.slice.SliceItem.FORMAT_REMOTE_INPUT;
 
+import static androidx.slice.core.SliceHints.ICON_IMAGE;
+
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.app.RemoteInput;
@@ -27,9 +29,6 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
-import android.graphics.drawable.Icon;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 import android.util.TypedValue;
 import android.view.View;
 import android.view.ViewParent;
@@ -39,11 +38,16 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import java.util.List;
-
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.widget.ImageViewCompat;
 import androidx.slice.SliceItem;
+import androidx.slice.core.SliceActionImpl;
 import androidx.slice.core.SliceQuery;
 
+import java.util.List;
+
 /**
  * @hide
  */
@@ -75,25 +79,25 @@
         mColor = color;
         for (int i = 0; i < mActionsGroup.getChildCount(); i++) {
             View view = mActionsGroup.getChildAt(i);
-            SliceItem item = (SliceItem) view.getTag();
-            boolean tint = !item.hasHint(HINT_NO_TINT);
+            int mode = (Integer) view.getTag();
+            boolean tint = mode == ICON_IMAGE;
             if (tint) {
-                ((ImageView) view).setImageTintList(ColorStateList.valueOf(mColor));
+                ImageViewCompat.setImageTintList((ImageView) view, ColorStateList.valueOf(mColor));
             }
         }
     }
 
-    private ImageView addAction(Icon icon, boolean allowTint, SliceItem image) {
+    private ImageView addAction(IconCompat icon, boolean allowTint) {
         ImageView imageView = new ImageView(getContext());
         imageView.setPadding(mIconPadding, mIconPadding, mIconPadding, mIconPadding);
         imageView.setScaleType(ScaleType.FIT_CENTER);
-        imageView.setImageIcon(icon);
+        imageView.setImageDrawable(icon.loadDrawable(getContext()));
         if (allowTint) {
-            imageView.setImageTintList(ColorStateList.valueOf(mColor));
+            ImageViewCompat.setImageTintList(imageView, ColorStateList.valueOf(mColor));
         }
         imageView.setBackground(SliceViewUtil.getDrawable(getContext(),
                 android.R.attr.selectableItemBackground));
-        imageView.setTag(image);
+        imageView.setTag(allowTint);
         addAction(imageView);
         return imageView;
     }
@@ -117,7 +121,7 @@
             if (input != null && image != null
                     && input.getRemoteInput().getAllowFreeFormInput()) {
                 boolean tint = !image.hasHint(HINT_NO_TINT);
-                addAction(image.getIcon(), tint, image).setOnClickListener(
+                addAction(image.getIcon(), tint).setOnClickListener(
                         new OnClickListener() {
                             @Override
                             public void onClick(View v) {
@@ -127,16 +131,17 @@
                         });
                 createRemoteInputView(mColor, getContext());
             } else if (action.hasHint(Slice.HINT_SHORTCUT)) {
-                final ActionContent ac = new ActionContent(action);
-                SliceItem iconItem = ac.getIconItem();
-                if (iconItem != null && ac.getActionItem() != null) {
-                    boolean tint = !iconItem.hasHint(HINT_NO_TINT);
-                    addAction(iconItem.getIcon(), tint, image).setOnClickListener(
+                final SliceActionImpl ac = new SliceActionImpl(action);
+                IconCompat iconItem = ac.getIcon();
+                if (iconItem != null && ac.getAction() != null) {
+                    boolean tint = ac.getImageMode() == ICON_IMAGE;
+                    addAction(iconItem, tint).setOnClickListener(
                             new OnClickListener() {
                                 @Override
                                 public void onClick(View v) {
                                     try {
-                                        ac.getActionItem().getAction().send();
+                                        // TODO - should log events here
+                                        ac.getAction().send();
                                     } catch (CanceledException e) {
                                         e.printStackTrace();
                                     }
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridContent.java b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
index 64ead75..14a05aa 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridContent.java
@@ -30,26 +30,28 @@
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
-import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
-import static androidx.slice.builders.ListBuilder.LARGE_IMAGE;
-import static androidx.slice.builders.ListBuilder.SMALL_IMAGE;
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
+import static androidx.slice.core.SliceHints.ICON_IMAGE;
+import static androidx.slice.core.SliceHints.LARGE_IMAGE;
+import static androidx.slice.core.SliceHints.SMALL_IMAGE;
 
 import android.app.slice.Slice;
 import android.content.Context;
 import android.content.res.Resources;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.slice.SliceItem;
-import androidx.slice.builders.ListBuilder;
+import androidx.slice.core.SliceHints;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.view.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Extracts information required to present content in a grid format from a slice.
  * @hide
@@ -64,7 +66,7 @@
     private SliceItem mSeeMoreItem;
     private int mMaxCellLineCount;
     private boolean mHasImage;
-    private @ListBuilder.ImageMode int mLargestImageMode;
+    private @SliceHints.ImageMode int mLargestImageMode;
     private SliceItem mContentDescr;
 
     private int mBigPicMinHeight;
@@ -195,10 +197,11 @@
         List<SliceItem> filteredItems = new ArrayList<>();
         for (int i = 0; i < items.size(); i++) {
             SliceItem item = items.get(i);
+            boolean isNonCellContent = item.hasAnyHints(HINT_SHORTCUT, HINT_SEE_MORE,
+                    HINT_KEY_WORDS, HINT_TTL, HINT_LAST_UPDATED);
             if (SUBTYPE_CONTENT_DESCRIPTION.equals(item.getSubType())) {
                 mContentDescr = item;
-            } else if (item.hasHint(HINT_LIST_ITEM) && !item.hasAnyHints(HINT_SHORTCUT,
-                    HINT_SEE_MORE, HINT_KEY_WORDS)) {
+            } else if (item.hasHint(HINT_LIST_ITEM) && !isNonCellContent) {
                 filteredItems.add(item);
             }
         }
@@ -333,9 +336,9 @@
          */
         private boolean isValidCellContent(SliceItem cellItem) {
             final String format = cellItem.getFormat();
-            boolean isSpecial = SUBTYPE_CONTENT_DESCRIPTION.equals(cellItem.getSubType())
-                    || cellItem.hasHint(HINT_KEY_WORDS);
-            return !isSpecial
+            boolean isNonCellContent = SUBTYPE_CONTENT_DESCRIPTION.equals(cellItem.getSubType())
+                    || cellItem.hasAnyHints(HINT_KEY_WORDS, HINT_TTL, HINT_LAST_UPDATED);
+            return !isNonCellContent
                     && (FORMAT_TEXT.equals(format)
                     || FORMAT_TIMESTAMP.equals(format)
                     || FORMAT_IMAGE.equals(format));
diff --git a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
index 54302ba..dce37e0 100644
--- a/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/GridRowView.java
@@ -17,6 +17,7 @@
 package androidx.slice.widget;
 
 import static android.app.slice.Slice.HINT_LARGE;
+import static android.app.slice.Slice.HINT_LIST_ITEM;
 import static android.app.slice.Slice.HINT_NO_TINT;
 import static android.app.slice.Slice.HINT_TITLE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
@@ -46,10 +47,6 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
 import androidx.annotation.ColorInt;
 import androidx.annotation.RestrictTo;
 import androidx.slice.Slice;
@@ -57,6 +54,10 @@
 import androidx.slice.core.SliceQuery;
 import androidx.slice.view.R;
 
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
 /**
  * @hide
  */
@@ -139,7 +140,8 @@
     public void setSlice(Slice slice) {
         resetView();
         mRowIndex = 0;
-        mGridContent = new GridContent(getContext(), slice.getItems().get(0));
+        SliceItem item = SliceQuery.find(slice, FORMAT_SLICE, HINT_LIST_ITEM, null);
+        mGridContent = new GridContent(getContext(), item);
         populateViews(mGridContent);
     }
 
@@ -325,7 +327,7 @@
             addedView = tv;
         } else if (FORMAT_IMAGE.equals(format)) {
             ImageView iv = new ImageView(getContext());
-            iv.setImageIcon(item.getIcon());
+            iv.setImageDrawable(item.getIcon().loadDrawable(getContext()));
             LinearLayout.LayoutParams lp;
             if (item.hasHint(HINT_LARGE)) {
                 iv.setScaleType(ScaleType.CENTER_CROP);
diff --git a/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java b/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
index 48fe80b..ffa64c4 100644
--- a/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
+++ b/slices/view/src/main/java/androidx/slice/widget/LargeSliceAdapter.java
@@ -27,8 +27,6 @@
 
 import android.app.slice.Slice;
 import android.content.Context;
-import androidx.annotation.RestrictTo;
-import androidx.recyclerview.widget.RecyclerView;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
@@ -36,14 +34,16 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 
-import java.util.ArrayList;
-import java.util.List;
-import java.util.function.Consumer;
-
+import androidx.annotation.RestrictTo;
+import androidx.recyclerview.widget.RecyclerView;
 import androidx.slice.SliceItem;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.view.R;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
 /**
  * @hide
  */
@@ -56,6 +56,8 @@
     static final int TYPE_MESSAGE       = 4;
     static final int TYPE_MESSAGE_LOCAL = 5;
 
+    static final int HEADER_INDEX = 0;
+
     private final IdGenerator mIdGen = new IdGenerator();
     private final Context mContext;
     private List<SliceWrapper> mSlices = new ArrayList<>();
@@ -63,6 +65,8 @@
     private int mColor;
     private AttributeSet mAttrs;
     private List<SliceItem> mSliceActions;
+    private boolean mShowLastUpdated;
+    private long mLastUpdated;
 
     public LargeSliceAdapter(Context context) {
         mContext = context;
@@ -78,9 +82,7 @@
      */
     public void setSliceActions(List<SliceItem> actions) {
         mSliceActions = actions;
-        if (getItemCount() > 0) {
-            notifyItemChanged(0); // Header item (index 0) displays the actions
-        }
+        notifyHeaderChanged();
     }
 
     /**
@@ -108,6 +110,22 @@
         notifyDataSetChanged();
     }
 
+    /**
+     * Sets whether the last updated time should be shown on the slice.
+     */
+    public void setShowLastUpdated(boolean showLastUpdated) {
+        mShowLastUpdated = showLastUpdated;
+        notifyHeaderChanged();
+    }
+
+    /**
+     * Sets when the slice was last updated.
+     */
+    public void setLastUpdated(long lastUpdated) {
+        mLastUpdated = lastUpdated;
+        notifyHeaderChanged();
+    }
+
     @Override
     public SliceViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         View v = inflateForType(viewType);
@@ -134,16 +152,24 @@
     public void onBindViewHolder(SliceViewHolder holder, int position) {
         SliceWrapper slice = mSlices.get(position);
         if (holder.mSliceView != null) {
-            final boolean isHeader = position == 0;
+            final boolean isHeader = position == HEADER_INDEX;
             holder.mSliceView.setTint(mColor);
             holder.mSliceView.setStyle(mAttrs);
             holder.mSliceView.setSliceItem(slice.mItem, isHeader, position, mSliceObserver);
             if (isHeader && holder.mSliceView instanceof RowView) {
                 holder.mSliceView.setSliceActions(mSliceActions);
+                holder.mSliceView.setLastUpdated(mLastUpdated);
+                holder.mSliceView.setShowLastUpdated(mShowLastUpdated);
             }
         }
     }
 
+    private void notifyHeaderChanged() {
+        if (getItemCount() > 0) {
+            notifyItemChanged(HEADER_INDEX);
+        }
+    }
+
     private View inflateForType(int viewType) {
         View v = new RowView(mContext);
         switch (viewType) {
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 7b51451..36409e8 100644
--- a/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/LargeTemplateView.java
@@ -17,17 +17,17 @@
 package androidx.slice.widget;
 
 import android.content.Context;
+import android.util.AttributeSet;
+
 import androidx.annotation.RestrictTo;
 import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
-import android.util.AttributeSet;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-
 /**
  * @hide
  */
@@ -102,6 +102,18 @@
         mAdapter.setStyle(attrs);
     }
 
+    @Override
+    public void setShowLastUpdated(boolean showLastUpdated) {
+        super.setShowLastUpdated(showLastUpdated);
+        mAdapter.setShowLastUpdated(showLastUpdated);
+    }
+
+    @Override
+    public void setLastUpdated(long lastUpdated) {
+        super.setLastUpdated(lastUpdated);
+        mAdapter.setLastUpdated(lastUpdated);
+    }
+
     private void populate() {
         if (mSlice == null) {
             resetView();
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 1a0f069..955144d 100644
--- a/slices/view/src/main/java/androidx/slice/widget/ListContent.java
+++ b/slices/view/src/main/java/androidx/slice/widget/ListContent.java
@@ -28,6 +28,8 @@
 import static android.app.slice.SliceItem.FORMAT_TEXT;
 
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
 
 import android.content.Context;
 
@@ -36,7 +38,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
-import androidx.slice.SliceUtils;
+import androidx.slice.SliceMetadata;
 import androidx.slice.core.SliceQuery;
 
 import java.util.ArrayList;
@@ -62,22 +64,12 @@
     }
 
     /**
-     * Resets the content.
-     */
-    public void reset() {
-        mColorItem = null;
-        mHeaderItem = null;
-        mRowItems.clear();
-    }
-
-    /**
      * @return whether this row has content that is valid to display.
      */
     private boolean populate(Slice slice) {
-        reset();
         mColorItem = SliceQuery.findSubtype(slice, FORMAT_INT, SUBTYPE_COLOR);
         // Find slice actions
-        mSliceActions = SliceUtils.getSliceActions(slice);
+        mSliceActions = SliceMetadata.getSliceActions(slice);
         // Find header
         mHeaderItem = findHeaderItem(slice);
         if (mHeaderItem != null) {
@@ -89,8 +81,9 @@
         for (int i = 0; i < children.size(); i++) {
             final SliceItem child = children.get(i);
             final String format = child.getFormat();
-            if (!child.hasAnyHints(HINT_ACTIONS, HINT_SEE_MORE, HINT_KEY_WORDS)
-                    && (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
+            boolean isNonRowContent = child.hasAnyHints(HINT_ACTIONS, HINT_SEE_MORE, HINT_KEY_WORDS,
+                    HINT_TTL, HINT_LAST_UPDATED);
+            if (!isNonRowContent && (FORMAT_ACTION.equals(format) || FORMAT_SLICE.equals(format))) {
                 if (mHeaderItem == null && !child.hasHint(HINT_LIST_ITEM)) {
                     mHeaderItem = child;
                     mRowItems.add(0, child);
@@ -221,7 +214,7 @@
     private static SliceItem findHeaderItem(@NonNull Slice slice) {
         // See if header is specified
         String[] nonHints = new String[] {HINT_LIST_ITEM, HINT_SHORTCUT, HINT_ACTIONS,
-                HINT_KEY_WORDS};
+                HINT_KEY_WORDS, HINT_TTL, HINT_LAST_UPDATED};
         SliceItem header = SliceQuery.find(slice, FORMAT_SLICE, null, nonHints);
         if (header != null && isValidHeader(header)) {
             return header;
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 e08ceb0..7565895 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_PARTIAL;
 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;
@@ -31,6 +32,8 @@
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
 import static androidx.slice.core.SliceHints.HINT_KEY_WORDS;
+import static androidx.slice.core.SliceHints.HINT_LAST_UPDATED;
+import static androidx.slice.core.SliceHints.HINT_TTL;
 import static androidx.slice.core.SliceHints.SUBTYPE_RANGE;
 
 import android.content.Context;
@@ -271,7 +274,9 @@
     }
 
     private static boolean hasText(SliceItem textSlice) {
-        return textSlice != null && !TextUtils.isEmpty(textSlice.getText());
+        return textSlice != null
+                && (textSlice.hasHint(HINT_PARTIAL)
+                    || !TextUtils.isEmpty(textSlice.getText()));
     }
 
     /**
@@ -337,11 +342,10 @@
      * @return whether this item is valid content to display in a row.
      */
     private static boolean isValidRowContent(SliceItem slice, SliceItem item) {
-        if (item.hasHint(HINT_KEY_WORDS)) {
+        if (item.hasAnyHints(HINT_KEY_WORDS, HINT_TTL, HINT_LAST_UPDATED)) {
             return false;
         }
-        if (FORMAT_SLICE.equals(item.getFormat())
-                && !item.hasAnyHints(HINT_SHORTCUT, HINT_KEY_WORDS)) {
+        if (FORMAT_SLICE.equals(item.getFormat()) && !item.hasHint(HINT_SHORTCUT)) {
             // Unpack contents of slice
             item = item.getSlice().getItems().get(0);
         }
@@ -367,6 +371,7 @@
         final String type = item.getFormat();
         return (FORMAT_ACTION.equals(type) && (SliceQuery.find(item, FORMAT_IMAGE) != null))
                     || FORMAT_IMAGE.equals(type)
-                    || FORMAT_TIMESTAMP.equals(type);
+                    || (FORMAT_TIMESTAMP.equals(type)
+                && !item.hasAnyHints(HINT_TTL, HINT_LAST_UPDATED));
     }
 }
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 18b0d54..21264f5 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -18,6 +18,7 @@
 
 import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
 import static android.app.slice.Slice.HINT_NO_TINT;
+import static android.app.slice.Slice.HINT_PARTIAL;
 import static android.app.slice.Slice.HINT_SHORTCUT;
 import static android.app.slice.Slice.SUBTYPE_TOGGLE;
 import static android.app.slice.SliceItem.FORMAT_ACTION;
@@ -27,6 +28,8 @@
 import static android.app.slice.SliceItem.FORMAT_TIMESTAMP;
 
 import static androidx.slice.core.SliceHints.EXTRA_RANGE_VALUE;
+import static androidx.slice.core.SliceHints.ICON_IMAGE;
+import static androidx.slice.core.SliceHints.SMALL_IMAGE;
 import static androidx.slice.core.SliceHints.SUBTYPE_MAX;
 import static androidx.slice.core.SliceHints.SUBTYPE_VALUE;
 import static androidx.slice.widget.SliceView.MODE_SMALL;
@@ -35,7 +38,10 @@
 import android.app.PendingIntent.CanceledException;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Icon;
+import android.graphics.Typeface;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.LayoutInflater;
@@ -53,8 +59,10 @@
 
 import androidx.annotation.ColorInt;
 import androidx.annotation.RestrictTo;
+import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
+import androidx.slice.core.SliceActionImpl;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.view.R;
 
@@ -79,6 +87,7 @@
     private LinearLayout mContent;
     private TextView mPrimaryText;
     private TextView mSecondaryText;
+    private TextView mLastUpdatedText;
     private View mDivider;
     private ArrayList<CompoundButton> mToggles = new ArrayList<>();
     private LinearLayout mEndContainer;
@@ -88,7 +97,7 @@
 
     private int mRowIndex;
     private RowContent mRowContent;
-    private ActionContent mRowAction;
+    private SliceActionImpl mRowAction;
     private boolean mIsHeader;
     private List<SliceItem> mHeaderActions;
 
@@ -108,6 +117,7 @@
         mContent = (LinearLayout) findViewById(android.R.id.content);
         mPrimaryText = (TextView) findViewById(android.R.id.title);
         mSecondaryText = (TextView) findViewById(android.R.id.summary);
+        mLastUpdatedText = (TextView) findViewById(R.id.last_updated);
         mDivider = findViewById(R.id.divider);
         mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
         mSeekBar = (SeekBar) findViewById(R.id.seek_bar);
@@ -144,6 +154,14 @@
     }
 
     @Override
+    public void setShowLastUpdated(boolean showLastUpdated) {
+        super.setShowLastUpdated(showLastUpdated);
+        if (mRowContent != null) {
+            populateViews();
+        }
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int height = getMode() == MODE_SMALL ? getSmallHeight() : getActualHeight();
         heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
@@ -208,17 +226,10 @@
         mPrimaryText.setTextColor(mTitleColor);
         mPrimaryText.setVisibility(titleItem != null ? View.VISIBLE : View.GONE);
 
-        final SliceItem subTitle = getMode() == MODE_SMALL
+        final SliceItem subtitleItem = getMode() == MODE_SMALL
                 ? mRowContent.getSummaryItem()
                 : mRowContent.getSubtitleItem();
-        if (subTitle != null) {
-            mSecondaryText.setText(subTitle.getText());
-        }
-        mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
-                ? mHeaderSubtitleSize
-                : mSubtitleSize);
-        mSecondaryText.setTextColor(mSubtitleColor);
-        mSecondaryText.setVisibility(subTitle != null ? View.VISIBLE : View.GONE);
+        addSubtitle(subtitleItem);
 
         final SliceItem range = mRowContent.getRange();
         if (range != null) {
@@ -228,7 +239,7 @@
 
         SliceItem primaryAction = mRowContent.getPrimaryAction();
         if (primaryAction != null) {
-            mRowAction = new ActionContent(primaryAction);
+            mRowAction = new SliceActionImpl(primaryAction);
             if (mRowAction.isToggle()) {
                 // If primary action is a toggle, add it and we're done
                 addToggle(mRowAction, mTintColor, mEndContainer);
@@ -236,9 +247,9 @@
                 return;
             }
         }
-        List<SliceItem> endItems = mRowContent.getEndItems();
 
-        // If we're here we might be able to show end items
+        // If we're here we can can show end items; check for top level actions first
+        List<SliceItem> endItems = mRowContent.getEndItems();
         String desiredFormat = FORMAT_ACTION;
         if (mIsHeader && mHeaderActions != null && mHeaderActions.size() > 0) {
             // Use these if we have them instead
@@ -297,13 +308,44 @@
             if (mRowContent.endItemsContainAction() && itemCount == 1) {
                 SliceItem unwrappedActionItem = endItems.get(0).getSlice().getItems().get(0);
                 if (!SUBTYPE_TOGGLE.equals(unwrappedActionItem.getSubType())) {
-                    mRowAction = new ActionContent(endItems.get(0));
+                    mRowAction = new SliceActionImpl(endItems.get(0));
                 }
                 setViewClickable(this, true);
             }
         }
     }
 
+    private void addSubtitle(final SliceItem subtitleItem) {
+        CharSequence subtitleTimeString = null;
+        if (mShowLastUpdated) {
+            subtitleTimeString = getResources().getString(R.string.abc_slice_updated,
+                    SliceViewUtil.getRelativeTimeString(mLastUpdated));
+        }
+        CharSequence subtitle = subtitleItem != null ? subtitleItem.getText() : null;
+        boolean subtitleExists = !TextUtils.isEmpty(subtitle)
+                        || (subtitleItem != null && subtitleItem.hasHint(HINT_PARTIAL));
+        if (subtitleExists) {
+            mSecondaryText.setText(subtitle);
+            mSecondaryText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mIsHeader
+                    ? mHeaderSubtitleSize
+                    : mSubtitleSize);
+            mSecondaryText.setTextColor(mSubtitleColor);
+        }
+        if (subtitleTimeString != null) {
+            if (!TextUtils.isEmpty(subtitle)) {
+                subtitleTimeString = " \u00B7 " + subtitleTimeString;
+            }
+            SpannableString sp = new SpannableString(subtitleTimeString);
+            sp.setSpan(new StyleSpan(Typeface.ITALIC), 0, subtitleTimeString.length(), 0);
+            mLastUpdatedText.setText(sp);
+            mLastUpdatedText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                    mIsHeader ? mHeaderSubtitleSize : mSubtitleSize);
+            mLastUpdatedText.setTextColor(mSubtitleColor);
+        }
+        mLastUpdatedText.setVisibility(TextUtils.isEmpty(subtitleTimeString) ? GONE : VISIBLE);
+        mSecondaryText.setVisibility(subtitleExists ? VISIBLE : GONE);
+    }
+
     private void addRange(final SliceItem range) {
         final boolean isSeekBar = FORMAT_ACTION.equals(range.getFormat());
         final ProgressBar progressBar = isSeekBar ? mSeekBar : mProgressBar;
@@ -344,11 +386,11 @@
     /**
      * Add a toggle view to container.
      */
-    private void addToggle(final ActionContent actionContent, int color, ViewGroup container) {
+    private void addToggle(final SliceActionImpl actionContent, int color, ViewGroup container) {
         // Check if this is a custom toggle
         final CompoundButton toggle;
-        if (actionContent.isCustomToggle()) {
-            Icon checkedIcon = actionContent.getIconItem().getIcon();
+        if (actionContent.isToggle() && !actionContent.isDefaultToggle()) {
+            IconCompat checkedIcon = actionContent.getIcon();
             if (color != -1) {
                 // TODO - Should custom toggle buttons be tinted? What if the app wants diff
                 // colors per state?
@@ -375,7 +417,7 @@
             @Override
             public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                 try {
-                    PendingIntent pi = actionContent.getActionItem().getAction();
+                    PendingIntent pi = actionContent.getAction();
                     Intent i = new Intent().putExtra(EXTRA_TOGGLE_STATE, isChecked);
                     pi.send(getContext(), 0, i, null, null);
                     if (mObserver != null) {
@@ -399,15 +441,15 @@
      */
     private boolean addItem(SliceItem sliceItem, int color, boolean isStart, int padding,
             final EventInfo info) {
-        SliceItem image = null;
-        SliceItem action = null;
+        IconCompat icon = null;
+        int imageMode = 0;
         SliceItem timeStamp = null;
-        ActionContent actionContent = null;
+        SliceActionImpl actionContent = null;
         ViewGroup container = isStart ? mStartContainer : mEndContainer;
         if (FORMAT_SLICE.equals(sliceItem.getFormat())) {
             // It's an action.... let's make it so
             if (sliceItem.hasHint(HINT_SHORTCUT)) {
-                actionContent = new ActionContent(sliceItem);
+                actionContent = new SliceActionImpl(sliceItem);
             } else {
                 sliceItem = sliceItem.getSlice().getItems().get(0);
             }
@@ -417,20 +459,23 @@
                 addToggle(actionContent, color, container);
                 return true;
             }
-            action = actionContent.getActionItem();
-            image = actionContent.getIconItem();
+            icon = actionContent.getIcon();
+            if (icon != null) {
+                imageMode = actionContent.getImageMode();
+            }
         }
         if (FORMAT_IMAGE.equals(sliceItem.getFormat())) {
-            image = sliceItem;
+            icon = sliceItem.getIcon();
+            imageMode = sliceItem.hasHint(HINT_NO_TINT) ? SMALL_IMAGE : ICON_IMAGE;
         } else if (FORMAT_TIMESTAMP.equals(sliceItem.getFormat())) {
             timeStamp = sliceItem;
         }
         View addedView = null;
-        if (image != null) {
+        if (icon != null) {
             ImageView iv = new ImageView(getContext());
-            iv.setImageIcon(image.getIcon());
+            iv.setImageDrawable(icon.loadDrawable(getContext()));
             int size = mImageSize;
-            if (!image.hasHint(HINT_NO_TINT)) {
+            if (imageMode == ICON_IMAGE) {
                 if (color != -1) {
                     iv.setColorFilter(color);
                 }
@@ -453,15 +498,15 @@
             container.addView(tv);
             addedView = tv;
         }
-        if (action != null && addedView != null) {
-            final SliceItem sliceAction = action;
+        if (actionContent != null && addedView != null) {
+            final SliceActionImpl finalAction = actionContent;
             addedView.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     try {
-                        sliceAction.getAction().send();
+                        finalAction.getAction().send();
                         if (mObserver != null) {
-                            mObserver.onSliceAction(info, sliceAction);
+                            mObserver.onSliceAction(info, finalAction.getSliceItem());
                         }
                     } catch (CanceledException e) {
                         e.printStackTrace();
@@ -501,10 +546,10 @@
 
     @Override
     public void onClick(View view) {
-        if (mRowAction != null && mRowAction.getActionItem() != null && !mRowAction.isToggle()) {
+        if (mRowAction != null && mRowAction.getAction() != null && !mRowAction.isToggle()) {
             // Check for a row action
             try {
-                mRowAction.getActionItem().getAction().send();
+                mRowAction.getAction().send();
                 if (mObserver != null) {
                     EventInfo info = new EventInfo(getMode(), EventInfo.ACTION_TYPE_CONTENT,
                             EventInfo.ROW_TYPE_LIST, mRowIndex);
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceChildView.java b/slices/view/src/main/java/androidx/slice/widget/SliceChildView.java
index 8250a9e..2e52246 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceChildView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceChildView.java
@@ -18,19 +18,19 @@
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.FrameLayout;
 
-import java.util.List;
-
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
 import androidx.slice.view.R;
 
+import java.util.List;
+
 /**
  * Base class for children views of {@link SliceView}.
  * @hide
@@ -49,6 +49,8 @@
     protected int mSubtitleSize;
     protected int mGridTitleSize;
     protected int mGridSubtitleSize;
+    protected boolean mShowLastUpdated;
+    protected long mLastUpdated = -1;
 
     public SliceChildView(@NonNull Context context) {
         super(context);
@@ -113,6 +115,20 @@
     }
 
     /**
+     * Sets whether the last updated time should be displayed.
+     */
+    public void setShowLastUpdated(boolean showLastUpdated) {
+        mShowLastUpdated = showLastUpdated;
+    }
+
+    /**
+     * Sets when the content of this view was last updated.
+     */
+    public void setLastUpdated(long lastUpdated) {
+        mLastUpdated = lastUpdated;
+    }
+
+    /**
      * Sets the observer to notify when an interaction events occur on the view.
      */
     public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
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 9fb977e..272bbdc 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceView.java
@@ -35,7 +35,8 @@
 import androidx.lifecycle.Observer;
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
-import androidx.slice.SliceUtils;
+import androidx.slice.SliceMetadata;
+import androidx.slice.core.SliceHints;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.view.R;
 
@@ -122,6 +123,7 @@
 
     private boolean mShowActions = false;
     private boolean mIsScrollable = true;
+    private boolean mShowLastUpdated = true;
 
     private final int mShortcutSize;
     private final int mMinLargeHeight;
@@ -261,15 +263,14 @@
      */
     public void setSlice(@Nullable Slice slice) {
         if (slice != null) {
-            if (mCurrentSlice == null || mCurrentSlice.getUri() != slice.getUri()) {
-                // New slice, new actions
-                mActions = SliceUtils.getSliceActions(slice);
+            if (mCurrentSlice == null || !mCurrentSlice.getUri().equals(slice.getUri())) {
                 mCurrentView.resetView();
             }
         } else {
             // No slice, no actions
             mActions = null;
         }
+        mActions = SliceMetadata.getSliceActions(slice);
         mCurrentSlice = slice;
         reinflate();
     }
@@ -290,14 +291,14 @@
      * It is required that the slice be set on this view before actions can be set, otherwise
      * this will throw {@link IllegalStateException}. If any of the actions supplied are not
      * available for the slice set on this view (i.e. the action is not returned by
-     * {@link SliceUtils#getSliceActions(Slice)} this will throw {@link IllegalArgumentException}.
+     * {@link SliceMetadata#getSliceActions()} this will throw {@link IllegalArgumentException}.
      */
     public void setSliceActions(@Nullable List<SliceItem> newActions) {
         // Check that these actions are part of available set
         if (mCurrentSlice == null) {
             throw new IllegalStateException("Trying to set actions on a view without a slice");
         }
-        List<SliceItem> availableActions = SliceUtils.getSliceActions(mCurrentSlice);
+        List<SliceItem> availableActions = SliceMetadata.getSliceActions(mCurrentSlice);
         if (availableActions != null && newActions != null) {
             for (int i = 0; i < newActions.size(); i++) {
                 if (!availableActions.contains(newActions.get(i))) {
@@ -347,6 +348,18 @@
     }
 
     /**
+     * Sets whether this view should display when the slice was last updated.
+     *
+     * @param showLastUpdated whether the view should display when the slice was last updated.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    public void setShowLastUpdated(boolean showLastUpdated) {
+        mShowLastUpdated = showLastUpdated;
+        mCurrentView.setShowLastUpdated(showLastUpdated);
+    }
+
+    /**
      * @hide
      */
     @RestrictTo(RestrictTo.Scope.LIBRARY)
@@ -435,6 +448,16 @@
         mCurrentView.setStyle(mAttrs);
         mCurrentView.setTint(getTintColor());
         mCurrentView.setVisibility(lc.isValid() ? View.VISIBLE : View.GONE);
+
+        // Check if the slice content is expired and show when it was last updated
+        SliceMetadata sliceMetadata = SliceMetadata.from(getContext(), mCurrentSlice);
+        long lastUpdated = sliceMetadata.getLastUpdatedTime();
+        long expiry = sliceMetadata.getExpiry();
+        long now = System.currentTimeMillis();
+        mCurrentView.setLastUpdated(lastUpdated);
+        boolean expired = expiry != SliceHints.INFINITY && now > expiry;
+        mCurrentView.setShowLastUpdated(mShowLastUpdated && expired);
+
         // Set the slice
         mCurrentView.setSlice(mCurrentSlice);
         updateActions();
diff --git a/slices/view/src/main/java/androidx/slice/widget/SliceViewUtil.java b/slices/view/src/main/java/androidx/slice/widget/SliceViewUtil.java
index 0c76fcf..c8e3d74 100644
--- a/slices/view/src/main/java/androidx/slice/widget/SliceViewUtil.java
+++ b/slices/view/src/main/java/androidx/slice/widget/SliceViewUtil.java
@@ -29,18 +29,19 @@
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.Icon;
+import android.text.format.DateUtils;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
 import androidx.annotation.AttrRes;
 import androidx.annotation.ColorInt;
 import androidx.annotation.NonNull;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.content.ContextCompat;
-import android.text.format.DateUtils;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
+import androidx.core.graphics.drawable.IconCompat;
 
 import java.util.Calendar;
 
@@ -139,25 +140,24 @@
     /**
      */
     @RequiresApi(23)
-    public static Icon createIconFromDrawable(Drawable d) {
+    public static IconCompat createIconFromDrawable(Drawable d) {
         if (d instanceof BitmapDrawable) {
-            return Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
+            return IconCompat.createWithBitmap(((BitmapDrawable) d).getBitmap());
         }
         Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
                 Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(b);
         d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
         d.draw(canvas);
-        return Icon.createWithBitmap(b);
+        return IconCompat.createWithBitmap(b);
     }
 
     /**
      */
-    @RequiresApi(23)
     public static void createCircledIcon(@NonNull Context context, int iconSizePx,
-            Icon icon, boolean isLarge, ViewGroup parent) {
+            IconCompat icon, boolean isLarge, ViewGroup parent) {
         ImageView v = new ImageView(context);
-        v.setImageIcon(icon);
+        v.setImageDrawable(icon.loadDrawable(context));
         v.setScaleType(isLarge ? ImageView.ScaleType.CENTER_CROP
                 : ImageView.ScaleType.CENTER_INSIDE);
         parent.addView(v);
diff --git a/slices/view/src/main/res/layout/abc_slice_small_template.xml b/slices/view/src/main/res/layout/abc_slice_small_template.xml
index 4a47c06..1327066 100644
--- a/slices/view/src/main/res/layout/abc_slice_small_template.xml
+++ b/slices/view/src/main/res/layout/abc_slice_small_template.xml
@@ -45,11 +45,27 @@
             android:layout_height="wrap_content"
             android:maxLines="1"/>
 
-        <TextView android:id="@android:id/summary"
+        <LinearLayout
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_alignStart="@android:id/title"
-            android:maxLines="1" />
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@android:id/summary"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:ellipsize="end"
+                android:maxLines="1" />
+
+            <TextView
+                android:id="@+id/last_updated"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:ellipsize="end"
+                android:maxLines="1" />
+
+        </LinearLayout>
 
         <SeekBar
             android:id="@+id/seek_bar"
diff --git a/slices/view/src/main/res/values-af/strings.xml b/slices/view/src/main/res/values-af/strings.xml
index 322c8cf..812f811 100644
--- a/slices/view/src/main/res/values-af/strings.xml
+++ b/slices/view/src/main/res/values-af/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Wys meer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-az/strings.xml b/slices/view/src/main/res/values-az/strings.xml
index 7b0d59c..8ff3908 100644
--- a/slices/view/src/main/res/values-az/strings.xml
+++ b/slices/view/src/main/res/values-az/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Digər"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Digərinə baxın"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-be/strings.xml b/slices/view/src/main/res/values-be/strings.xml
index ae73c85..6ea856b 100644
--- a/slices/view/src/main/res/values-be/strings.xml
+++ b/slices/view/src/main/res/values-be/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Яшчэ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Яшчэ"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Яшчэ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bg/strings.xml b/slices/view/src/main/res/values-bg/strings.xml
index c8efb9a..882def9 100644
--- a/slices/view/src/main/res/values-bg/strings.xml
+++ b/slices/view/src/main/res/values-bg/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Още"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Показване на още"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bn/strings.xml b/slices/view/src/main/res/values-bn/strings.xml
index 0711d78..eb83395 100644
--- a/slices/view/src/main/res/values-bn/strings.xml
+++ b/slices/view/src/main/res/values-bn/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>টি"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"আরও"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"আরও দেখুন"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-bs/strings.xml b/slices/view/src/main/res/values-bs/strings.xml
index 1b97ec1..693f885 100644
--- a/slices/view/src/main/res/values-bs/strings.xml
+++ b/slices/view/src/main/res/values-bs/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Više"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ca/strings.xml b/slices/view/src/main/res/values-ca/strings.xml
index 9c9b13c..4ac9c6d 100644
--- a/slices/view/src/main/res/values-ca/strings.xml
+++ b/slices/view/src/main/res/values-ca/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> més"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Més"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra\'n més"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-da/strings.xml b/slices/view/src/main/res/values-da/strings.xml
index c41bd9a..806a5fe 100644
--- a/slices/view/src/main/res/values-da/strings.xml
+++ b/slices/view/src/main/res/values-da/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> mere"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mere"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Se mere"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-de/strings.xml b/slices/view/src/main/res/values-de/strings.xml
index c60b528..f6a1e32 100644
--- a/slices/view/src/main/res/values-de/strings.xml
+++ b/slices/view/src/main/res/values-de/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mehr"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mehr anzeigen"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-el/strings.xml b/slices/view/src/main/res/values-el/strings.xml
index f8cb37c..19963f2 100644
--- a/slices/view/src/main/res/values-el/strings.xml
+++ b/slices/view/src/main/res/values-el/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Περισσότ."</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Εμφάνιση περισσότερων"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rAU/strings.xml b/slices/view/src/main/res/values-en-rAU/strings.xml
index 4767f88..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rAU/strings.xml
+++ b/slices/view/src/main/res/values-en-rAU/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rCA/strings.xml b/slices/view/src/main/res/values-en-rCA/strings.xml
index 4767f88..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rCA/strings.xml
+++ b/slices/view/src/main/res/values-en-rCA/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rGB/strings.xml b/slices/view/src/main/res/values-en-rGB/strings.xml
index 4767f88..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rGB/strings.xml
+++ b/slices/view/src/main/res/values-en-rGB/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rIN/strings.xml b/slices/view/src/main/res/values-en-rIN/strings.xml
index 4767f88..f222ba5 100644
--- a/slices/view/src/main/res/values-en-rIN/strings.xml
+++ b/slices/view/src/main/res/values-en-rIN/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"More"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Show more"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-en-rXC/strings.xml b/slices/view/src/main/res/values-en-rXC/strings.xml
index 2bd9d5e..243dccb 100644
--- a/slices/view/src/main/res/values-en-rXC/strings.xml
+++ b/slices/view/src/main/res/values-en-rXC/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‎‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‏‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎+ ‎‏‎‎‏‏‎<xliff:g id="NUMBER">%1$d</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‏‎More‎‏‎‎‏‎"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎Show more‎‏‎‎‏‎"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-es-rUS/strings.xml b/slices/view/src/main/res/values-es-rUS/strings.xml
index 1fda757..7fc5b56 100644
--- a/slices/view/src/main/res/values-es-rUS/strings.xml
+++ b/slices/view/src/main/res/values-es-rUS/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar más"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-es/strings.xml b/slices/view/src/main/res/values-es/strings.xml
index 1920ed5..b81e23c 100644
--- a/slices/view/src/main/res/values-es/strings.xml
+++ b/slices/view/src/main/res/values-es/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> más"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Más"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Ver más"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-et/strings.xml b/slices/view/src/main/res/values-et/strings.xml
index c34dee7..80bec54 100644
--- a/slices/view/src/main/res/values-et/strings.xml
+++ b/slices/view/src/main/res/values-et/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"ja veel <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Rohkem"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Kuva rohkem"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-eu/strings.xml b/slices/view/src/main/res/values-eu/strings.xml
index ff82ef6..295f184 100644
--- a/slices/view/src/main/res/values-eu/strings.xml
+++ b/slices/view/src/main/res/values-eu/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Beste <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Gehiago"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Erakutsi gehiago"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-fi/strings.xml b/slices/view/src/main/res/values-fi/strings.xml
index 863c2f5..0e37b9d 100644
--- a/slices/view/src/main/res/values-fi/strings.xml
+++ b/slices/view/src/main/res/values-fi/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Lisää"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Näytä lisää"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-fr/strings.xml b/slices/view/src/main/res/values-fr/strings.xml
index 9d64bc2..b4f147b 100644
--- a/slices/view/src/main/res/values-fr/strings.xml
+++ b/slices/view/src/main/res/values-fr/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> autres"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Plus"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Afficher plus"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-gl/strings.xml b/slices/view/src/main/res/values-gl/strings.xml
index 2893e44..f8686de 100644
--- a/slices/view/src/main/res/values-gl/strings.xml
+++ b/slices/view/src/main/res/values-gl/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> máis"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Máis"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Amosar máis"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-gu/strings.xml b/slices/view/src/main/res/values-gu/strings.xml
index 044a117..4cf8b47 100644
--- a/slices/view/src/main/res/values-gu/strings.xml
+++ b/slices/view/src/main/res/values-gu/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"વધુ"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"વધુ બતાવો"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hi/strings.xml b/slices/view/src/main/res/values-hi/strings.xml
index 3f0db62..3688497 100644
--- a/slices/view/src/main/res/values-hi/strings.xml
+++ b/slices/view/src/main/res/values-hi/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"ज़्यादा देखें"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"ज़्यादा देखें"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hr/strings.xml b/slices/view/src/main/res/values-hr/strings.xml
index 1857f12..5ec52b8 100644
--- a/slices/view/src/main/res/values-hr/strings.xml
+++ b/slices/view/src/main/res/values-hr/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"još <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Više"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Prikaži više"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-hu/strings.xml b/slices/view/src/main/res/values-hu/strings.xml
index b655dbe..957dd68 100644
--- a/slices/view/src/main/res/values-hu/strings.xml
+++ b/slices/view/src/main/res/values-hu/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Több"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Több megjelenítése"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-in/strings.xml b/slices/view/src/main/res/values-in/strings.xml
index 17da9ee..7d46931 100644
--- a/slices/view/src/main/res/values-in/strings.xml
+++ b/slices/view/src/main/res/values-in/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Lainnya"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Tampilkan lainnya"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-it/strings.xml b/slices/view/src/main/res/values-it/strings.xml
index f64fef2..8f0a761 100644
--- a/slices/view/src/main/res/values-it/strings.xml
+++ b/slices/view/src/main/res/values-it/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Altro"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostra altro"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ja/strings.xml b/slices/view/src/main/res/values-ja/strings.xml
index a0ed985..a18751f 100644
--- a/slices/view/src/main/res/values-ja/strings.xml
+++ b/slices/view/src/main/res/values-ja/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"他 <xliff:g id="NUMBER">%1$d</xliff:g> 件"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"もっと見る"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"もっと見る"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ka/strings.xml b/slices/view/src/main/res/values-ka/strings.xml
index 1da1a4e..8701f5d 100644
--- a/slices/view/src/main/res/values-ka/strings.xml
+++ b/slices/view/src/main/res/values-ka/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"მეტი"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"მეტის ჩვენება"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-kk/strings.xml b/slices/view/src/main/res/values-kk/strings.xml
index f95841f..1867ada 100644
--- a/slices/view/src/main/res/values-kk/strings.xml
+++ b/slices/view/src/main/res/values-kk/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Тағы"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Толығырақ көрсету"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-km/strings.xml b/slices/view/src/main/res/values-km/strings.xml
index 2d93b60..3f50a99 100644
--- a/slices/view/src/main/res/values-km/strings.xml
+++ b/slices/view/src/main/res/values-km/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"ច្រើន​ទៀត"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"បង្ហាញ​ច្រើនទៀត"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-kn/strings.xml b/slices/view/src/main/res/values-kn/strings.xml
index fea51c8..e8224f3 100644
--- a/slices/view/src/main/res/values-kn/strings.xml
+++ b/slices/view/src/main/res/values-kn/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"ಇನ್ನಷ್ಟು"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"ಹೆಚ್ಚು ತೋರಿಸಿ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ko/strings.xml b/slices/view/src/main/res/values-ko/strings.xml
index d11f21e..8e7cb24 100644
--- a/slices/view/src/main/res/values-ko/strings.xml
+++ b/slices/view/src/main/res/values-ko/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g>개 더보기"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"더보기"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"더보기"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ky/strings.xml b/slices/view/src/main/res/values-ky/strings.xml
index 8349057..910ae6d 100644
--- a/slices/view/src/main/res/values-ky/strings.xml
+++ b/slices/view/src/main/res/values-ky/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Дагы"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Дагы көрсөтүү"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-lo/strings.xml b/slices/view/src/main/res/values-lo/strings.xml
index b0185ce..d266a43 100644
--- a/slices/view/src/main/res/values-lo/strings.xml
+++ b/slices/view/src/main/res/values-lo/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"ເພີ່ມເຕີມ"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"ສະແດງເພີ່ມເຕີມ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-mk/strings.xml b/slices/view/src/main/res/values-mk/strings.xml
index 5a243a4..b3c5da4 100644
--- a/slices/view/src/main/res/values-mk/strings.xml
+++ b/slices/view/src/main/res/values-mk/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Повеќе"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Прикажи повеќе"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ml/strings.xml b/slices/view/src/main/res/values-ml/strings.xml
index 3f77875..e2dc0b1 100644
--- a/slices/view/src/main/res/values-ml/strings.xml
+++ b/slices/view/src/main/res/values-ml/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"കൂടുതൽ"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"കൂടുതൽ കാണിക്കുക"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-mn/strings.xml b/slices/view/src/main/res/values-mn/strings.xml
index bec9ac5..740f455 100644
--- a/slices/view/src/main/res/values-mn/strings.xml
+++ b/slices/view/src/main/res/values-mn/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Бусад"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Дэлгэрэнгүй үзэх"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-mr/strings.xml b/slices/view/src/main/res/values-mr/strings.xml
index 03b0bed..ab06bea 100644
--- a/slices/view/src/main/res/values-mr/strings.xml
+++ b/slices/view/src/main/res/values-mr/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"आणखी"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"आणखी दाखवा"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ms/strings.xml b/slices/view/src/main/res/values-ms/strings.xml
index 6e276b6..03bda10 100644
--- a/slices/view/src/main/res/values-ms/strings.xml
+++ b/slices/view/src/main/res/values-ms/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Lagi"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Tunjukkan lagi"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-my/strings.xml b/slices/view/src/main/res/values-my/strings.xml
index 4c39980..754d40e 100644
--- a/slices/view/src/main/res/values-my/strings.xml
+++ b/slices/view/src/main/res/values-my/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"နောက်ထပ်"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"နောက်ထပ် ပြပါ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-nb/strings.xml b/slices/view/src/main/res/values-nb/strings.xml
index 8713242..e977965 100644
--- a/slices/view/src/main/res/values-nb/strings.xml
+++ b/slices/view/src/main/res/values-nb/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Vis mer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ne/strings.xml b/slices/view/src/main/res/values-ne/strings.xml
index 9d3d0c8..6a95860 100644
--- a/slices/view/src/main/res/values-ne/strings.xml
+++ b/slices/view/src/main/res/values-ne/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"थप"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"थप देखाउनुहोस्"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-nl/strings.xml b/slices/view/src/main/res/values-nl/strings.xml
index 3798fcb..ed28ef2 100644
--- a/slices/view/src/main/res/values-nl/strings.xml
+++ b/slices/view/src/main/res/values-nl/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Meer"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Meer weergeven"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pa/strings.xml b/slices/view/src/main/res/values-pa/strings.xml
index 5c78776..cd6db9b 100644
--- a/slices/view/src/main/res/values-pa/strings.xml
+++ b/slices/view/src/main/res/values-pa/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"ਹੋਰ"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"ਹੋਰ ਦਿਖਾਓ"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pl/strings.xml b/slices/view/src/main/res/values-pl/strings.xml
index 9a61601..5fe2d2b 100644
--- a/slices/view/src/main/res/values-pl/strings.xml
+++ b/slices/view/src/main/res/values-pl/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Więcej"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Pokaż więcej"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt-rBR/strings.xml b/slices/view/src/main/res/values-pt-rBR/strings.xml
index d3373a5..a163c4a 100644
--- a/slices/view/src/main/res/values-pt-rBR/strings.xml
+++ b/slices/view/src/main/res/values-pt-rBR/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt-rPT/strings.xml b/slices/view/src/main/res/values-pt-rPT/strings.xml
index a61795f..7d4c127 100644
--- a/slices/view/src/main/res/values-pt-rPT/strings.xml
+++ b/slices/view/src/main/res/values-pt-rPT/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-pt/strings.xml b/slices/view/src/main/res/values-pt/strings.xml
index d3373a5..a163c4a 100644
--- a/slices/view/src/main/res/values-pt/strings.xml
+++ b/slices/view/src/main/res/values-pt/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"Mais <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mais"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Mostrar mais"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ro/strings.xml b/slices/view/src/main/res/values-ro/strings.xml
index 6070e17..ed61fde 100644
--- a/slices/view/src/main/res/values-ro/strings.xml
+++ b/slices/view/src/main/res/values-ro/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mai mult"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Vedeți mai multe"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-si/strings.xml b/slices/view/src/main/res/values-si/strings.xml
index 4d5ab4a..58feb78 100644
--- a/slices/view/src/main/res/values-si/strings.xml
+++ b/slices/view/src/main/res/values-si/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"තව"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"තව පෙන්වන්න"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sk/strings.xml b/slices/view/src/main/res/values-sk/strings.xml
index c27c533..fe77506 100644
--- a/slices/view/src/main/res/values-sk/strings.xml
+++ b/slices/view/src/main/res/values-sk/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Viac"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Zobraziť viac"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sl/strings.xml b/slices/view/src/main/res/values-sl/strings.xml
index 3dc60a8..802caf1 100644
--- a/slices/view/src/main/res/values-sl/strings.xml
+++ b/slices/view/src/main/res/values-sl/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"in še <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Več"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Pokaži več"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sq/strings.xml b/slices/view/src/main/res/values-sq/strings.xml
index 9b1ba91..e1cdae8 100644
--- a/slices/view/src/main/res/values-sq/strings.xml
+++ b/slices/view/src/main/res/values-sq/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Më shumë"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Shfaq më shumë"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sv/strings.xml b/slices/view/src/main/res/values-sv/strings.xml
index d41940f..f8ed0c7 100644
--- a/slices/view/src/main/res/values-sv/strings.xml
+++ b/slices/view/src/main/res/values-sv/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"<xliff:g id="NUMBER">%1$d</xliff:g> till"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mer"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Visa mer"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-sw/strings.xml b/slices/view/src/main/res/values-sw/strings.xml
index c512c09..b23ed5e 100644
--- a/slices/view/src/main/res/values-sw/strings.xml
+++ b/slices/view/src/main/res/values-sw/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Mengine"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Onyesha mengine"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ta/strings.xml b/slices/view/src/main/res/values-ta/strings.xml
index c127c27..9f2be0e 100644
--- a/slices/view/src/main/res/values-ta/strings.xml
+++ b/slices/view/src/main/res/values-ta/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"மேலும்"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"மேலும் காட்டு"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-te/strings.xml b/slices/view/src/main/res/values-te/strings.xml
index 80d2432..0eb1da7 100644
--- a/slices/view/src/main/res/values-te/strings.xml
+++ b/slices/view/src/main/res/values-te/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"మరింత"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"మరింత చూపు"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-th/strings.xml b/slices/view/src/main/res/values-th/strings.xml
index 03c5a95..4cdd991 100644
--- a/slices/view/src/main/res/values-th/strings.xml
+++ b/slices/view/src/main/res/values-th/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"เพิ่มเติม"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"แสดงเพิ่ม"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-tr/strings.xml b/slices/view/src/main/res/values-tr/strings.xml
index 93eca82..09a589e 100644
--- a/slices/view/src/main/res/values-tr/strings.xml
+++ b/slices/view/src/main/res/values-tr/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Diğer"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Daha fazla göster"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-uk/strings.xml b/slices/view/src/main/res/values-uk/strings.xml
index c5ab87c..06c02bc 100644
--- a/slices/view/src/main/res/values-uk/strings.xml
+++ b/slices/view/src/main/res/values-uk/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Більше"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Показати більше"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-ur/strings.xml b/slices/view/src/main/res/values-ur/strings.xml
index 7b24d79..f12d6b3 100644
--- a/slices/view/src/main/res/values-ur/strings.xml
+++ b/slices/view/src/main/res/values-ur/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"‎‎‎‎‎+ <xliff:g id="NUMBER">%1$d</xliff:g>‎‎"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"مزید"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"مزید دکھائیں"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-uz/strings.xml b/slices/view/src/main/res/values-uz/strings.xml
index c600886..cbc9979 100644
--- a/slices/view/src/main/res/values-uz/strings.xml
+++ b/slices/view/src/main/res/values-uz/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Yana"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Yana"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-vi/strings.xml b/slices/view/src/main/res/values-vi/strings.xml
index 451b080..3890636 100644
--- a/slices/view/src/main/res/values-vi/strings.xml
+++ b/slices/view/src/main/res/values-vi/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Thêm"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Hiển thị thêm"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zh-rHK/strings.xml b/slices/view/src/main/res/values-zh-rHK/strings.xml
index b21b9b9..565b565 100644
--- a/slices/view/src/main/res/values-zh-rHK/strings.xml
+++ b/slices/view/src/main/res/values-zh-rHK/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"顯示更多"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zh-rTW/strings.xml b/slices/view/src/main/res/values-zh-rTW/strings.xml
index b21b9b9..565b565 100644
--- a/slices/view/src/main/res/values-zh-rTW/strings.xml
+++ b/slices/view/src/main/res/values-zh-rTW/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"更多"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"顯示更多"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values-zu/strings.xml b/slices/view/src/main/res/values-zu/strings.xml
index 03e6fd1..c5ebb10 100644
--- a/slices/view/src/main/res/values-zu/strings.xml
+++ b/slices/view/src/main/res/values-zu/strings.xml
@@ -20,4 +20,8 @@
     <string name="abc_slice_more_content" msgid="6405516388971241142">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
     <string name="abc_slice_more" msgid="1983560225998630901">"Okuningi"</string>
     <string name="abc_slice_show_more" msgid="1567717014004692768">"Bonisa okuningi"</string>
+    <!-- no translation found for abc_slice_updated (8155085405396453848) -->
+    <skip />
+    <!-- no translation found for abc_slice_error (4188371422904147368) -->
+    <skip />
 </resources>
diff --git a/slices/view/src/main/res/values/strings.xml b/slices/view/src/main/res/values/strings.xml
index 8bdfa85..b959f86 100644
--- a/slices/view/src/main/res/values/strings.xml
+++ b/slices/view/src/main/res/values/strings.xml
@@ -16,10 +16,37 @@
   -->
 
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <!-- Format string indicating the number of extra items that aren't being displayed. [CHAR LIMIT=none] -->
+    <!-- Format string indicating the number of extra items that aren't being displayed.
+         [CHAR LIMIT=none] -->
     <string name="abc_slice_more_content">+ <xliff:g id="number" example="5">%1$d</xliff:g></string>
     <!-- Text indicating there is more content available that is not displayed. [CHAR LIMIT=10] -->
     <string name="abc_slice_more">More</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>
+
+    <!-- Format string indicating how old the content in the template is. [CHAR LIMIT=150]-->
+    <string name="abc_slice_updated">Updated <xliff:g id="time" example="5 min ago">%1$s</xliff:g></string>
+
+    <!-- Text describing a time in the past in minutes, ideally this string should use an
+         abbreviated format of the word "minute", if available. [CHAR LIMIT=15]-->
+    <plurals name="abc_slice_duration_min">
+        <item quantity="one"><xliff:g example="1">%d</xliff:g> min ago</item>
+        <item quantity="other"><xliff:g example="2">%d</xliff:g> min ago</item>
+    </plurals>
+    <!-- Text describing a time in the past in years, ideally this string should use an
+         abbreviated format of the word "year", if available. [CHAR LIMIT=15]-->
+    <plurals name="abc_slice_duration_years">
+        <item quantity="one"><xliff:g example="1">%d</xliff:g> yr ago</item>
+        <item quantity="other"><xliff:g example="2">%d</xliff:g> yr ago</item>
+    </plurals>
+    <!-- Text describing a time in the past in days, ideally this string should use an
+         abbreviated format of the word "day", if available. [CHAR LIMIT=15]-->
+    <plurals name="abc_slice_duration_days">
+        <item quantity="one"><xliff:g example="1">%d</xliff:g> day ago</item>
+        <item quantity="other"><xliff:g example="2">%d</xliff:g> days ago</item>
+    </plurals>
+
+    <!-- Text indicating that there was a failure connecting to the app providing the slice
+         [CHAR LIMIT=none]-->
+    <string name="abc_slice_error">Couldn\'t connect</string>
 </resources>
\ No newline at end of file
diff --git a/transition/src/main/java/androidx/transition/RectEvaluator.java b/transition/src/main/java/androidx/transition/RectEvaluator.java
index 26527b5..6dab422 100644
--- a/transition/src/main/java/androidx/transition/RectEvaluator.java
+++ b/transition/src/main/java/androidx/transition/RectEvaluator.java
@@ -19,12 +19,9 @@
 import android.animation.TypeEvaluator;
 import android.graphics.Rect;
 
-import androidx.annotation.RequiresApi;
-
 /**
  * This evaluator can be used to perform type interpolation between <code>Rect</code> values.
  */
-@RequiresApi(14)
 class RectEvaluator implements TypeEvaluator<Rect> {
 
     /**
diff --git a/transition/src/main/java/androidx/transition/TransitionValuesMaps.java b/transition/src/main/java/androidx/transition/TransitionValuesMaps.java
index 2f57769..4db4603 100644
--- a/transition/src/main/java/androidx/transition/TransitionValuesMaps.java
+++ b/transition/src/main/java/androidx/transition/TransitionValuesMaps.java
@@ -19,11 +19,9 @@
 import android.util.SparseArray;
 import android.view.View;
 
-import androidx.annotation.RequiresApi;
 import androidx.collection.ArrayMap;
 import androidx.collection.LongSparseArray;
 
-@RequiresApi(14)
 class TransitionValuesMaps {
 
     final ArrayMap<View, TransitionValues> mViewValues = new ArrayMap<>();
diff --git a/transition/src/main/java/androidx/transition/ViewGroupOverlayApi14.java b/transition/src/main/java/androidx/transition/ViewGroupOverlayApi14.java
index eda6c5a..f1bd80a 100644
--- a/transition/src/main/java/androidx/transition/ViewGroupOverlayApi14.java
+++ b/transition/src/main/java/androidx/transition/ViewGroupOverlayApi14.java
@@ -21,9 +21,7 @@
 import android.view.ViewGroup;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 
-@RequiresApi(14)
 class ViewGroupOverlayApi14 extends ViewOverlayApi14 implements ViewGroupOverlayImpl {
 
     ViewGroupOverlayApi14(Context context, ViewGroup hostView, View requestingView) {
diff --git a/transition/src/main/java/androidx/transition/ViewGroupOverlayImpl.java b/transition/src/main/java/androidx/transition/ViewGroupOverlayImpl.java
index 3264a13..be009e3 100644
--- a/transition/src/main/java/androidx/transition/ViewGroupOverlayImpl.java
+++ b/transition/src/main/java/androidx/transition/ViewGroupOverlayImpl.java
@@ -19,9 +19,7 @@
 import android.view.View;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 
-@RequiresApi(14)
 interface ViewGroupOverlayImpl extends ViewOverlayImpl {
 
     /**
diff --git a/transition/src/main/java/androidx/transition/ViewOverlayApi14.java b/transition/src/main/java/androidx/transition/ViewOverlayApi14.java
index 0a92736..12ebf77 100644
--- a/transition/src/main/java/androidx/transition/ViewOverlayApi14.java
+++ b/transition/src/main/java/androidx/transition/ViewOverlayApi14.java
@@ -28,7 +28,6 @@
 import android.view.ViewParent;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.view.ViewCompat;
 
@@ -36,7 +35,6 @@
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 
-@RequiresApi(14)
 class ViewOverlayApi14 implements ViewOverlayImpl {
 
     /**
diff --git a/transition/src/main/java/androidx/transition/ViewOverlayImpl.java b/transition/src/main/java/androidx/transition/ViewOverlayImpl.java
index 68989bf..355bd06 100644
--- a/transition/src/main/java/androidx/transition/ViewOverlayImpl.java
+++ b/transition/src/main/java/androidx/transition/ViewOverlayImpl.java
@@ -19,9 +19,7 @@
 import android.graphics.drawable.Drawable;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 
-@RequiresApi(14)
 interface ViewOverlayImpl {
 
     /**
diff --git a/transition/src/main/java/androidx/transition/WindowIdApi14.java b/transition/src/main/java/androidx/transition/WindowIdApi14.java
index d36d7c2..6a9231e 100644
--- a/transition/src/main/java/androidx/transition/WindowIdApi14.java
+++ b/transition/src/main/java/androidx/transition/WindowIdApi14.java
@@ -18,9 +18,6 @@
 
 import android.os.IBinder;
 
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(14)
 class WindowIdApi14 implements WindowIdImpl {
 
     private final IBinder mToken;
diff --git a/transition/src/main/java/androidx/transition/WindowIdImpl.java b/transition/src/main/java/androidx/transition/WindowIdImpl.java
index 372694a..ca57588 100644
--- a/transition/src/main/java/androidx/transition/WindowIdImpl.java
+++ b/transition/src/main/java/androidx/transition/WindowIdImpl.java
@@ -16,8 +16,5 @@
 
 package androidx.transition;
 
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(14)
 interface WindowIdImpl {
 }
diff --git a/v7/appcompat/src/androidTest/AndroidManifest.xml b/v7/appcompat/src/androidTest/AndroidManifest.xml
index 008e19a..945ebeb 100644
--- a/v7/appcompat/src/androidTest/AndroidManifest.xml
+++ b/v7/appcompat/src/androidTest/AndroidManifest.xml
@@ -42,6 +42,11 @@
             android:theme="@style/Theme.SampleDrawerLayout"/>
 
         <activity
+            android:name="androidx.appcompat.app.DrawerInteractionActivity"
+            android:label="@string/drawer_layout_activity"
+            android:theme="@style/Theme.SampleDrawerLayout"/>
+
+        <activity
             android:name="androidx.appcompat.app.DrawerLayoutDoubleActivity"
             android:label="@string/drawer_layout_activity"
             android:theme="@style/Theme.SampleDrawerLayout"/>
diff --git a/loader/src/androidTest/java/androidx/loader/app/test/EmptyActivity.java b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionActivity.java
similarity index 71%
rename from loader/src/androidTest/java/androidx/loader/app/test/EmptyActivity.java
rename to v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionActivity.java
index 1b55e3b..ae7154a 100644
--- a/loader/src/androidTest/java/androidx/loader/app/test/EmptyActivity.java
+++ b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionActivity.java
@@ -14,9 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.loader.app.test;
+package androidx.appcompat.app;
 
-import androidx.core.app.SupportActivity;
+import androidx.appcompat.testutils.BaseTestActivity;
 
-public class EmptyActivity extends SupportActivity {
+public class DrawerInteractionActivity extends BaseTestActivity {
+    @Override
+    protected int getContentViewLayoutResId() {
+        return 0;
+    }
 }
diff --git a/v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionTest.java b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionTest.java
new file mode 100755
index 0000000..1c3f6c0
--- /dev/null
+++ b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/DrawerInteractionTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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.appcompat.app;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+
+import static androidx.appcompat.testutils.DrawerLayoutActions.openDrawer;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.app.Activity;
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.Gravity;
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.core.view.GravityCompat;
+import androidx.drawerlayout.widget.DrawerLayout;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+@RunWith(AndroidJUnit4.class)
+public class DrawerInteractionTest {
+
+    @Rule
+    public final ActivityTestRule<DrawerInteractionActivity> mActivityTestRule =
+            new ActivityTestRule<>(DrawerInteractionActivity.class);
+
+    private TestDrawerLayout mDrawerLayout;
+    private View mStartDrawer;
+    private View mContentView;
+
+    @Before
+    public void setUp() throws Throwable {
+        final Activity activity = mActivityTestRule.getActivity();
+
+        Context context = InstrumentationRegistry.getContext();
+        mDrawerLayout = new TestDrawerLayout(InstrumentationRegistry.getContext());
+        mContentView = Mockito.spy(new View(context));
+        mStartDrawer = Mockito.spy(new View(context));
+
+        mDrawerLayout.setLayoutParams(new ViewGroup.LayoutParams(100, 100));
+        DrawerLayout.LayoutParams contentViewLayoutParams = new DrawerLayout.LayoutParams(100, 100);
+        DrawerLayout.LayoutParams drawerViewLayoutParams = new DrawerLayout.LayoutParams(50, 100);
+
+        contentViewLayoutParams.gravity = Gravity.NO_GRAVITY;
+        drawerViewLayoutParams.gravity = Gravity.START;
+
+        mContentView.setLayoutParams(contentViewLayoutParams);
+        mStartDrawer.setLayoutParams(drawerViewLayoutParams);
+        mStartDrawer.setBackgroundColor(0xFF00FF00);
+
+        mDrawerLayout.addView(mContentView);
+        mDrawerLayout.addView(mStartDrawer);
+        mDrawerLayout.setBackgroundColor(0xFFFF0000);
+
+        mDrawerLayout.expectLayouts(1);
+        mActivityTestRule.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.setContentView(mDrawerLayout);
+            }
+        });
+        assertThat(mDrawerLayout.waitForLayouts(2), is(true));
+    }
+
+    // Verification that DrawerLayout blocks certain pointer motion events from getting to the
+    // content view when the drawer is open.
+
+    @Test
+    @LargeTest
+    public void ui_pointerEvent_overDrawer_receivedByDrawer() throws Throwable {
+        onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
+                GravityCompat.START));
+        MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0);
+        motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
+
+        mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
+
+        verify(mStartDrawer).dispatchGenericMotionEvent(motionEvent);
+
+    }
+
+    @Test
+    @LargeTest
+    public void ui_pointerEvent_overDrawer_notReceivedByContent() throws Throwable {
+        onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
+                GravityCompat.START));
+        MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 25, 50, 0);
+        motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
+
+        mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
+
+        verify(mContentView, never()).dispatchGenericMotionEvent(any(MotionEvent.class));
+    }
+
+    @Test
+    @LargeTest
+    public void ui_pointerEvent_overContentDrawerOpen_notReceivedByContent() throws Throwable {
+        onView(isAssignableFrom(DrawerLayout.class)).perform(openDrawer(
+                GravityCompat.START));
+        MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0);
+        motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
+
+        mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
+
+        verify(mContentView, never()).dispatchGenericMotionEvent(any(MotionEvent.class));
+    }
+
+    @Test
+    @LargeTest
+    public void ui_pointerEvent_overContentDrawerClosed_receivedByContent() {
+        MotionEvent motionEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_SCROLL, 75, 50, 0);
+        motionEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
+
+        mDrawerLayout.dispatchGenericMotionEvent(motionEvent);
+
+        verify(mContentView).dispatchGenericMotionEvent(motionEvent);
+    }
+
+    private class TestDrawerLayout extends DrawerLayout {
+
+        CountDownLatch mLayoutCountDownLatch;
+
+        TestDrawerLayout(Context context) {
+            super(context);
+        }
+
+        public void expectLayouts(int count) {
+            mLayoutCountDownLatch = new CountDownLatch(count);
+        }
+
+        public boolean waitForLayouts(int seconds) throws InterruptedException {
+            boolean result = mLayoutCountDownLatch.await(seconds, TimeUnit.SECONDS);
+            mLayoutCountDownLatch = null;
+            return result;
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+            super.onLayout(changed, left, top, right, bottom);
+            if (mLayoutCountDownLatch != null) {
+                mLayoutCountDownLatch.countDown();
+            }
+        }
+
+    }
+
+
+}
diff --git a/v7/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
index 598df4d..5bae3ef 100644
--- a/v7/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
+++ b/v7/appcompat/src/androidTest/java/androidx/appcompat/app/LayoutInflaterFactoryTestCase.java
@@ -23,7 +23,6 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.support.test.annotation.UiThreadTest;
-import android.support.test.filters.SdkSuppress;
 import android.support.test.filters.SmallTest;
 import android.support.test.rule.ActivityTestRule;
 import android.support.test.runner.AndroidJUnit4;
@@ -34,7 +33,6 @@
 import android.view.ViewGroup;
 import android.widget.LinearLayout;
 
-import androidx.annotation.RequiresApi;
 import androidx.appcompat.custom.ContextWrapperFrameLayout;
 import androidx.appcompat.test.R;
 import androidx.appcompat.widget.AppCompatAutoCompleteTextView;
@@ -81,8 +79,6 @@
     }
 
     // Propagation of themed context to children only works on API 11+.
-    @SdkSuppress(minSdkVersion = 11)
-    @RequiresApi(11)
     @UiThreadTest
     @Test
     @SmallTest
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggle.java b/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggle.java
index d90b7bd..4941938 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggle.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggle.java
@@ -28,7 +28,6 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.StringRes;
 import androidx.appcompat.graphics.drawable.DrawerArrowDrawable;
 import androidx.appcompat.widget.Toolbar;
@@ -208,10 +207,8 @@
             });
         } else if (activity instanceof DelegateProvider) { // Allow the Activity to provide an impl
             mActivityImpl = ((DelegateProvider) activity).getDrawerToggleDelegate();
-        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
-            mActivityImpl = new JellybeanMr2Delegate(activity);
         } else {
-            mActivityImpl = new IcsDelegate(activity);
+            mActivityImpl = new FrameworkActionBarDelegate(activity);
         }
 
         mDrawerLayout = drawerLayout;
@@ -515,33 +512,34 @@
         mSlider.setProgress(position);
     }
 
-    /**
-     * Delegate if SDK version is between ICS and JBMR2
-     */
-    private static class IcsDelegate implements Delegate {
+    private static class FrameworkActionBarDelegate implements Delegate {
+        private final Activity mActivity;
+        private ActionBarDrawerToggleHoneycomb.SetIndicatorInfo mSetIndicatorInfo;
 
-        final Activity mActivity;
-        ActionBarDrawerToggleHoneycomb.SetIndicatorInfo mSetIndicatorInfo;
-
-        IcsDelegate(Activity activity) {
+        FrameworkActionBarDelegate(Activity activity) {
             mActivity = activity;
         }
 
         @Override
         public Drawable getThemeUpIndicator() {
+            if (Build.VERSION.SDK_INT >= 18) {
+                final TypedArray a = getActionBarThemedContext().obtainStyledAttributes(null,
+                        new int[] {android.R.attr.homeAsUpIndicator},
+                        android.R.attr.actionBarStyle, 0);
+                final Drawable result = a.getDrawable(0);
+                a.recycle();
+                return result;
+            }
             return ActionBarDrawerToggleHoneycomb.getThemeUpIndicator(mActivity);
         }
 
         @Override
         public Context getActionBarThemedContext() {
             final ActionBar actionBar = mActivity.getActionBar();
-            final Context context;
             if (actionBar != null) {
-                context = actionBar.getThemedContext();
-            } else {
-                context = mActivity;
+                return actionBar.getThemedContext();
             }
-            return context;
+            return mActivity;
         }
 
         @Override
@@ -555,74 +553,28 @@
         public void setActionBarUpIndicator(Drawable themeImage, int contentDescRes) {
             final ActionBar actionBar = mActivity.getActionBar();
             if (actionBar != null) {
-                actionBar.setDisplayShowHomeEnabled(true);
-                mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarUpIndicator(
+                if (Build.VERSION.SDK_INT >= 18) {
+                    actionBar.setHomeAsUpIndicator(themeImage);
+                    actionBar.setHomeActionContentDescription(contentDescRes);
+                } else {
+                    actionBar.setDisplayShowHomeEnabled(true);
+                    mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarUpIndicator(
                         mSetIndicatorInfo, mActivity, themeImage, contentDescRes);
-                actionBar.setDisplayShowHomeEnabled(false);
+                    actionBar.setDisplayShowHomeEnabled(false);
+                }
             }
         }
 
         @Override
         public void setActionBarDescription(int contentDescRes) {
-            mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarDescription(
-                    mSetIndicatorInfo, mActivity, contentDescRes);
-        }
-    }
-
-    /**
-     * Delegate if SDK version is JB MR2 or newer
-     */
-    @RequiresApi(18)
-    private static class JellybeanMr2Delegate implements Delegate {
-
-        final Activity mActivity;
-
-        JellybeanMr2Delegate(Activity activity) {
-            mActivity = activity;
-        }
-
-        @Override
-        public Drawable getThemeUpIndicator() {
-            final TypedArray a = getActionBarThemedContext().obtainStyledAttributes(null,
-                    new int[]{android.R.attr.homeAsUpIndicator}, android.R.attr.actionBarStyle, 0);
-            final Drawable result = a.getDrawable(0);
-            a.recycle();
-            return result;
-        }
-
-        @Override
-        public Context getActionBarThemedContext() {
-            final ActionBar actionBar = mActivity.getActionBar();
-            final Context context;
-            if (actionBar != null) {
-                context = actionBar.getThemedContext();
+            if (Build.VERSION.SDK_INT >= 18) {
+                final ActionBar actionBar = mActivity.getActionBar();
+                if (actionBar != null) {
+                    actionBar.setHomeActionContentDescription(contentDescRes);
+                }
             } else {
-                context = mActivity;
-            }
-            return context;
-        }
-
-        @Override
-        public boolean isNavigationVisible() {
-            final ActionBar actionBar = mActivity.getActionBar();
-            return actionBar != null &&
-                    (actionBar.getDisplayOptions() & ActionBar.DISPLAY_HOME_AS_UP) != 0;
-        }
-
-        @Override
-        public void setActionBarUpIndicator(Drawable drawable, int contentDescRes) {
-            final ActionBar actionBar = mActivity.getActionBar();
-            if (actionBar != null) {
-                actionBar.setHomeAsUpIndicator(drawable);
-                actionBar.setHomeActionContentDescription(contentDescRes);
-            }
-        }
-
-        @Override
-        public void setActionBarDescription(int contentDescRes) {
-            final ActionBar actionBar = mActivity.getActionBar();
-            if (actionBar != null) {
-                actionBar.setHomeActionContentDescription(contentDescRes);
+                mSetIndicatorInfo = ActionBarDrawerToggleHoneycomb.setActionBarDescription(
+                    mSetIndicatorInfo, mActivity, contentDescRes);
             }
         }
     }
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggleHoneycomb.java b/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggleHoneycomb.java
index 9d2c718..ac02d1b 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggleHoneycomb.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/app/ActionBarDrawerToggleHoneycomb.java
@@ -28,8 +28,6 @@
 import android.view.ViewGroup;
 import android.widget.ImageView;
 
-import androidx.annotation.RequiresApi;
-
 import java.lang.reflect.Method;
 
 /**
@@ -41,7 +39,6 @@
  *
  * Moved from Support-v4
  */
-@RequiresApi(11)
 class ActionBarDrawerToggleHoneycomb {
     private static final String TAG = "ActionBarDrawerToggleHC";
 
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemWrapperICS.java b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemWrapperICS.java
index 860ed18..d98acf3 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemWrapperICS.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuItemWrapperICS.java
@@ -30,7 +30,6 @@
 import android.view.View;
 import android.widget.FrameLayout;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appcompat.view.CollapsibleActionView;
 import androidx.core.internal.view.SupportMenuItem;
@@ -43,7 +42,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@RequiresApi(14)
 public class MenuItemWrapperICS extends BaseMenuWrapper<SupportMenuItem> implements MenuItem {
     static final String LOG_TAG = "MenuItemWrapper";
 
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuWrapperICS.java b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuWrapperICS.java
index 71252c9..b7e370e 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuWrapperICS.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/MenuWrapperICS.java
@@ -24,13 +24,11 @@
 import android.view.MenuItem;
 import android.view.SubMenu;
 
-import androidx.annotation.RequiresApi;
 import androidx.core.internal.view.SupportMenu;
 
 /**
  * Wraps a support {@link SupportMenu} as a framework {@link android.view.Menu}
  */
-@RequiresApi(14)
 class MenuWrapperICS extends BaseMenuWrapper<SupportMenu> implements Menu {
 
     MenuWrapperICS(Context context, SupportMenu object) {
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/SubMenuWrapperICS.java b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/SubMenuWrapperICS.java
index 5d57567..21d8a3d 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/view/menu/SubMenuWrapperICS.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/view/menu/SubMenuWrapperICS.java
@@ -24,7 +24,6 @@
 import android.view.SubMenu;
 import android.view.View;
 
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.internal.view.SupportSubMenu;
 
@@ -33,7 +32,6 @@
  * @hide
  */
 @RestrictTo(LIBRARY_GROUP)
-@RequiresApi(14)
 class SubMenuWrapperICS extends MenuWrapperICS implements SubMenu {
 
     SubMenuWrapperICS(Context context, SupportSubMenu subMenu) {
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawable.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawable.java
index 9e95d84..175cdb3 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawable.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawable.java
@@ -18,12 +18,12 @@
 
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.drawable.Drawable;
 
-import androidx.annotation.RequiresApi;
+import androidx.annotation.NonNull;
 
-@RequiresApi(9)
 class ActionBarBackgroundDrawable extends Drawable {
 
     final ActionBarContainer mContainer;
@@ -61,4 +61,17 @@
         return PixelFormat.UNKNOWN;
     }
 
+    @Override
+    public void getOutline(@NonNull Outline outline) {
+        if (mContainer.mIsSplit) {
+            if (mContainer.mSplitBackground != null) {
+                mContainer.mSplitBackground.getOutline(outline);
+            }
+        } else {
+            // ignore the stacked background for shadow casting
+            if (mContainer.mBackground != null) {
+                mContainer.mBackground.getOutline(outline);
+            }
+        }
+    }
 }
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawableV21.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawableV21.java
deleted file mode 100644
index 1438004..0000000
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarBackgroundDrawableV21.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2015 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.appcompat.widget;
-
-import android.graphics.Outline;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
-
-@RequiresApi(21)
-class ActionBarBackgroundDrawableV21 extends ActionBarBackgroundDrawable {
-
-    public ActionBarBackgroundDrawableV21(ActionBarContainer container) {
-        super(container);
-    }
-
-    @Override
-    public void getOutline(@NonNull Outline outline) {
-        if (mContainer.mIsSplit) {
-            if (mContainer.mSplitBackground != null) {
-                mContainer.mSplitBackground.getOutline(outline);
-            }
-        } else {
-            // ignore the stacked background for shadow casting
-            if (mContainer.mBackground != null) {
-                mContainer.mBackground.getOutline(outline);
-            }
-        }
-    }
-}
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarContainer.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarContainer.java
index d965ded..49e063f 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarContainer.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/ActionBarContainer.java
@@ -21,7 +21,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
-import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -59,9 +58,7 @@
         super(context, attrs);
 
         // Set a transparent background so that we project appropriately.
-        final Drawable bg = Build.VERSION.SDK_INT >= 21
-                ? new ActionBarBackgroundDrawableV21(this)
-                : new ActionBarBackgroundDrawable(this);
+        final Drawable bg = new ActionBarBackgroundDrawable(this);
         ViewCompat.setBackground(this, bg);
 
         TypedArray a = context.obtainStyledAttributes(attrs,
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatButton.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatButton.java
index ec29cdb..b4dee76 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatButton.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatButton.java
@@ -31,7 +31,6 @@
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appcompat.R;
 import androidx.core.view.TintableBackgroundView;
@@ -175,7 +174,6 @@
         event.setClassName(Button.class.getName());
     }
 
-    @RequiresApi(14)
     @Override
     public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
         super.onInitializeAccessibilityNodeInfo(info);
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
index 8fa121e..31d92e8 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatDrawableManager.java
@@ -43,7 +43,6 @@
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appcompat.R;
 import androidx.collection.ArrayMap;
@@ -781,7 +780,6 @@
         }
     }
 
-    @RequiresApi(11)
     private static class AvdcInflateDelegate implements InflateDelegate {
         AvdcInflateDelegate() {
         }
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBar.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBar.java
index fcbede9..bcf37b7 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBar.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBar.java
@@ -21,7 +21,6 @@
 import android.util.AttributeSet;
 import android.widget.SeekBar;
 
-import androidx.annotation.RequiresApi;
 import androidx.appcompat.R;
 
 /**
@@ -63,7 +62,6 @@
         mAppCompatSeekBarHelper.drawableStateChanged();
     }
 
-    @RequiresApi(11)
     @Override
     public void jumpDrawablesToCurrentState() {
         super.jumpDrawablesToCurrentState();
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBarHelper.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBarHelper.java
index f7560b7..9d1ffc3 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBarHelper.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatSeekBarHelper.java
@@ -24,7 +24,6 @@
 import android.widget.SeekBar;
 
 import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
 import androidx.appcompat.R;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.core.view.ViewCompat;
@@ -142,7 +141,6 @@
         }
     }
 
-    @RequiresApi(11)
     void jumpDrawablesToCurrentState() {
         if (mTickMark != null) {
             mTickMark.jumpToCurrentState();
diff --git a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
index 93f3512..bb3b5bb 100644
--- a/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
+++ b/v7/appcompat/src/main/java/androidx/appcompat/widget/AppCompatTextHelper.java
@@ -32,7 +32,6 @@
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.appcompat.R;
 import androidx.core.content.res.ResourcesCompat;
@@ -40,7 +39,6 @@
 
 import java.lang.ref.WeakReference;
 
-@RequiresApi(9)
 class AppCompatTextHelper {
 
     // Enum for the "typeface" XML parameter.
diff --git a/v7/recyclerview/src/main/java/androidx/recyclerview/widget/PositionMap.java b/v7/recyclerview/src/main/java/androidx/recyclerview/widget/PositionMap.java
deleted file mode 100644
index b5bf5a4..0000000
--- a/v7/recyclerview/src/main/java/androidx/recyclerview/widget/PositionMap.java
+++ /dev/null
@@ -1,464 +0,0 @@
-/*
- * 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.recyclerview.widget;
-
-import java.util.ArrayList;
-
-/**
- * Like a SparseArray, but with the ability to offset key ranges for bulk insertions/deletions.
- */
-class PositionMap<E> implements Cloneable {
-    private static final Object DELETED = new Object();
-    private boolean mGarbage = false;
-
-    private int[] mKeys;
-    private Object[] mValues;
-    private int mSize;
-
-    /**
-     * Creates a new SparseArray containing no mappings.
-     */
-    PositionMap() {
-        this(10);
-    }
-
-    /**
-     * Creates a new PositionMap containing no mappings that will not
-     * require any additional memory allocation to store the specified
-     * number of mappings.  If you supply an initial capacity of 0, the
-     * sparse array will be initialized with a light-weight representation
-     * not requiring any additional array allocations.
-     */
-    PositionMap(int initialCapacity) {
-        if (initialCapacity == 0) {
-            mKeys = ContainerHelpers.EMPTY_INTS;
-            mValues = ContainerHelpers.EMPTY_OBJECTS;
-        } else {
-            initialCapacity = idealIntArraySize(initialCapacity);
-            mKeys = new int[initialCapacity];
-            mValues = new Object[initialCapacity];
-        }
-        mSize = 0;
-    }
-
-    @Override
-    @SuppressWarnings("unchecked")
-    public PositionMap<E> clone() {
-        PositionMap<E> clone = null;
-        try {
-            clone = (PositionMap<E>) super.clone();
-            clone.mKeys = mKeys.clone();
-            clone.mValues = mValues.clone();
-        } catch (CloneNotSupportedException cnse) {
-            /* ignore */
-        }
-        return clone;
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or <code>null</code>
-     * if no such mapping has been made.
-     */
-    public E get(int key) {
-        return get(key, null);
-    }
-
-    /**
-     * Gets the Object mapped from the specified key, or the specified Object
-     * if no such mapping has been made.
-     */
-    @SuppressWarnings("unchecked")
-    public E get(int key, E valueIfKeyNotFound) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i < 0 || mValues[i] == DELETED) {
-            return valueIfKeyNotFound;
-        } else {
-            return (E) mValues[i];
-        }
-    }
-
-    /**
-     * Removes the mapping from the specified key, if there was any.
-     */
-    public void delete(int key) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            if (mValues[i] != DELETED) {
-                mValues[i] = DELETED;
-                mGarbage = true;
-            }
-        }
-    }
-
-    /**
-     * Alias for {@link #delete(int)}.
-     */
-    public void remove(int key) {
-        delete(key);
-    }
-
-    /**
-     * Removes the mapping at the specified index.
-     */
-    public void removeAt(int index) {
-        if (mValues[index] != DELETED) {
-            mValues[index] = DELETED;
-            mGarbage = true;
-        }
-    }
-
-    /**
-     * Remove a range of mappings as a batch.
-     *
-     * @param index Index to begin at
-     * @param size Number of mappings to remove
-     */
-    public void removeAtRange(int index, int size) {
-        final int end = Math.min(mSize, index + size);
-        for (int i = index; i < end; i++) {
-            removeAt(i);
-        }
-    }
-
-    public void insertKeyRange(int keyStart, int count) {
-
-    }
-
-    public void removeKeyRange(ArrayList<E> removedItems, int keyStart, int count) {
-
-    }
-
-    private void gc() {
-        // Log.e("SparseArray", "gc start with " + mSize);
-
-        int n = mSize;
-        int o = 0;
-        int[] keys = mKeys;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            Object val = values[i];
-
-            if (val != DELETED) {
-                if (i != o) {
-                    keys[o] = keys[i];
-                    values[o] = val;
-                    values[i] = null;
-                }
-
-                o++;
-            }
-        }
-
-        mGarbage = false;
-        mSize = o;
-
-        // Log.e("SparseArray", "gc end with " + mSize);
-    }
-
-    /**
-     * Adds a mapping from the specified key to the specified value,
-     * replacing the previous mapping from the specified key if there
-     * was one.
-     */
-    public void put(int key, E value) {
-        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
-
-        if (i >= 0) {
-            mValues[i] = value;
-        } else {
-            i = ~i;
-
-            if (i < mSize && mValues[i] == DELETED) {
-                mKeys[i] = key;
-                mValues[i] = value;
-                return;
-            }
-
-            if (mGarbage && mSize >= mKeys.length) {
-                gc();
-
-                // Search again because indices may have changed.
-                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
-            }
-
-            if (mSize >= mKeys.length) {
-                int n = idealIntArraySize(mSize + 1);
-
-                int[] nkeys = new int[n];
-                Object[] nvalues = new Object[n];
-
-                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-                mKeys = nkeys;
-                mValues = nvalues;
-            }
-
-            if (mSize - i != 0) {
-                // Log.e("SparseArray", "move " + (mSize - i));
-                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
-                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
-            }
-
-            mKeys[i] = key;
-            mValues[i] = value;
-            mSize++;
-        }
-    }
-
-    /**
-     * Returns the number of key-value mappings that this SparseArray
-     * currently stores.
-     */
-    public int size() {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mSize;
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the key from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    public int keyAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return mKeys[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, returns
-     * the value from the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    @SuppressWarnings("unchecked")
-    public E valueAt(int index) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return (E) mValues[index];
-    }
-
-    /**
-     * Given an index in the range <code>0...size()-1</code>, sets a new
-     * value for the <code>index</code>th key-value mapping that this
-     * SparseArray stores.
-     */
-    public void setValueAt(int index, E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        mValues[index] = value;
-    }
-
-    /**
-     * Returns the index for which {@link #keyAt} would return the
-     * specified key, or a negative number if the specified
-     * key is not mapped.
-     */
-    public int indexOfKey(int key) {
-        if (mGarbage) {
-            gc();
-        }
-
-        return ContainerHelpers.binarySearch(mKeys, mSize, key);
-    }
-
-    /**
-     * Returns an index for which {@link #valueAt} would return the
-     * specified key, or a negative number if no keys map to the
-     * specified value.
-     * <p>Beware that this is a linear search, unlike lookups by key,
-     * and that multiple keys can map to the same value and this will
-     * find only one of them.
-     * <p>Note also that unlike most collections' {@code indexOf} methods,
-     * this method compares values using {@code ==} rather than {@code equals}.
-     */
-    public int indexOfValue(E value) {
-        if (mGarbage) {
-            gc();
-        }
-
-        for (int i = 0; i < mSize; i++) {
-            if (mValues[i] == value) {
-                return i;
-            }
-        }
-
-        return -1;
-    }
-
-    /**
-     * Removes all key-value mappings from this SparseArray.
-     */
-    public void clear() {
-        int n = mSize;
-        Object[] values = mValues;
-
-        for (int i = 0; i < n; i++) {
-            values[i] = null;
-        }
-
-        mSize = 0;
-        mGarbage = false;
-    }
-
-    /**
-     * Puts a key/value pair into the array, optimizing for the case where
-     * the key is greater than all existing keys in the array.
-     */
-    public void append(int key, E value) {
-        if (mSize != 0 && key <= mKeys[mSize - 1]) {
-            put(key, value);
-            return;
-        }
-
-        if (mGarbage && mSize >= mKeys.length) {
-            gc();
-        }
-
-        int pos = mSize;
-        if (pos >= mKeys.length) {
-            int n = idealIntArraySize(pos + 1);
-
-            int[] nkeys = new int[n];
-            Object[] nvalues = new Object[n];
-
-            // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
-            System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
-            System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
-
-            mKeys = nkeys;
-            mValues = nvalues;
-        }
-
-        mKeys[pos] = key;
-        mValues[pos] = value;
-        mSize = pos + 1;
-    }
-
-    /**
-     * {@inheritDoc}
-     *
-     * <p>This implementation composes a string by iterating over its mappings. If
-     * this map contains itself as a value, the string "(this Map)"
-     * will appear in its place.
-     */
-    @Override
-    public String toString() {
-        if (size() <= 0) {
-            return "{}";
-        }
-
-        StringBuilder buffer = new StringBuilder(mSize * 28);
-        buffer.append('{');
-        for (int i = 0; i < mSize; i++) {
-            if (i > 0) {
-                buffer.append(", ");
-            }
-            int key = keyAt(i);
-            buffer.append(key);
-            buffer.append('=');
-            Object value = valueAt(i);
-            if (value != this) {
-                buffer.append(value);
-            } else {
-                buffer.append("(this Map)");
-            }
-        }
-        buffer.append('}');
-        return buffer.toString();
-    }
-
-    static int idealByteArraySize(int need) {
-        for (int i = 4; i < 32; i++) {
-            if (need <= (1 << i) - 12) {
-                return (1 << i) - 12;
-            }
-        }
-
-        return need;
-    }
-
-    static int idealBooleanArraySize(int need) {
-        return idealByteArraySize(need);
-    }
-
-    static int idealShortArraySize(int need) {
-        return idealByteArraySize(need * 2) / 2;
-    }
-
-    static int idealCharArraySize(int need) {
-        return idealByteArraySize(need * 2) / 2;
-    }
-
-    static int idealIntArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
-    }
-
-    static int idealFloatArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
-    }
-
-    static int idealObjectArraySize(int need) {
-        return idealByteArraySize(need * 4) / 4;
-    }
-
-    static int idealLongArraySize(int need) {
-        return idealByteArraySize(need * 8) / 8;
-    }
-
-    static class ContainerHelpers {
-        static final boolean[] EMPTY_BOOLEANS = new boolean[0];
-        static final int[] EMPTY_INTS = new int[0];
-        static final long[] EMPTY_LONGS = new long[0];
-        static final Object[] EMPTY_OBJECTS = new Object[0];
-
-        // This is Arrays.binarySearch(), but doesn't do any argument validation.
-        static int binarySearch(int[] array, int size, int value) {
-            int lo = 0;
-            int hi = size - 1;
-
-            while (lo <= hi) {
-                final int mid = (lo + hi) >>> 1;
-                final int midVal = array[mid];
-
-                if (midVal < value) {
-                    lo = mid + 1;
-                } else if (midVal > value) {
-                    hi = mid - 1;
-                } else {
-                    return mid;  // value found
-                }
-            }
-            return ~lo;  // value not present
-        }
-    }
-
-}
diff --git a/viewpager2/src/androidTest/AndroidManifest.xml b/viewpager2/src/androidTest/AndroidManifest.xml
index d1332fa..8e7596b 100755
--- a/viewpager2/src/androidTest/AndroidManifest.xml
+++ b/viewpager2/src/androidTest/AndroidManifest.xml
@@ -19,6 +19,7 @@
     <uses-sdk android:targetSdkVersion="${target-sdk-version}"/>
 
     <application android:supportsRtl="true">
-        <activity android:name="androidx.viewpager2.widget.TestActivity"/>
+        <activity android:name="androidx.viewpager2.widget.swipe.ViewAdapterActivity"/>
+        <activity android:name="androidx.viewpager2.widget.swipe.FragmentAdapterActivity"/>
     </application>
 </manifest>
\ No newline at end of file
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java
new file mode 100644
index 0000000..483317b
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BasicTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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 androidx.viewpager2.widget;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.arrayWithSize;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import java.util.UUID;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BasicTest {
+    @Rule
+    public ExpectedException mExpectedException = ExpectedException.none();
+
+    @Test
+    public void test_recyclerViewAdapter_pageFillEnforced() {
+        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 RecyclerView.Adapter<RecyclerView.ViewHolder>() {
+            @NonNull
+            @Override
+            public RecyclerView.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 RecyclerView.ViewHolder(view) {
+                };
+            }
+
+            @Override
+            public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+                // do nothing
+            }
+
+            @Override
+            public int getItemCount() {
+                return 1;
+            }
+        });
+
+        viewPager.measure(0, 0); // equivalent of unspecified
+    }
+
+    @Test
+    public void test_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));
+    }
+
+    @Test
+    public void test_saveStateParcel_createRestore() throws Throwable {
+        // given
+        Bundle superState = createIntBundle(42);
+        ViewPager2.SavedState state = new ViewPager2.SavedState(superState);
+        state.mRecyclerViewId = 700;
+        state.mAdapterState = new Parcelable[]{createIntBundle(1), createIntBundle(2),
+                createIntBundle(3)};
+
+        // when
+        Parcel parcel = Parcel.obtain();
+        state.writeToParcel(parcel, 0);
+        final String parcelSuffix = UUID.randomUUID().toString();
+        parcel.writeString(parcelSuffix); // to verify parcel boundaries
+        parcel.setDataPosition(0);
+        ViewPager2.SavedState recreatedState = ViewPager2.SavedState.CREATOR.createFromParcel(
+                parcel);
+
+        // then
+        assertThat("Parcel reading should not go out of bounds", parcel.readString(),
+                equalTo(parcelSuffix));
+        assertThat("All of the parcel should be read", parcel.dataAvail(), equalTo(0));
+        assertThat(recreatedState.mRecyclerViewId, equalTo(700));
+        assertThat(recreatedState.mAdapterState, arrayWithSize(3));
+        assertThat((int) ((Bundle) recreatedState.getSuperState()).get("key"), equalTo(42));
+        assertThat((int) ((Bundle) recreatedState.mAdapterState[0]).get("key"), equalTo(1));
+        assertThat((int) ((Bundle) recreatedState.mAdapterState[1]).get("key"), equalTo(2));
+        assertThat((int) ((Bundle) recreatedState.mAdapterState[2]).get("key"), equalTo(3));
+    }
+
+    private Bundle createIntBundle(int value) {
+        Bundle bundle = new Bundle(1);
+        bundle.putInt("key", value);
+        return bundle;
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.java
new file mode 100644
index 0000000..8d32543
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/SwipeTest.java
@@ -0,0 +1,313 @@
+/*
+ * 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 androidx.viewpager2.widget;
+
+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.assertThat;
+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.view.View.OVER_SCROLL_NEVER;
+
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+
+import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
+
+import android.os.Build;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.testutils.FragmentActivityUtils;
+import androidx.viewpager2.test.R;
+import androidx.viewpager2.widget.swipe.BaseActivity;
+import androidx.viewpager2.widget.swipe.FragmentAdapterActivity;
+import androidx.viewpager2.widget.swipe.PageSwiper;
+import androidx.viewpager2.widget.swipe.ViewAdapterActivity;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+@LargeTest
+@RunWith(Parameterized.class)
+public class SwipeTest {
+    private static final List<Class<? extends BaseActivity>> TEST_ACTIVITIES_ALL = asList(
+            ViewAdapterActivity.class, FragmentAdapterActivity.class);
+    private static final Set<Integer> NO_CONFIG_CHANGES = Collections.emptySet();
+    private static final List<Pair<Integer, Integer>> NO_MUTATIONS = Collections.emptyList();
+    private static final boolean RANDOM_PASS_ENABLED = false;
+
+    private final TestConfig mTestConfig;
+    private ActivityTestRule<? extends BaseActivity> mActivityTestRule;
+    private PageSwiper mSwiper;
+
+    public SwipeTest(TestConfig testConfig) {
+        mTestConfig = testConfig;
+    }
+
+    @Test
+    public void test() throws Throwable {
+        BaseActivity activity = mActivityTestRule.getActivity();
+
+        final int[] expectedValues = new int[mTestConfig.mTotalPages];
+        for (int i = 0; i < mTestConfig.mTotalPages; i++) {
+            expectedValues[i] = i;
+        }
+
+        int currentPage = 0, currentStep = 0;
+        assertStateCorrect(expectedValues[currentPage], activity);
+        for (int nextPage : mTestConfig.mPageSequence) {
+            // value change
+            if (mTestConfig.mStepToNewValue.containsKey(currentStep)) {
+                expectedValues[currentPage] = mTestConfig.mStepToNewValue.get(currentStep);
+                updatePage(currentPage, expectedValues[currentPage], activity);
+                assertStateCorrect(expectedValues[currentPage], activity);
+            }
+
+            // config change
+            if (mTestConfig.mConfigChangeSteps.contains(currentStep++)) {
+                activity = FragmentActivityUtils.recreateActivity(mActivityTestRule, activity);
+                assertStateCorrect(expectedValues[currentPage], activity);
+            }
+
+            // page swipe
+            mSwiper.swipe(currentPage, nextPage);
+            currentPage = nextPage;
+            assertStateCorrect(expectedValues[currentPage], activity);
+        }
+    }
+
+    private static void updatePage(final int pageIx, final int newValue,
+            final BaseActivity activity) {
+        activity.runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                activity.updatePage(pageIx, newValue);
+            }
+        });
+    }
+
+    private void assertStateCorrect(int expectedValue, BaseActivity activity) {
+        onView(allOf(withId(R.id.text_view), isDisplayed())).check(
+                matches(withText(String.valueOf(expectedValue))));
+        activity.validateState();
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static List<TestConfig> getParams() {
+        List<TestConfig> tests = new ArrayList<>();
+
+        if (RANDOM_PASS_ENABLED) { // run locally after making larger changes
+            tests.addAll(generateRandomTests());
+        }
+
+        for (Class<? extends BaseActivity> activityClass : TEST_ACTIVITIES_ALL) {
+            tests.add(new TestConfig("full pass", asList(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0),
+                    NO_CONFIG_CHANGES, NO_MUTATIONS, 8, activityClass));
+
+            tests.add(new TestConfig("swipe beyond edge pages",
+                    asList(0, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0), NO_CONFIG_CHANGES, NO_MUTATIONS, 4,
+                    activityClass));
+
+            tests.add(new TestConfig("config change", asList(1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0),
+                    asList(3, 5, 7), NO_MUTATIONS, 7, activityClass));
+
+            tests.add(
+                    new TestConfig("regression1", asList(1, 2, 3, 2, 1, 2, 3, 4), NO_CONFIG_CHANGES,
+                            NO_MUTATIONS, 10, activityClass));
+
+            tests.add(new TestConfig("regression2", asList(1, 2, 3, 4, 3, 2, 1, 2, 3, 4, 5),
+                    NO_CONFIG_CHANGES, NO_MUTATIONS, 10, activityClass));
+
+            tests.add(new TestConfig("regression3", asList(1, 2, 3, 2, 1, 2, 3, 2, 1, 0),
+                    NO_CONFIG_CHANGES, NO_MUTATIONS, 10, activityClass));
+        }
+
+        // mutations only apply to Fragment state persistence
+        tests.add(new TestConfig("mutations", asList(1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0),
+                singletonList(8),
+                asList(Pair.create(0, 999), Pair.create(1, 100), Pair.create(3, 300),
+                        Pair.create(5, 500)), 7, FragmentAdapterActivity.class));
+
+        return checkTestNamesUnique(tests);
+    }
+
+    private static Collection<TestConfig> generateRandomTests() {
+        List<TestConfig> result = new ArrayList<>();
+
+        int id = 0;
+        for (int i = 0; i < 10; i++) {
+            // both adapters
+            for (Class<? extends BaseActivity> adapterClass : TEST_ACTIVITIES_ALL) {
+                result.add(createRandomTest(id++, 8, 50, 0, 0, 0.875, adapterClass));
+                result.add(createRandomTest(id++, 8, 10, 0.5, 0, 0.875, adapterClass));
+            }
+
+            // fragment adapter specific
+            result.add(
+                    createRandomTest(id++, 8, 50, 0, 0.125, 0.875, FragmentAdapterActivity.class));
+            result.add(createRandomTest(id++, 8, 10, 0.5, 0.125, 0.875,
+                    FragmentAdapterActivity.class));
+        }
+
+        return result;
+    }
+
+    /**
+     * @param advanceProbability determines the probability of a swipe direction being towards
+     *                           the next edge - e.g. if we start from the left, it's the
+     *                           probability that the next swipe will go right. <p> Setting it to
+     *                           values closer to 0.5 results in a lot of back and forth, while
+     *                           setting it closer to 1.0 results in going edge to edge with few
+     *                           back-swipes.
+     */
+    @SuppressWarnings("SameParameterValue")
+    private static TestConfig createRandomTest(int id, int totalPages, int sequenceLength,
+            double configChangeProbability, double mutationProbability, double advanceProbability,
+            Class<? extends BaseActivity> activityClass) {
+        Random random = new Random();
+
+        List<Integer> pageSequence = new ArrayList<>();
+        List<Integer> configChanges = new ArrayList<>();
+        List<Pair<Integer, Integer>> stepToNewValue = new ArrayList<>();
+
+        int pageIx = 0;
+        Double goRightProbability = null;
+        for (int currentStep = 0; currentStep < sequenceLength; currentStep++) {
+            if (random.nextDouble() < configChangeProbability) {
+                configChanges.add(currentStep);
+            }
+
+            if (random.nextDouble() < mutationProbability) {
+                stepToNewValue.add(Pair.create(currentStep, random.nextInt(10_000)));
+            }
+
+            boolean goRight;
+            if (pageIx == 0) {
+                goRight = true;
+                goRightProbability = advanceProbability;
+            } else if (pageIx == totalPages - 1) { // last page
+                goRight = false;
+                goRightProbability = 1 - advanceProbability;
+            } else {
+                goRight = random.nextDouble() < goRightProbability;
+            }
+            pageSequence.add(goRight ? ++pageIx : --pageIx);
+        }
+
+        return new TestConfig("random_" + id, pageSequence, configChanges, stepToNewValue,
+                totalPages, activityClass);
+    }
+
+    private static List<TestConfig> checkTestNamesUnique(List<TestConfig> configs) {
+        Set<String> names = new HashSet<>();
+        for (TestConfig config : configs) {
+            names.add(config.toString());
+        }
+        assertThat(names.size(), is(configs.size()));
+        return configs;
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        Log.i(getClass().getSimpleName(), mTestConfig.toFullSpecString());
+
+        mActivityTestRule = new ActivityTestRule<>(mTestConfig.mActivityClass, true, false);
+        mActivityTestRule.launchActivity(BaseActivity.createIntent(mTestConfig.mTotalPages));
+
+        ViewPager2 viewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
+        RecyclerView recyclerView = (RecyclerView) viewPager.getChildAt(0); // HACK
+        mSwiper = new PageSwiper(mTestConfig.mTotalPages, recyclerView);
+
+        // Disabling edge animations on API < 16. Espresso discourages animations altogether, but
+        // keeping them for now where they work - as closer to the real environment.
+        if (Build.VERSION.SDK_INT < 16) {
+            recyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
+        }
+
+        onView(withId(R.id.view_pager)).check(matches(isDisplayed()));
+    }
+
+    private static class TestConfig {
+        final String mMessage;
+        final List<Integer> mPageSequence;
+        final Set<Integer> mConfigChangeSteps;
+        /** {@link Map.Entry#getKey()} = step, {@link Map.Entry#getValue()} = new value */
+        final Map<Integer, Integer> mStepToNewValue;
+        final int mTotalPages;
+        final Class<? extends BaseActivity> mActivityClass;
+
+        /**
+         * @param stepToNewValue {@link Pair#first} = step, {@link Pair#second} = new value
+         */
+        TestConfig(String message, List<Integer> pageSequence,
+                Collection<Integer> configChangeSteps,
+                List<Pair<Integer, Integer>> stepToNewValue,
+                int totalPages,
+                Class<? extends BaseActivity> activityClass) {
+            mMessage = message;
+            mPageSequence = pageSequence;
+            mConfigChangeSteps = new HashSet<>(configChangeSteps);
+            mStepToNewValue = mapFromPairList(stepToNewValue);
+            mTotalPages = totalPages;
+            mActivityClass = activityClass;
+        }
+
+        private static Map<Integer, Integer> mapFromPairList(List<Pair<Integer, Integer>> list) {
+            Map<Integer, Integer> result = new HashMap<>();
+            for (Pair<Integer, Integer> pair : list) {
+                Integer prevValueAtKey = result.put(pair.first, pair.second);
+                assertThat("there should be only one value defined for a key", prevValueAtKey,
+                        equalTo(null));
+            }
+            return result;
+        }
+
+        @Override
+        public String toString() {
+            return mActivityClass.getSimpleName() + ": " + mMessage;
+        }
+
+        String toFullSpecString() {
+            return String.format(
+                    "Test: %s\nPage sequence: %s\nTotal pages: %s\nMutations {step1:newValue1, "
+                            + "step2:newValue2, ...}: %s",
+                    toString(),
+                    mPageSequence,
+                    mTotalPages,
+                    mStepToNewValue.toString().replace('=', ':'));
+        }
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TestActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TestActivity.java
deleted file mode 100644
index 74e2e4a..0000000
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TestActivity.java
+++ /dev/null
@@ -1,32 +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.viewpager2.widget;
-
-import android.os.Bundle;
-
-import androidx.testutils.RecreatedActivity;
-import androidx.viewpager2.test.R;
-
-public class TestActivity extends RecreatedActivity {
-    @Override
-    public void onCreate(Bundle bundle) {
-        super.onCreate(bundle);
-        setContentView(R.layout.activity_test_layout);
-
-        ViewPager2Tests.sAdapterStrategy.setAdapter((ViewPager2) findViewById(R.id.view_pager));
-    }
-}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ViewPager2Tests.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ViewPager2Tests.java
deleted file mode 100644
index 48d55f7..0000000
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ViewPager2Tests.java
+++ /dev/null
@@ -1,669 +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.viewpager2.widget;
-
-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.view.View.OVER_SCROLL_NEVER;
-
-import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
-
-import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.arrayWithSize;
-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.os.Parcel;
-import android.os.Parcelable;
-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.text.TextUtils;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.core.util.Preconditions;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
-import androidx.recyclerview.widget.RecyclerView;
-import androidx.recyclerview.widget.RecyclerView.Adapter;
-import androidx.recyclerview.widget.RecyclerView.ViewHolder;
-import androidx.testutils.FragmentActivityUtils;
-import androidx.viewpager2.test.R;
-
-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.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicInteger;
-
-@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")};
-
-    /** mean of injecting different adapters into {@link TestActivity#onCreate(Bundle)} */
-    static AdapterStrategy sAdapterStrategy;
-
-    interface AdapterStrategy {
-        void setAdapter(ViewPager2 viewPager);
-    }
-
-    @Rule
-    public final ActivityTestRule<TestActivity> mActivityTestRule;
-    @Rule
-    public ExpectedException mExpectedException = ExpectedException.none();
-
-    // allows to wait until swipe operation is finished (Smooth Scroller done)
-    private CountDownLatch mStableAfterSwipe;
-
-    public ViewPager2Tests() {
-        mActivityTestRule = new ActivityTestRule<>(TestActivity.class, true, false);
-    }
-
-    private void setUpActivity(AdapterStrategy adapterStrategy) {
-        sAdapterStrategy = Preconditions.checkNotNull(adapterStrategy);
-        mActivityTestRule.launchActivity(null);
-
-        ViewPager2 viewPager = mActivityTestRule.getActivity().findViewById(R.id.view_pager);
-        viewPager.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();
-                }
-            }
-        });
-
-        if (Build.VERSION.SDK_INT < 16) { // TODO(b/71500143): remove temporary workaround
-            RecyclerView mRecyclerView = (RecyclerView) viewPager.getChildAt(0);
-            mRecyclerView.setOverScrollMode(OVER_SCROLL_NEVER);
-        }
-
-        onView(withId(viewPager.getId())).check(matches(isDisplayed()));
-    }
-
-    @Before
-    public void setUp() {
-        sAdapterStrategy = null;
-
-        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_activityRecreation() throws Throwable {
-        testFragmentLifecycle(7, Arrays.asList(1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0),
-                PageMutator.NO_OP, new HashSet<>(Arrays.asList(3, 5, 7)));
-    }
-
-    @Test
-    public void fragmentAdapter_random() throws Throwable {
-        final int totalPages = 8; // increase when stress testing locally
-        final int sequenceLength = 20; // increase when stress testing locally
-        testFragmentLifecycle_random(totalPages, sequenceLength, PageMutator.NO_OP);
-    }
-
-    @Test
-    public void fragmentAdapter_random_withMutations() throws Throwable {
-        final int totalPages = 8; // increase when stress testing locally
-        final int sequenceLength = 20; // increase when stress testing locally
-        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,
-                Collections.<Integer>emptySet());
-    }
-
-    @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, Set) */
-    private void testFragmentLifecycle(final int totalPages, List<Integer> pageSequence)
-            throws Throwable {
-        testFragmentLifecycle(totalPages, pageSequence, PageMutator.NO_OP,
-                Collections.<Integer>emptySet());
-    }
-
-    /**
-     * 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, Set<Integer> activityRecreateSteps) 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;
-        }
-
-        setUpActivity(new AdapterStrategy() {
-            @Override
-            public void setAdapter(ViewPager2 viewPager) {
-                viewPager.setAdapter(
-                        ((FragmentActivity) viewPager.getContext()).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);
-        verifyCurrentPage(expectedValues[currentPage.get()]);
-        int stepCounter = 0;
-        for (int nextPage : pageSequence) {
-            if (activityRecreateSteps.contains(stepCounter++)) {
-                FragmentActivityUtils.recreateActivity(mActivityTestRule,
-                        mActivityTestRule.getActivity());
-            }
-            swipe(currentPage.get(), nextPage, totalPages);
-            currentPage.set(nextPage);
-            verifyCurrentPage(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_edges() throws Throwable {
-        testViewAdapter(4, Arrays.asList(0, 0, 1, 2, 3, 3, 3, 2, 1, 0, 0, 0),
-                Collections.<Integer>emptySet());
-    }
-
-    @Test
-    public void viewAdapter_fullPass() throws Throwable {
-        testViewAdapter(8, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 6, 5, 4, 3, 2, 1, 0),
-                Collections.<Integer>emptySet());
-    }
-
-    @Test
-    public void viewAdapter_activityRecreation() throws Throwable {
-        testViewAdapter(7,
-                Arrays.asList(1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1, 0),
-                new HashSet<>(Arrays.asList(3, 5, 7)));
-    }
-
-    @Test
-    public void saveState_parcelWriteRestore() throws Throwable {
-        // given
-        Bundle superState = createIntBundle(42);
-        ViewPager2.SavedState state = new ViewPager2.SavedState(superState);
-        state.mRecyclerViewId = 700;
-        state.mAdapterState = new Parcelable[]{createIntBundle(1), createIntBundle(2),
-                createIntBundle(3)};
-
-        // when
-        Parcel parcel = Parcel.obtain();
-        state.writeToParcel(parcel, 0);
-        final String parcelSuffix = UUID.randomUUID().toString();
-        parcel.writeString(parcelSuffix); // to verify parcel boundaries
-        parcel.setDataPosition(0);
-        ViewPager2.SavedState recreatedState = ViewPager2.SavedState.CREATOR.createFromParcel(
-                parcel);
-
-        // then
-        assertThat("Parcel reading should not go out of bounds", parcel.readString(),
-                equalTo(parcelSuffix));
-        assertThat("All of the parcel should be read", parcel.dataAvail(), equalTo(0));
-        assertThat(recreatedState.mRecyclerViewId, equalTo(700));
-        assertThat(recreatedState.mAdapterState, arrayWithSize(3));
-        assertThat((int) ((Bundle) recreatedState.getSuperState()).get("key"), equalTo(42));
-        assertThat((int) ((Bundle) recreatedState.mAdapterState[0]).get("key"), equalTo(1));
-        assertThat((int) ((Bundle) recreatedState.mAdapterState[1]).get("key"), equalTo(2));
-        assertThat((int) ((Bundle) recreatedState.mAdapterState[2]).get("key"), equalTo(3));
-    }
-
-    private Bundle createIntBundle(int value) {
-        Bundle bundle = new Bundle(1);
-        bundle.putInt("key", value);
-        return bundle;
-    }
-
-    private void testViewAdapter(final int totalPages, List<Integer> pageSequence,
-            Set<Integer> activityRecreateSteps) throws InterruptedException {
-        setUpActivity(new AdapterStrategy() {
-            @Override
-            public void setAdapter(final ViewPager2 viewPager) {
-                viewPager.setAdapter(
-                        new Adapter<ViewHolder>() {
-                            @NonNull
-                            @Override
-                            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
-                                    int viewType) {
-                                return new ViewHolder(
-                                        LayoutInflater.from(viewPager.getContext()).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;
-                            }
-                        });
-            }
-        });
-
-        verifyCurrentPage(0);
-        int currentPage = 0;
-        int stepCounter = 0;
-        for (int nextPage : pageSequence) {
-            if (activityRecreateSteps.contains(stepCounter++)) {
-                FragmentActivityUtils.recreateActivity(mActivityTestRule,
-                        mActivityTestRule.getActivity());
-            }
-            swipe(currentPage, nextPage, totalPages);
-            currentPage = nextPage;
-            verifyCurrentPage(currentPage);
-        }
-    }
-
-    /**
-     * Verifies that the current page displays the correct value and has the correct color.
-     *
-     * @param expectedPageValue value expected to be displayed on the page
-     */
-    private void verifyCurrentPage(int expectedPageValue) {
-        onView(allOf(withId(R.id.text_view), isDisplayed())).check(
-                matches(allOf(withText(String.valueOf(expectedPageValue)),
-                        new BackgroundColorMatcher(getColor(expectedPageValue)))));
-    }
-
-    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/viewpager2/widget/swipe/BaseActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java
new file mode 100644
index 0000000..5e3f326
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/BaseActivity.java
@@ -0,0 +1,56 @@
+/*
+ * 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 androidx.viewpager2.widget.swipe;
+
+import static androidx.core.util.Preconditions.checkNotNull;
+
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.testutils.RecreatedActivity;
+import androidx.viewpager2.test.R;
+import androidx.viewpager2.widget.ViewPager2;
+
+public abstract class BaseActivity extends RecreatedActivity {
+    private static final String ARG_TOTAL_PAGES = "totalPages";
+
+    protected ViewPager2 mViewPager;
+    protected int mTotalPages;
+
+    @Override
+    public void onCreate(Bundle bundle) {
+        super.onCreate(bundle);
+        setContentView(R.layout.activity_test_layout);
+
+        mViewPager = findViewById(R.id.view_pager);
+        mTotalPages = checkNotNull(getIntent().getExtras()).getInt(ARG_TOTAL_PAGES);
+
+        setAdapter();
+    }
+
+    protected abstract void setAdapter();
+
+    public abstract void validateState();
+
+    public abstract void updatePage(int pageIx, int newValue);
+
+    public static Intent createIntent(int totalPages) {
+        Intent intent = new Intent();
+        intent.putExtra(ARG_TOTAL_PAGES, totalPages);
+        return intent;
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapterActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapterActivity.java
new file mode 100644
index 0000000..2d670a8
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/FragmentAdapterActivity.java
@@ -0,0 +1,93 @@
+/*
+ * 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 androidx.viewpager2.widget.swipe;
+
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.lessThanOrEqualTo;
+import static org.junit.Assert.assertThat;
+
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.widget.ViewPager2;
+
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class FragmentAdapterActivity extends BaseActivity {
+    private static final Random RANDOM = new Random();
+
+    private AtomicInteger mAttachCount = new AtomicInteger(0);
+    private AtomicInteger mDestroyCount = new AtomicInteger(0);
+    private PageFragment[] mFragments;
+
+    @Override
+    protected void setAdapter() {
+        mFragments = new PageFragment[mTotalPages];
+
+        ViewPager2.FragmentProvider fragmentProvider = new ViewPager2.FragmentProvider() {
+            final boolean[] mWasEverAttached = new boolean[mTotalPages];
+
+            @Override
+            public Fragment getItem(final int position) {
+                PageFragment fragment = PageFragment.create(valueForPosition(position));
+
+                fragment.mOnAttachListener = new PageFragment.EventListener() {
+                    @Override
+                    public void onEvent(PageFragment fragment) {
+                        mAttachCount.incrementAndGet();
+                        mWasEverAttached[position] = true;
+                    }
+                };
+
+                fragment.mOnDestroyListener = new PageFragment.EventListener() {
+                    @Override
+                    public void onEvent(PageFragment fragment) {
+                        mDestroyCount.incrementAndGet();
+                    }
+                };
+
+                return mFragments[position] = fragment;
+            }
+
+            private int valueForPosition(int position) {
+                // only supply correct value ones; then rely on it being kept by Fragment state
+                return mWasEverAttached[position]
+                        ? RANDOM.nextInt() // junk value to be overridden by state saved value
+                        : position;
+            }
+
+            @Override
+            public int getCount() {
+                return mTotalPages;
+            }
+        };
+
+        mViewPager.setAdapter(getSupportFragmentManager(), fragmentProvider,
+                ViewPager2.FragmentRetentionPolicy.SAVE_STATE);
+    }
+
+    @Override
+    public void updatePage(int pageIx, int newValue) {
+        mFragments[pageIx].updateValue(newValue);
+    }
+
+    @Override
+    public void validateState() {
+        assertThat(mAttachCount.get() - mDestroyCount.get(),
+                allOf(greaterThanOrEqualTo(1), lessThanOrEqualTo(4)));
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageFragment.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageFragment.java
new file mode 100644
index 0000000..23132bc
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageFragment.java
@@ -0,0 +1,91 @@
+/*
+ * 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 androidx.viewpager2.widget.swipe;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.viewpager2.test.R;
+
+public class PageFragment extends Fragment {
+    private static final String ARG_VALUE = "value";
+
+    private int mValue;
+    EventListener mOnAttachListener = EventListener.NO_OP;
+    EventListener mOnDestroyListener = EventListener.NO_OP;
+
+    static PageFragment create(int value) {
+        PageFragment result = new PageFragment();
+        Bundle args = new Bundle(1);
+        args.putInt(ARG_VALUE, value);
+        result.setArguments(args);
+        return result;
+    }
+
+    @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();
+        updateValue(data.getInt(ARG_VALUE));
+    }
+
+    @Override
+    public void onAttach(Context context) {
+        super.onAttach(context);
+        mOnAttachListener.onEvent(this);
+    }
+
+    @Override
+    public void onSaveInstanceState(@NonNull Bundle outState) {
+        outState.putInt(ARG_VALUE, mValue);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mOnDestroyListener.onEvent(this);
+    }
+
+    void updateValue(int newValue) {
+        mValue = newValue;
+        ((TextView) getView()).setText(String.valueOf(newValue));
+    }
+
+    public interface EventListener {
+        void onEvent(PageFragment fragment);
+
+        EventListener NO_OP = new EventListener() {
+            @Override
+            public void onEvent(PageFragment fragment) {
+                // do nothing
+            }
+        };
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.java
new file mode 100644
index 0000000..a17ef94
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/PageSwiper.java
@@ -0,0 +1,98 @@
+/*
+ * 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 androidx.viewpager2.widget.swipe;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import static androidx.core.util.Preconditions.checkArgumentNonnegative;
+import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE;
+
+import static org.hamcrest.CoreMatchers.allOf;
+
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.ViewActions;
+
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.viewpager2.test.R;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class PageSwiper {
+    private CountDownLatch mStableAfterSwipe;
+    private final int mLastPageIx;
+
+    public PageSwiper(int totalPages, RecyclerView recyclerView) {
+        mLastPageIx = checkArgumentNonnegative(totalPages - 1);
+
+        recyclerView.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();
+                }
+            }
+        });
+    }
+
+    public void swipe(int currentPageIx, int nextPageIx) throws InterruptedException {
+        if (nextPageIx > mLastPageIx) {
+            throw new IllegalArgumentException("Invalid next page: beyond last page.");
+        }
+
+        if (currentPageIx == nextPageIx) { // dedicated for testing edge behaviour
+            if (nextPageIx == 0) {
+                swipeRight(); // bounce off the left edge
+                return;
+            }
+            if (nextPageIx == mLastPageIx) { // bounce off the right edge
+                swipeLeft();
+                return;
+            }
+            throw new IllegalArgumentException(
+                    "Invalid sequence. Not on an edge, and current page = next page.");
+        }
+
+        if (Math.abs(nextPageIx - currentPageIx) > 1) {
+            throw new IllegalArgumentException(
+                    "Specified next page not adjacent to the current page.");
+        }
+
+        if (nextPageIx > currentPageIx) {
+            swipeLeft();
+        } else {
+            swipeRight();
+        }
+    }
+
+    private void swipeLeft() throws InterruptedException {
+        swipe(ViewActions.swipeLeft());
+    }
+
+    private void swipeRight() throws InterruptedException {
+        swipe(ViewActions.swipeRight());
+    }
+
+    private void swipe(ViewAction swipeAction) throws InterruptedException {
+        mStableAfterSwipe = new CountDownLatch(1);
+        onView(allOf(isDisplayed(), withId(R.id.text_view))).perform(swipeAction);
+        mStableAfterSwipe.await(1, TimeUnit.SECONDS);
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapterActivity.java b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapterActivity.java
new file mode 100644
index 0000000..8830561
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/swipe/ViewAdapterActivity.java
@@ -0,0 +1,64 @@
+/*
+ * 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 androidx.viewpager2.widget.swipe;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+import androidx.recyclerview.widget.RecyclerView.ViewHolder;
+import androidx.viewpager2.test.R;
+
+public class ViewAdapterActivity extends BaseActivity {
+    @Override
+    protected void setAdapter() {
+        mViewPager.setAdapter(new RecyclerView.Adapter<ViewHolder>() {
+            @NonNull
+            @Override
+            public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
+                    int viewType) {
+                return new ViewHolder(
+                        LayoutInflater.from(ViewAdapterActivity.this).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));
+            }
+
+            @Override
+            public int getItemCount() {
+                return mTotalPages;
+            }
+        });
+    }
+
+    @Override
+    public void validateState() {
+        // do nothing
+    }
+
+    @Override
+    public void updatePage(int pageIx, int newValue) {
+        throw new IllegalStateException("not implemented");
+    }
+}
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
index 11c73f2..29e2f40 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
+++ b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
@@ -158,7 +158,7 @@
         int mRecyclerViewId;
         Parcelable[] mAdapterState;
 
-        @RequiresApi(21)
+        @RequiresApi(24)
         SavedState(Parcel source, ClassLoader loader) {
             super(source, loader);
             readValues(source, loader);
@@ -188,7 +188,7 @@
         static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
             @Override
             public SavedState createFromParcel(Parcel source, ClassLoader loader) {
-                return Build.VERSION.SDK_INT >= 21
+                return Build.VERSION.SDK_INT >= 24
                         ? new SavedState(source, loader)
                         : new SavedState(source);
             }
@@ -455,11 +455,6 @@
                 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
diff --git a/webkit/api/current.txt b/webkit/api/current.txt
index 36bc76b..fb15e2f 100644
--- a/webkit/api/current.txt
+++ b/webkit/api/current.txt
@@ -32,6 +32,7 @@
   }
 
   public class WebViewCompat {
+    method public static android.content.pm.PackageInfo getCurrentWebViewPackage(android.content.Context);
     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>);
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
index 3c64b9c..bd77fdb 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewCompatTest.java
@@ -19,6 +19,7 @@
 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 static org.junit.Assert.fail;
 
@@ -28,6 +29,7 @@
 import android.os.Looper;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
+import android.support.test.filters.Suppress;
 import android.support.test.runner.AndroidJUnit4;
 import android.webkit.SafeBrowsingResponse;
 import android.webkit.ValueCallback;
@@ -83,6 +85,7 @@
         assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
+    @Suppress // TODO(gsennton) remove @Suppress when b/76202025 has been resolved
     @Test
     public void testCheckThread() {
         try {
@@ -235,4 +238,22 @@
             Assert.fail("The privacy policy URL should be a well-formed URL");
         }
     }
+
+    /**
+     * WebViewCompat.getCurrentWebViewPackage should be null on pre-L devices.
+     * On L+ devices WebViewCompat.getCurrentWebViewPackage should be null only in exceptional
+     * circumstances - like when the WebView APK is being updated, or for Wear devices. The L+
+     * devices used in support library testing should have a non-null WebView package.
+     */
+    @Test
+    public void testGetCurrentWebViewPackage() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            assertNull(WebViewCompat.getCurrentWebViewPackage(
+                    InstrumentationRegistry.getTargetContext()));
+        } else {
+            assertNotNull(
+                    WebViewCompat.getCurrentWebViewPackage(
+                            InstrumentationRegistry.getTargetContext()));
+        }
+    }
 }
diff --git a/webkit/src/main/java/androidx/webkit/WebViewCompat.java b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
index 0098a82..45def2e 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewCompat.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewCompat.java
@@ -17,6 +17,8 @@
 package androidx.webkit;
 
 import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Looper;
@@ -210,6 +212,92 @@
         }
     }
 
+    /**
+     * If WebView has already been loaded into the current process this method will return the
+     * package that was used to load it. Otherwise, the package that would be used if the WebView
+     * was loaded right now will be returned; this does not cause WebView to be loaded, so this
+     * information may become outdated at any time.
+     * The WebView package changes either when the current WebView package is updated, disabled, or
+     * uninstalled. It can also be changed through a Developer Setting.
+     * If the WebView package changes, any app process that has loaded WebView will be killed. The
+     * next time the app starts and loads WebView it will use the new WebView package instead.
+     * @return the current WebView package, or {@code null} if there is none.
+     */
+    // Note that this API is not protected by a {@link androidx.webkit.WebViewFeature} since
+    // this feature is not dependent on the WebView APK.
+    @Nullable
+    public static PackageInfo getCurrentWebViewPackage(@NonNull Context context) {
+        // There was no WebView Package before Lollipop, the WebView code was part of the framework
+        // back then.
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+            return null;
+        }
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            return WebView.getCurrentWebViewPackage();
+        } else { // L-N
+            try {
+                PackageInfo loadedWebViewPackageInfo = getLoadedWebViewPackageInfo();
+                if (loadedWebViewPackageInfo != null) return loadedWebViewPackageInfo;
+            } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException
+                | NoSuchMethodException  e) {
+                return null;
+            }
+
+            // If WebViewFactory.getLoadedPackageInfo() returns null then WebView hasn't been loaded
+            // yet, in that case we need to fetch the name of the WebView package, and fetch the
+            // corresponding PackageInfo through the PackageManager
+            return getNotYetLoadedWebViewPackageInfo(context);
+        }
+    }
+
+    /**
+     * Return the PackageInfo of the currently loaded WebView APK. This method uses reflection and
+     * propagates any exceptions thrown, to the caller.
+     */
+    private static PackageInfo getLoadedWebViewPackageInfo()
+            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException,
+            IllegalAccessException {
+        Class webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
+        PackageInfo webviewPackageInfo =
+                (PackageInfo) webViewFactoryClass.getMethod(
+                        "getLoadedPackageInfo").invoke(null);
+        return webviewPackageInfo;
+    }
+
+    /**
+     * Return the PackageInfo of the WebView APK that would have been used as WebView implementation
+     * if WebView was to be loaded right now.
+     */
+    private static PackageInfo getNotYetLoadedWebViewPackageInfo(Context context) {
+        String webviewPackageName = null;
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
+                    && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
+                Class webViewFactoryClass = null;
+                webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
+
+                webviewPackageName = (String) webViewFactoryClass.getMethod(
+                        "getWebViewPackageName").invoke(null);
+            } else {
+                Class webviewUpdateServiceClass =
+                        Class.forName("android.webkit.WebViewUpdateService");
+                webviewPackageName = (String) webviewUpdateServiceClass.getMethod(
+                        "getCurrentWebViewPackageName").invoke(null);
+            }
+        } catch (ClassNotFoundException | IllegalAccessException | InvocationTargetException
+                | NoSuchMethodException  e) {
+            return null;
+        }
+        if (webviewPackageName == null) return null;
+        PackageManager pm = context.getPackageManager();
+        try {
+            return pm.getPackageInfo(webviewPackageName, 0);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+    }
+
     private static WebViewProviderAdapter getProvider(WebView webview) {
         return new WebViewProviderAdapter(createProvider(webview));
     }