Merge "Do not allow custom Parcelables for media2" into androidx-master-dev
diff --git a/activity/activity-ktx/src/main/java/androidx/activity/ActivityViewModelLazy.kt b/activity/activity-ktx/src/main/java/androidx/activity/ActivityViewModelLazy.kt
index 2b7b97f..0cdc8cc 100644
--- a/activity/activity-ktx/src/main/java/androidx/activity/ActivityViewModelLazy.kt
+++ b/activity/activity-ktx/src/main/java/androidx/activity/ActivityViewModelLazy.kt
@@ -20,7 +20,6 @@
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelLazy
 import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
 import androidx.lifecycle.ViewModelProvider.Factory
 
 /**
@@ -42,10 +41,7 @@
     noinline factoryProducer: (() -> Factory)? = null
 ): Lazy<VM> {
     val factoryPromise = factoryProducer ?: {
-        val application = application ?: throw IllegalArgumentException(
-            "ViewModel can be accessed only when Activity is attached"
-        )
-        AndroidViewModelFactory.getInstance(application)
+        defaultViewModelProviderFactory
     }
 
     return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise)
diff --git a/activity/activity/api/1.1.0-alpha02.txt b/activity/activity/api/1.1.0-alpha02.txt
index cd98da6..f087fd3 100644
--- a/activity/activity/api/1.1.0-alpha02.txt
+++ b/activity/activity/api/1.1.0-alpha02.txt
@@ -1,9 +1,10 @@
 // Signature format: 3.0
 package androidx.activity {
 
-  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
     ctor public ComponentActivity();
     ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method @Deprecated public Object? getLastCustomNonConfigurationInstance();
     method public androidx.lifecycle.Lifecycle getLifecycle();
     method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
diff --git a/activity/activity/api/current.txt b/activity/activity/api/current.txt
index cd98da6..f087fd3 100644
--- a/activity/activity/api/current.txt
+++ b/activity/activity/api/current.txt
@@ -1,9 +1,10 @@
 // Signature format: 3.0
 package androidx.activity {
 
-  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
     ctor public ComponentActivity();
     ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method @Deprecated public Object? getLastCustomNonConfigurationInstance();
     method public androidx.lifecycle.Lifecycle getLifecycle();
     method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
diff --git a/activity/activity/api/restricted_1.1.0-alpha02.txt b/activity/activity/api/restricted_1.1.0-alpha02.txt
index cd98da6..f087fd3 100644
--- a/activity/activity/api/restricted_1.1.0-alpha02.txt
+++ b/activity/activity/api/restricted_1.1.0-alpha02.txt
@@ -1,9 +1,10 @@
 // Signature format: 3.0
 package androidx.activity {
 
-  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
     ctor public ComponentActivity();
     ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method @Deprecated public Object? getLastCustomNonConfigurationInstance();
     method public androidx.lifecycle.Lifecycle getLifecycle();
     method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
diff --git a/activity/activity/api/restricted_current.txt b/activity/activity/api/restricted_current.txt
index cd98da6..f087fd3 100644
--- a/activity/activity/api/restricted_current.txt
+++ b/activity/activity/api/restricted_current.txt
@@ -1,9 +1,10 @@
 // Signature format: 3.0
 package androidx.activity {
 
-  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
+  public class ComponentActivity extends androidx.core.app.ComponentActivity implements androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.activity.OnBackPressedDispatcherOwner androidx.savedstate.SavedStateRegistryOwner androidx.lifecycle.ViewModelStoreOwner {
     ctor public ComponentActivity();
     ctor @ContentView public ComponentActivity(@LayoutRes int);
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method @Deprecated public Object? getLastCustomNonConfigurationInstance();
     method public androidx.lifecycle.Lifecycle getLifecycle();
     method public final androidx.activity.OnBackPressedDispatcher getOnBackPressedDispatcher();
diff --git a/activity/activity/build.gradle b/activity/activity/build.gradle
index 81bb273..36959fc 100644
--- a/activity/activity/build.gradle
+++ b/activity/activity/build.gradle
@@ -18,10 +18,11 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     api(project(":lifecycle:lifecycle-runtime"))
     api(project(":lifecycle:lifecycle-viewmodel"))
     api("androidx.savedstate:savedstate:1.0.0-rc01")
+    api(project(":lifecycle:lifecycle-viewmodel-savedstate"))
 
     androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityViewModelTest.kt b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityViewModelTest.kt
index b7a8b3f..e52b140 100644
--- a/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityViewModelTest.kt
+++ b/activity/activity/src/androidTest/java/androidx/activity/ComponentActivityViewModelTest.kt
@@ -16,7 +16,10 @@
 
 package androidx.activity
 
+import android.app.Application
 import android.os.Bundle
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.SavedStateHandle
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.ViewModelStore
@@ -72,12 +75,18 @@
     fun testActivityOnCleared() {
         lateinit var activityModel: TestViewModel
         lateinit var defaultActivityModel: TestViewModel
+        lateinit var androidModel: TestAndroidViewModel
+        lateinit var savedStateModel: TestSavedStateViewModel
         ActivityScenario.launch(ViewModelActivity::class.java).use { scenario ->
             activityModel = scenario.withActivity { this.activityModel }
             defaultActivityModel = scenario.withActivity { this.defaultActivityModel }
+            androidModel = scenario.withActivity { this.androidModel }
+            savedStateModel = scenario.withActivity { this.savedStateModel }
         }
         assertThat(activityModel.cleared).isTrue()
         assertThat(defaultActivityModel.cleared).isTrue()
+        assertThat(androidModel.cleared).isTrue()
+        assertThat(savedStateModel.cleared).isTrue()
     }
 }
 
@@ -91,18 +100,19 @@
     lateinit var postOnCreateViewModelStore: ViewModelStore
     lateinit var activityModel: TestViewModel
     lateinit var defaultActivityModel: TestViewModel
+    lateinit var androidModel: TestAndroidViewModel
+    lateinit var savedStateModel: TestSavedStateViewModel
 
     override fun onCreate(savedInstanceState: Bundle?) {
         preOnCreateViewModelStore = viewModelStore
         super.onCreate(savedInstanceState)
         postOnCreateViewModelStore = viewModelStore
 
-        val viewModelProvider = ViewModelProvider(
-            this,
-            ViewModelProvider.NewInstanceFactory()
-        )
+        val viewModelProvider = ViewModelProvider(this)
         activityModel = viewModelProvider.get(KEY_ACTIVITY_MODEL, TestViewModel::class.java)
         defaultActivityModel = viewModelProvider.get(TestViewModel::class.java)
+        androidModel = viewModelProvider.get(TestAndroidViewModel::class.java)
+        savedStateModel = viewModelProvider.get(TestSavedStateViewModel::class.java)
     }
 }
 
@@ -112,4 +122,21 @@
     override fun onCleared() {
         cleared = true
     }
-}
\ No newline at end of file
+}
+
+class TestAndroidViewModel(application: Application) : AndroidViewModel(application) {
+    var cleared = false
+
+    override fun onCleared() {
+        cleared = true
+    }
+}
+
+@Suppress("unused")
+class TestSavedStateViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() {
+    var cleared = false
+
+    override fun onCleared() {
+        cleared = true
+    }
+}
diff --git a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
index a596e73..cee2d27 100644
--- a/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
+++ b/activity/activity/src/main/java/androidx/activity/ComponentActivity.java
@@ -29,11 +29,14 @@
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.lifecycle.HasDefaultViewModelProviderFactory;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleEventObserver;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
 import androidx.lifecycle.ReportFragment;
+import androidx.lifecycle.SavedStateViewModelFactory;
+import androidx.lifecycle.ViewModelProvider;
 import androidx.lifecycle.ViewModelStore;
 import androidx.lifecycle.ViewModelStoreOwner;
 import androidx.savedstate.SavedStateRegistry;
@@ -50,6 +53,7 @@
 public class ComponentActivity extends androidx.core.app.ComponentActivity implements
         LifecycleOwner,
         ViewModelStoreOwner,
+        HasDefaultViewModelProviderFactory,
         SavedStateRegistryOwner,
         OnBackPressedDispatcherOwner {
 
@@ -64,6 +68,7 @@
 
     // Lazily recreated from NonConfigurationInstances by getViewModelStore()
     private ViewModelStore mViewModelStore;
+    private ViewModelProvider.Factory mDefaultFactory;
 
     private final OnBackPressedDispatcher mOnBackPressedDispatcher =
             new OnBackPressedDispatcher(new Runnable() {
@@ -273,6 +278,29 @@
     }
 
     /**
+     * {@inheritDoc}
+     *
+     * <p>The extras of {@link #getIntent()} when this is first called will be used as
+     * the defaults to any {@link androidx.lifecycle.SavedStateHandle} passed to a view model
+     * created using this factory.</p>
+     */
+    @NonNull
+    @Override
+    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+        if (getApplication() == null) {
+            throw new IllegalStateException("Your activity is not yet attached to the "
+                    + "Application instance. You can't request ViewModel before onCreate call.");
+        }
+        if (mDefaultFactory == null) {
+            mDefaultFactory = new SavedStateViewModelFactory(
+                    getApplication(),
+                    this,
+                    getIntent() != null ? getIntent().getExtras() : null);
+        }
+        return mDefaultFactory;
+    }
+
+    /**
      * Called when the activity has detected the user's press of the back
      * key. The {@link #getOnBackPressedDispatcher() OnBackPressedDispatcher} will be given a
      * chance to handle the back button before the default behavior of
diff --git a/ads/ads-identifier-provider/build.gradle b/ads/ads-identifier-provider/build.gradle
index 78b4ade..535bbde 100644
--- a/ads/ads-identifier-provider/build.gradle
+++ b/ads/ads-identifier-provider/build.gradle
@@ -27,7 +27,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation(AUTO_VALUE_ANNOTATIONS)
     annotationProcessor(AUTO_VALUE)
 
diff --git a/ads/ads-identifier/build.gradle b/ads/ads-identifier/build.gradle
index fed8afc..3ab81a6 100644
--- a/ads/ads-identifier/build.gradle
+++ b/ads/ads-identifier/build.gradle
@@ -27,11 +27,11 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation(AUTO_VALUE_ANNOTATIONS)
     annotationProcessor(AUTO_VALUE)
     api(GUAVA_LISTENABLE_FUTURE)
-    implementation(project(":concurrent:concurrent-futures"))
+    implementation("androidx.concurrent:concurrent-futures:1.0.0-beta01")
 
     implementation(project(":ads-identifier-common"))
 
diff --git a/animation/build.gradle b/animation/build.gradle
index 65781d0..1d1800e 100644
--- a/animation/build.gradle
+++ b/animation/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT, libs.exclude_for_espresso)
diff --git a/animation/integration-tests/testapp/build.gradle b/animation/integration-tests/testapp/build.gradle
index 82a6fe05..a9992a4 100644
--- a/animation/integration-tests/testapp/build.gradle
+++ b/animation/integration-tests/testapp/build.gradle
@@ -23,7 +23,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation(project(":animation"))
     implementation(project(":animation:testing"))
 
diff --git a/animation/testing/build.gradle b/animation/testing/build.gradle
index f33191e..ad98a4c 100644
--- a/animation/testing/build.gradle
+++ b/animation/testing/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation(project(":animation"))
     implementation(ANDROIDX_TEST_EXT_JUNIT)
     implementation(ANDROIDX_TEST_CORE)
diff --git a/appcompat/benchmark/build.gradle b/appcompat/benchmark/build.gradle
index 8ff9b65..962cb98 100644
--- a/appcompat/benchmark/build.gradle
+++ b/appcompat/benchmark/build.gradle
@@ -21,6 +21,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/appcompat/build.gradle b/appcompat/build.gradle
index 5ce2ab6..e18e0bd9 100644
--- a/appcompat/build.gradle
+++ b/appcompat/build.gradle
@@ -12,7 +12,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
 
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.cursoradapter:cursoradapter:1.0.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
diff --git a/asynclayoutinflater/build.gradle b/asynclayoutinflater/build.gradle
index 2c12378..3dcd2f0 100644
--- a/asynclayoutinflater/build.gradle
+++ b/asynclayoutinflater/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
 }
 
 androidx {
diff --git a/benchmark/benchmark/build.gradle b/benchmark/benchmark/build.gradle
index 23f8633..b540dcd 100644
--- a/benchmark/benchmark/build.gradle
+++ b/benchmark/benchmark/build.gradle
@@ -19,6 +19,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/benchmark/gradle-plugin/build.gradle b/benchmark/gradle-plugin/build.gradle
index 6ce036b..949c11a 100644
--- a/benchmark/gradle-plugin/build.gradle
+++ b/benchmark/gradle-plugin/build.gradle
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-
+import androidx.build.BuildServerConfigurationKt
 import androidx.build.CompilationTarget
 import androidx.build.LibraryGroups
 import androidx.build.LibraryVersions
@@ -70,6 +70,17 @@
 
 tasks["compileTestJava"].dependsOn generateSdkResource
 
+task buildOnServer(type: Copy) {
+  from {
+    def f = project.file("src/main/resources/scripts/lockClocks.sh")
+    if (!f.exists()) {
+        throw new GradleException(f.toString() + " does not exist")
+    }
+    return f
+  }
+  destinationDir BuildServerConfigurationKt.getDistributionDirectory(rootProject)
+}
+
 gradlePlugin {
     plugins {
         benchmark {
diff --git a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
index 7365bc8..1a57e4f9 100644
--- a/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
+++ b/benchmark/gradle-plugin/src/main/kotlin/androidx/benchmark/gradle/BenchmarkPlugin.kt
@@ -88,11 +88,17 @@
             }
         }
 
-        project.tasks.register("lockClocks", LockClocksTask::class.java).configure {
-            it.adbPath.set(extension.adbExecutable.absolutePath)
+        if (project.rootProject.tasks.findByName("lockClocks") == null) {
+            project.rootProject.tasks.register("lockClocks", LockClocksTask::class.java).configure {
+                it.adbPath.set(extension.adbExecutable.absolutePath)
+            }
         }
-        project.tasks.register("unlockClocks", UnlockClocksTask::class.java).configure {
-            it.adbPath.set(extension.adbExecutable.absolutePath)
+
+        if (project.rootProject.tasks.findByName("unlockClocks") == null) {
+            project.rootProject.tasks.register("unlockClocks", UnlockClocksTask::class.java)
+                .configure {
+                    it.adbPath.set(extension.adbExecutable.absolutePath)
+                }
         }
 
         val extensionVariants = when (extension) {
diff --git a/benchmark/integration-tests/startup-benchmark/build.gradle b/benchmark/integration-tests/startup-benchmark/build.gradle
index 4219241..80085a3 100644
--- a/benchmark/integration-tests/startup-benchmark/build.gradle
+++ b/benchmark/integration-tests/startup-benchmark/build.gradle
@@ -20,6 +20,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/biometric/build.gradle b/biometric/build.gradle
index e423137..e1dbcfe 100644
--- a/biometric/build.gradle
+++ b/biometric/build.gradle
@@ -10,7 +10,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.appcompat:appcompat:1.1.0-rc01")
-    api("androidx.core:core:1.1.0-rc02")
+    api("androidx.core:core:1.1.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
 }
 
diff --git a/browser/build.gradle b/browser/build.gradle
index 06018de..5dd3789 100644
--- a/browser/build.gradle
+++ b/browser/build.gradle
@@ -17,7 +17,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     api("androidx.annotation:annotation:1.1.0")
 
     implementation("androidx.collection:collection:1.1.0")
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 59996ce..c51fd30 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -58,11 +58,6 @@
     }
 }
 
-sourceSets {
-    main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin"
-    main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources"
-}
-
 dependencies {
     implementation build_libs.gradle
     implementation build_libs.error_prone_gradle
@@ -73,3 +68,18 @@
     testImplementation "junit:junit:4.12"
 }
 
+apply plugin: "java-gradle-plugin"
+
+sourceSets {
+    main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin"
+    main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources"
+}
+
+gradlePlugin {
+    plugins {
+        benchmark {
+            id = 'androidx.benchmark'
+            implementationClass = 'androidx.benchmark.gradle.BenchmarkPlugin'
+        }
+    }
+}
\ No newline at end of file
diff --git a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
index 8ab32de..35fedcb 100644
--- a/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/AndroidXPlugin.kt
@@ -16,8 +16,6 @@
 
 package androidx.build
 
-import androidx.benchmark.gradle.LockClocksTask
-import androidx.benchmark.gradle.UnlockClocksTask
 import androidx.build.SupportConfig.BENCHMARK_INSTRUMENTATION_RUNNER
 import androidx.build.SupportConfig.BUILD_TOOLS_VERSION
 import androidx.build.SupportConfig.COMPILE_SDK_VERSION
@@ -277,6 +275,7 @@
                         "verifyDependencyVersions" == task.name ||
                         "reportLibraryMetrics" == task.name ||
                         CREATE_STUB_API_JAR_TASK == task.name ||
+                        BUILD_ON_SERVER_TASK == task.name ||
                         ("lintDebug" == task.name &&
                         !project.rootProject.hasProperty(USE_MAX_DEP_VERSIONS))) {
                     buildOnServerTask.dependsOn(task)
@@ -315,14 +314,6 @@
             CheckSameVersionLibraryGroupsTask::class.java)
         buildOnServerTask.dependsOn(checkSameVersionLibraryGroupsTask)
 
-        val adbPath = "${getSdkPath(SupportConfig.getSupportRoot(project)).path}/platform-tools/adb"
-        tasks.register("lockClocks", LockClocksTask::class.java).configure {
-            it.adbPath.set(adbPath)
-        }
-        tasks.register("unlockClocks", UnlockClocksTask::class.java).configure {
-            it.adbPath.set(adbPath)
-        }
-
         AffectedModuleDetector.configure(gradle, this)
 
         // If useMaxDepVersions is set, iterate through all the project and substitute any androidx
diff --git a/buildSrc/src/main/kotlin/androidx/build/Jetify.kt b/buildSrc/src/main/kotlin/androidx/build/Jetify.kt
index 25b8e8b..ec84188 100644
--- a/buildSrc/src/main/kotlin/androidx/build/Jetify.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/Jetify.kt
@@ -30,6 +30,7 @@
     "m2repository/androidx/arch/**",
     "m2repository/androidx/arch/core/**",
     "m2repository/androidx/asynclayoutinflater/**",
+    "m2repository/androidx/benchmark/**",
     "m2repository/androidx/biometric/**",
     "m2repository/androidx/browser/**",
     "m2repository/androidx/camera/**",
diff --git a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
index b2af62a..9dacda3 100644
--- a/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/LibraryVersions.kt
@@ -58,7 +58,7 @@
     val ENTERPRISE = Version("1.0.0-alpha03")
     val EXIFINTERFACE = Version("1.1.0-beta02")
     val FRAGMENT = Version("1.2.0-alpha02")
-    val FUTURES = Version("1.0.0-beta02")
+    val FUTURES = Version("1.0.0-rc01")
     val GRIDLAYOUT = Version("1.1.0-alpha01")
     val HEIFWRITER = Version("1.1.0-alpha01")
     val INSPECTION = Version("1.0.0-alpha01")
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index 014e196..6c5bd2c 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -127,7 +127,7 @@
     prebuilts(LibraryGroups.WEBKIT, "1.1.0-alpha01")
     ignore(LibraryGroups.WORK.group, "work-gcm")
     ignore(LibraryGroups.WORK.group, "work-foreground")
-    prebuilts(LibraryGroups.WORK, "2.2.0-beta02")
+    prebuilts(LibraryGroups.WORK, "2.2.0-rc01")
     default(Ignore)
 }
 
diff --git a/camera/camera-camera2/build.gradle b/camera/camera-camera2/build.gradle
index 2a15464..b13de44 100644
--- a/camera/camera-camera2/build.gradle
+++ b/camera/camera-camera2/build.gradle
@@ -27,7 +27,7 @@
 dependencies {
     api(project(":camera:camera-core"))
 
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation("androidx.annotation:annotation:1.0.0")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(GUAVA_LISTENABLE_FUTURE)
diff --git a/camera/camera-core/build.gradle b/camera/camera-core/build.gradle
index d792fc0..b111e0d 100644
--- a/camera/camera-core/build.gradle
+++ b/camera/camera-core/build.gradle
@@ -29,7 +29,7 @@
     api("androidx.lifecycle:lifecycle-common:2.0.0")
     implementation("androidx.exifinterface:exifinterface:1.0.0")
     implementation("androidx.annotation:annotation:1.0.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(ARCH_LIFECYCLE_LIVEDATA)
 
diff --git a/camera/camera-testing/build.gradle b/camera/camera-testing/build.gradle
index 396ab3c..2be49b7 100644
--- a/camera/camera-testing/build.gradle
+++ b/camera/camera-testing/build.gradle
@@ -30,7 +30,7 @@
     implementation("androidx.annotation:annotation:1.0.0")
     implementation(GUAVA_LISTENABLE_FUTURE)
     implementation(project(":camera:camera-core"))
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(JUNIT)
 }
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/MainActivity.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/MainActivity.kt
index 63105dd..6dc6ca7 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/MainActivity.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/MainActivity.kt
@@ -117,7 +117,7 @@
         super.onCreate(savedInstanceState)
         setContentView(R.layout.activity_main)
 
-        camViewModel = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
+        camViewModel = ViewModelProvider(this)
             .get(CamViewModel::class.java)
         cameraParams = camViewModel.getCameraParams()
         deviceInfo = DeviceInfo()
diff --git a/car/moderator/build.gradle b/car/moderator/build.gradle
index 4d19dbd..bd7370d 100644
--- a/car/moderator/build.gradle
+++ b/car/moderator/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/compose/compose-runtime/compose-runtime-benchmark/build.gradle b/compose/compose-runtime/compose-runtime-benchmark/build.gradle
index 07a7246..dcb32f6 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/build.gradle
+++ b/compose/compose-runtime/compose-runtime-benchmark/build.gradle
@@ -24,6 +24,7 @@
     id("com.android.library")
     id("AndroidXUiPlugin")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 android {
diff --git a/concurrent/futures/api/1.0.0-rc01.txt b/concurrent/futures/api/1.0.0-rc01.txt
new file mode 100644
index 0000000..beb76bd
--- /dev/null
+++ b/concurrent/futures/api/1.0.0-rc01.txt
@@ -0,0 +1,21 @@
+// Signature format: 3.0
+package androidx.concurrent.futures {
+
+  public final class CallbackToFutureAdapter {
+    method public static <T> com.google.common.util.concurrent.ListenableFuture<T!> getFuture(androidx.concurrent.futures.CallbackToFutureAdapter.Resolver<T!>);
+  }
+
+  public static final class CallbackToFutureAdapter.Completer<T> {
+    method public void addCancellationListener(Runnable, java.util.concurrent.Executor);
+    method protected void finalize();
+    method public boolean set(T!);
+    method public boolean setCancelled();
+    method public boolean setException(Throwable);
+  }
+
+  public static interface CallbackToFutureAdapter.Resolver<T> {
+    method public Object? attachCompleter(androidx.concurrent.futures.CallbackToFutureAdapter.Completer<T!>) throws java.lang.Exception;
+  }
+
+}
+
diff --git a/concurrent/futures/api/restricted_1.0.0-rc01.txt b/concurrent/futures/api/restricted_1.0.0-rc01.txt
new file mode 100644
index 0000000..6dabf0b
--- /dev/null
+++ b/concurrent/futures/api/restricted_1.0.0-rc01.txt
@@ -0,0 +1,45 @@
+// Signature format: 3.0
+package androidx.concurrent.futures {
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public abstract class AbstractResolvableFuture<V> implements com.google.common.util.concurrent.ListenableFuture<V> {
+    ctor protected AbstractResolvableFuture();
+    method public final void addListener(Runnable!, java.util.concurrent.Executor!);
+    method protected void afterDone();
+    method public final boolean cancel(boolean);
+    method public final V! get(long, java.util.concurrent.TimeUnit!) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException;
+    method public final V! get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException;
+    method protected void interruptTask();
+    method public final boolean isCancelled();
+    method public final boolean isDone();
+    method protected String? pendingToString();
+    method protected boolean set(V?);
+    method protected boolean setException(Throwable!);
+    method protected boolean setFuture(com.google.common.util.concurrent.ListenableFuture<? extends V>!);
+    method protected final boolean wasInterrupted();
+  }
+
+  public final class CallbackToFutureAdapter {
+    method public static <T> com.google.common.util.concurrent.ListenableFuture<T!> getFuture(androidx.concurrent.futures.CallbackToFutureAdapter.Resolver<T!>);
+  }
+
+  public static final class CallbackToFutureAdapter.Completer<T> {
+    method public void addCancellationListener(Runnable, java.util.concurrent.Executor);
+    method protected void finalize();
+    method public boolean set(T!);
+    method public boolean setCancelled();
+    method public boolean setException(Throwable);
+  }
+
+  public static interface CallbackToFutureAdapter.Resolver<T> {
+    method public Object? attachCompleter(androidx.concurrent.futures.CallbackToFutureAdapter.Completer<T!>) throws java.lang.Exception;
+  }
+
+  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ResolvableFuture<V> extends androidx.concurrent.futures.AbstractResolvableFuture<V> {
+    method public static <V> androidx.concurrent.futures.ResolvableFuture<V!>! create();
+    method public boolean set(V?);
+    method public boolean setException(Throwable!);
+    method public boolean setFuture(com.google.common.util.concurrent.ListenableFuture<? extends V>!);
+  }
+
+}
+
diff --git a/content/build.gradle b/content/build.gradle
index cafb452..4a27186 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(JUNIT)
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
index ae2a733..6050e84 100644
--- a/coordinatorlayout/build.gradle
+++ b/coordinatorlayout/build.gradle
@@ -11,7 +11,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     // TODO: change to 1.1.0-alpha04 after release
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.customview:customview:1.0.0")
 
diff --git a/core/core/api/restricted_1.2.0-alpha03.txt b/core/core/api/restricted_1.2.0-alpha03.txt
index 0693bb2..138fb9f 100644
--- a/core/core/api/restricted_1.2.0-alpha03.txt
+++ b/core/core/api/restricted_1.2.0-alpha03.txt
@@ -140,13 +140,13 @@
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component {
     ctor public ComponentActivity();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean superDispatchKeyEvent(android.view.KeyEvent!);
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
-    ctor public ComponentActivity.ExtraData();
+  @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
+    ctor @Deprecated public ComponentActivity.ExtraData();
   }
 
   @RequiresApi(api=28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class CoreComponentFactory extends android.app.AppComponentFactory {
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 0693bb2..138fb9f 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -140,13 +140,13 @@
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class ComponentActivity extends android.app.Activity implements androidx.core.view.KeyEventDispatcher.Component {
     ctor public ComponentActivity();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public <T extends androidx.core.app.ComponentActivity.ExtraData> T! getExtraData(Class<T!>!);
+    method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public void putExtraData(androidx.core.app.ComponentActivity.ExtraData!);
     method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public boolean superDispatchKeyEvent(android.view.KeyEvent!);
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
-    ctor public ComponentActivity.ExtraData();
+  @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public static class ComponentActivity.ExtraData {
+    ctor @Deprecated public ComponentActivity.ExtraData();
   }
 
   @RequiresApi(api=28) @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class CoreComponentFactory extends android.app.AppComponentFactory {
diff --git a/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java b/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
index cda201b..98f553f 100644
--- a/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
+++ b/core/core/src/androidTest/java/androidx/core/app/ComponentActivityTest.java
@@ -27,6 +27,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@SuppressWarnings("deprecation")
 @RunWith(AndroidJUnit4.class)
 @LargeTest
 public class ComponentActivityTest extends BaseInstrumentationTestCase<TestComponentActivity> {
@@ -54,10 +55,10 @@
         assertEquals(mTestExtraData, mComponentActivity.getExtraData(TestExtraData.class));
     }
 
-    public class NeverAddedExtraData extends ComponentActivity.ExtraData {
+    private class NeverAddedExtraData extends ComponentActivity.ExtraData {
     }
 
-    public class TestExtraData extends ComponentActivity.ExtraData {
+    private class TestExtraData extends ComponentActivity.ExtraData {
     }
 }
 
diff --git a/core/core/src/androidTest/java/androidx/core/os/TraceCompatTest.java b/core/core/src/androidTest/java/androidx/core/os/TraceCompatTest.java
index d36b79a..5f229c4 100644
--- a/core/core/src/androidTest/java/androidx/core/os/TraceCompatTest.java
+++ b/core/core/src/androidTest/java/androidx/core/os/TraceCompatTest.java
@@ -21,15 +21,18 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import android.app.UiAutomation;
+import android.os.Build;
 import android.os.ParcelFileDescriptor;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.filters.LargeTest;
 import androidx.test.filters.SdkSuppress;
 import androidx.test.filters.SmallTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -50,12 +53,23 @@
         mByteArrayOutputStream = new ByteArrayOutputStream();
     }
 
+    @After
+    public void stopAtrace() throws IOException {
+        // Since API 23, 'async_stop' will work. On lower API levels it was broken (see aosp/157142)
+        if (Build.VERSION.SDK_INT >= 23) {
+            executeCommand("atrace --async_stop");
+        } else {
+            // Ensure tracing is not currently running by performing a short synchronous trace.
+            executeCommand("atrace -t 0");
+        }
+    }
+
     @Test
     public void beginAndEndSection() throws IOException {
         startTrace();
         TraceCompat.beginSection("beginAndEndSection");
         TraceCompat.endSection();
-        endTrace();
+        dumpTrace();
 
         assertTraceContains("tracing_mark_write:\\ B\\|.*\\|beginAndEndSection");
         assertTraceContains("tracing_mark_write:\\ E");
@@ -66,7 +80,7 @@
         startTrace();
         TraceCompat.beginAsyncSection("beginAndEndSectionAsync", /*cookie=*/5099);
         TraceCompat.endAsyncSection("beginAndEndSectionAsync", /*cookie=*/5099);
-        endTrace();
+        dumpTrace();
 
         assertTraceContains("tracing_mark_write:\\ S\\|.*\\|beginAndEndSectionAsync\\|5099");
         assertTraceContains("tracing_mark_write:\\ F\\|.*\\|beginAndEndSectionAsync\\|5099");
@@ -78,7 +92,7 @@
         TraceCompat.setCounter("counterName", 42);
         TraceCompat.setCounter("counterName", 47);
         TraceCompat.setCounter("counterName", 9787);
-        endTrace();
+        dumpTrace();
 
         assertTraceContains("tracing_mark_write:\\ C\\|.*\\|counterName\\|42");
         assertTraceContains("tracing_mark_write:\\ C\\|.*\\|counterName\\|47");
@@ -89,7 +103,7 @@
     public void isEnabledDuringTrace() throws IOException {
         startTrace();
         boolean enabled = TraceCompat.isEnabled();
-        endTrace();
+        dumpTrace();
 
         assertThat(enabled).isTrue();
     }
@@ -101,39 +115,45 @@
     }
 
     private void startTrace() throws IOException {
-        UiAutomation automation = InstrumentationRegistry.getInstrumentation()
-                .getUiAutomation();
         String processName =
                 ApplicationProvider.getApplicationContext().getApplicationInfo().processName;
 
         // Write the "async_start" status to the byte array to ensure atrace has fully started
         // before issuing any trace commands. This will also capture any errors that occur during
         // start so they can be added to the assertion error's message.
-        writeDataToByteStream(automation.executeShellCommand(
-                String.format("atrace --async_start -b %d -a %s", TRACE_BUFFER_SIZE,
-                        processName)),
+        executeCommand(
+                String.format("atrace --async_start -b %d -a %s", TRACE_BUFFER_SIZE, processName));
+    }
+
+    private void dumpTrace() throws IOException {
+        // On older versions of atrace, the -b option is required when dumping the trace so the
+        // trace buffer doesn't get cleared before being dumped.
+        executeCommand(
+                String.format("atrace --async_dump -b %d", TRACE_BUFFER_SIZE),
                 mByteArrayOutputStream);
     }
 
-    private void endTrace() throws IOException {
+    private static void executeCommand(@NonNull String command) throws IOException {
+        executeCommand(command, null);
+    }
+
+    private static void executeCommand(@NonNull String command,
+            @Nullable ByteArrayOutputStream outputStream) throws IOException {
         UiAutomation automation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        writeDataToByteStream(automation.executeShellCommand("atrace --async_stop"),
-                mByteArrayOutputStream);
-    }
 
-    private void writeDataToByteStream(ParcelFileDescriptor pfDescriptor,
-            ByteArrayOutputStream outputStream) throws IOException {
-        try (ParcelFileDescriptor.AutoCloseInputStream inputStream =
+        try (ParcelFileDescriptor pfDescriptor = automation.executeShellCommand(command);
+             ParcelFileDescriptor.AutoCloseInputStream inputStream =
                      new ParcelFileDescriptor.AutoCloseInputStream(
                              pfDescriptor)) {
             byte[] buffer = new byte[1024];
 
             int length;
             while ((length = inputStream.read(buffer)) >= 0) {
-                outputStream.write(buffer, 0, length);
+                if (outputStream != null) {
+                    outputStream.write(buffer, 0, length);
+                }
             }
         }
-
     }
 
     private void assertTraceContains(@NonNull String contentRegex) {
diff --git a/core/core/src/main/java/androidx/core/app/ComponentActivity.java b/core/core/src/main/java/androidx/core/app/ComponentActivity.java
index 9672a78..90d61c4 100644
--- a/core/core/src/main/java/androidx/core/app/ComponentActivity.java
+++ b/core/core/src/main/java/androidx/core/app/ComponentActivity.java
@@ -43,6 +43,7 @@
      *
      * <p>Note that these objects are not retained across configuration changes</p>
      */
+    @SuppressWarnings("deprecation")
     private SimpleArrayMap<Class<? extends ExtraData>, ExtraData> mExtraDataMap =
             new SimpleArrayMap<>();
 
@@ -54,8 +55,11 @@
      *
      * @see #getExtraData
      * @hide
+     * @deprecated Use {@link View#setTag(int, Object)} with the window's decor view.
      */
+    @SuppressWarnings("deprecation")
     @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Deprecated
     public void putExtraData(ExtraData extraData) {
         mExtraDataMap.put(extraData.getClass(), extraData);
     }
@@ -65,9 +69,11 @@
      *
      * @see #putExtraData
      * @hide
+     * @deprecated Use {@link View#getTag(int)} with the window's decor view.
      */
     @RestrictTo(LIBRARY_GROUP_PREFIX)
-    @SuppressWarnings("unchecked")
+    @SuppressWarnings({"unchecked", "deprecation"})
+    @Deprecated
     public <T extends ExtraData> T getExtraData(Class<T> extraDataClass) {
         return (T) mExtraDataMap.get(extraDataClass);
     }
@@ -101,8 +107,12 @@
 
     /**
      * @hide
+     * @deprecated Store the object you want to save directly by using
+     * {@link View#setTag(int, Object)} with the window's decor view.
      */
+    @SuppressWarnings("DeprecatedIsStillUsed")
     @RestrictTo(LIBRARY_GROUP_PREFIX)
+    @Deprecated
     public static class ExtraData {
     }
 }
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index fe7bd58..6ad3e31 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 0b811cb..4e13514 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -22,7 +22,7 @@
     // treats this as local jar and package it inside the aar.
     api files(configurations.repackage)
 
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation(project(':collection:collection'))
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/fragment/fragment-ktx/src/main/java/androidx/fragment/app/FragmentViewModelLazy.kt b/fragment/fragment-ktx/src/main/java/androidx/fragment/app/FragmentViewModelLazy.kt
index f67b19a..b9bf7b5 100644
--- a/fragment/fragment-ktx/src/main/java/androidx/fragment/app/FragmentViewModelLazy.kt
+++ b/fragment/fragment-ktx/src/main/java/androidx/fragment/app/FragmentViewModelLazy.kt
@@ -20,7 +20,6 @@
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelLazy
 import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
 import androidx.lifecycle.ViewModelProvider.Factory
 import androidx.lifecycle.ViewModelStore
 import androidx.lifecycle.ViewModelStoreOwner
@@ -61,7 +60,9 @@
 /**
  * Returns a property delegate to access parent activity's [ViewModel],
  * if [factoryProducer] is specified then [ViewModelProvider.Factory]
- * returned by it will be used to create [ViewModel] first time.
+ * returned by it will be used to create [ViewModel] first time. Otherwise, the activity's
+ * [androidx.activity.ComponentActivity.getDefaultViewModelProviderFactory](default factory)
+ * will be used.
  *
  * ```
  * class MyFragment : Fragment() {
@@ -75,7 +76,8 @@
 @MainThread
 inline fun <reified VM : ViewModel> Fragment.activityViewModels(
     noinline factoryProducer: (() -> Factory)? = null
-) = createViewModelLazy(VM::class, { requireActivity().viewModelStore }, factoryProducer)
+) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
+    factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })
 
 /**
  * Helper method for creation of [ViewModelLazy], that resolves `null` passed as [factoryProducer]
@@ -88,10 +90,7 @@
     factoryProducer: (() -> Factory)? = null
 ): Lazy<VM> {
     val factoryPromise = factoryProducer ?: {
-        val application = activity?.application ?: throw IllegalStateException(
-            "ViewModel can be accessed only when Fragment is attached"
-        )
-        AndroidViewModelFactory.getInstance(application)
+        defaultViewModelProviderFactory
     }
     return ViewModelLazy(viewModelClass, storeProducer, factoryPromise)
-}
+}
\ No newline at end of file
diff --git a/fragment/fragment/api/1.2.0-alpha02.txt b/fragment/fragment/api/1.2.0-alpha02.txt
index 346d9b7..672cb24 100644
--- a/fragment/fragment/api/1.2.0-alpha02.txt
+++ b/fragment/fragment/api/1.2.0-alpha02.txt
@@ -25,7 +25,7 @@
     field public static final int STYLE_NO_TITLE = 1; // 0x1
   }
 
-  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
     ctor public Fragment();
     ctor @ContentView public Fragment(@LayoutRes int);
     method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
@@ -36,6 +36,7 @@
     method public final android.os.Bundle? getArguments();
     method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
     method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public Object? getEnterTransition();
     method public Object? getExitTransition();
     method public final androidx.fragment.app.FragmentManager? getFragmentManager();
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 346d9b7..672cb24 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -25,7 +25,7 @@
     field public static final int STYLE_NO_TITLE = 1; // 0x1
   }
 
-  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
     ctor public Fragment();
     ctor @ContentView public Fragment(@LayoutRes int);
     method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
@@ -36,6 +36,7 @@
     method public final android.os.Bundle? getArguments();
     method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
     method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public Object? getEnterTransition();
     method public Object? getExitTransition();
     method public final androidx.fragment.app.FragmentManager? getFragmentManager();
diff --git a/fragment/fragment/api/restricted_1.2.0-alpha02.txt b/fragment/fragment/api/restricted_1.2.0-alpha02.txt
index 7b475f2..b1f0d5f 100644
--- a/fragment/fragment/api/restricted_1.2.0-alpha02.txt
+++ b/fragment/fragment/api/restricted_1.2.0-alpha02.txt
@@ -26,7 +26,7 @@
     field public static final int STYLE_NO_TITLE = 1; // 0x1
   }
 
-  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
     ctor public Fragment();
     ctor @ContentView public Fragment(@LayoutRes int);
     method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
@@ -37,6 +37,7 @@
     method public final android.os.Bundle? getArguments();
     method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
     method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public Object? getEnterTransition();
     method public Object? getExitTransition();
     method public final androidx.fragment.app.FragmentManager? getFragmentManager();
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 7b475f2..b1f0d5f 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -26,7 +26,7 @@
     field public static final int STYLE_NO_TITLE = 1; // 0x1
   }
 
-  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
+  public class Fragment implements android.content.ComponentCallbacks androidx.lifecycle.HasDefaultViewModelProviderFactory androidx.lifecycle.LifecycleOwner androidx.savedstate.SavedStateRegistryOwner android.view.View.OnCreateContextMenuListener androidx.lifecycle.ViewModelStoreOwner {
     ctor public Fragment();
     ctor @ContentView public Fragment(@LayoutRes int);
     method public void dump(String, java.io.FileDescriptor?, java.io.PrintWriter, String![]?);
@@ -37,6 +37,7 @@
     method public final android.os.Bundle? getArguments();
     method public final androidx.fragment.app.FragmentManager getChildFragmentManager();
     method public android.content.Context? getContext();
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
     method public Object? getEnterTransition();
     method public Object? getExitTransition();
     method public final androidx.fragment.app.FragmentManager? getFragmentManager();
diff --git a/fragment/fragment/build.gradle b/fragment/fragment/build.gradle
index c199145..777cb59 100644
--- a/fragment/fragment/build.gradle
+++ b/fragment/fragment/build.gradle
@@ -18,13 +18,14 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     api("androidx.collection:collection:1.1.0")
     api("androidx.viewpager:viewpager:1.0.0")
     api("androidx.loader:loader:1.0.0")
     api(project(":activity:activity"))
     api(project(":lifecycle:lifecycle-livedata-core"))
     api(project(":lifecycle:lifecycle-viewmodel"))
+    api(project(":lifecycle:lifecycle-viewmodel-savedstate"))
 
     androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
index eabe5c4..021ea3c 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentContainerViewTest.kt
@@ -35,6 +35,7 @@
 import androidx.testutils.waitForExecution
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Assert.fail
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -46,10 +47,12 @@
 class FragmentContainerViewTest {
     @get:Rule
     var activityRule = ActivityTestRule(FragmentTestActivity::class.java)
+    lateinit var context: Context
 
     @Before
     fun setupContainer() {
         activityRule.setContentView(R.layout.fragment_container_view)
+        context = activityRule.activity.applicationContext
     }
 
     @Test
@@ -99,8 +102,6 @@
     @SdkSuppress(minSdkVersion = 29) // WindowInsets.Builder requires API 29
     @Test
     fun windowInsetsDispatchToChildren() {
-        val context = activityRule.activity.applicationContext
-
         val parentView = FragmentContainerView(context)
         val childView = FragmentContainerView(context)
 
@@ -118,6 +119,8 @@
             insets
         }
 
+        childView.setTag(R.id.fragment_container_view_tag, Fragment())
+
         parentView.addView(childView)
         parentView.dispatchApplyWindowInsets(sentInsets)
 
@@ -125,18 +128,63 @@
     }
 
     @Test
-    fun removeViewAt() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
+    fun addView() {
+        val fm = activityRule.activity.supportFragmentManager
 
-        val childView1 = FragmentContainerView(context)
+        val view = View(context)
+        val fragment = Fragment()
+        fragment.mView = view
+
+        fm.setViewTag(fragment)
+
+        val fragmentContainerView = FragmentContainerView(context)
+
+        assertWithMessage("FragmentContainerView should have no child views")
+            .that(fragmentContainerView.childCount).isEqualTo(0)
+
+        fragmentContainerView.addView(view)
+
+        assertWithMessage("FragmentContainerView should have one child view")
+            .that(fragmentContainerView.childCount).isEqualTo(1)
+    }
+
+    @Test
+    fun addViewNotAssociatedWithFragment() {
+        val view = View(context)
+
+        try {
+            FragmentContainerView(context).addView(view, 0, null)
+            fail("View without a Fragment added to FragmentContainerView should throw an exception")
+        } catch (e: IllegalStateException) {
+            assertThat(e)
+                .hasMessageThat().contains(
+                    "Views added to a FragmentContainerView must be associated with a Fragment. " +
+                            "View " + view + " is not associated with a Fragment."
+                )
+        }
+    }
+
+    @Test
+    fun addViewInLayoutNotAssociatedWithFragment() {
+        val view = View(context)
+
+        try {
+            FragmentContainerView(context).addViewInLayout(view, 0, null, false)
+            fail("View without a Fragment added to FragmentContainerView should throw an exception")
+        } catch (e: IllegalStateException) {
+            assertThat(e)
+                .hasMessageThat().contains(
+                    "Views added to a FragmentContainerView must be associated with a Fragment. " +
+                            "View " + view + " is not associated with a Fragment."
+                )
+        }
+    }
+
+    @Test
+    fun removeViewAt() {
         val childView2 = FragmentContainerView(context)
 
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(FragmentContainerView(context), childView2)
 
         view.removeViewAt(0)
 
@@ -146,17 +194,10 @@
 
     @Test
     fun removeViewInLayout() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
         val childView1 = FragmentContainerView(context)
         val childView2 = FragmentContainerView(context)
 
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(childView1, childView2)
 
         view.removeViewInLayout(childView1)
 
@@ -166,17 +207,10 @@
 
     @Test
     fun removeView() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
         val childView1 = FragmentContainerView(context)
         val childView2 = FragmentContainerView(context)
 
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(childView1, childView2)
 
         view.removeView(childView1)
 
@@ -185,17 +219,10 @@
 
     @Test
     fun removeViews() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
-        val childView1 = FragmentContainerView(context)
-        val childView2 = FragmentContainerView(context)
-
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(
+            FragmentContainerView(context),
+            FragmentContainerView(context)
+        )
 
         view.removeViews(1, 1)
 
@@ -204,17 +231,10 @@
 
     @Test
     fun removeViewsInLayout() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
-        val childView1 = FragmentContainerView(context)
-        val childView2 = FragmentContainerView(context)
-
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(
+            FragmentContainerView(context),
+            FragmentContainerView(context)
+        )
 
         view.removeViewsInLayout(1, 1)
 
@@ -223,17 +243,10 @@
 
     @Test
     fun removeAllViewsInLayout() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
-        val childView1 = FragmentContainerView(context)
-        val childView2 = FragmentContainerView(context)
-
-        view.addView(childView1)
-        view.addView(childView2)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        val view = setupRemoveTestsView(
+            FragmentContainerView(context),
+            FragmentContainerView(context)
+        )
 
         view.removeAllViewsInLayout()
 
@@ -243,22 +256,37 @@
     // removeDetachedView should not actually remove the view
     @Test
     fun removeDetachedView() {
-        val context = activityRule.activity.applicationContext
-        val view = FragmentContainerView(context)
-
         val childView1 = FragmentContainerView(context)
         val childView2 = FragmentContainerView(context)
 
+        val view = setupRemoveTestsView(childView1, childView2)
+
+        view.removeDetachedView(childView1, false)
+
+        assertThat(view.childCount).isEqualTo(2)
+        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+    }
+
+    private fun setupRemoveTestsView(
+        childView1: FragmentContainerView,
+        childView2: FragmentContainerView
+    ): FragmentContainerView {
+        val view = FragmentContainerView(context)
+        val fragment1 = Fragment()
+        val fragment2 = Fragment()
+
+        fragment1.mView = childView1
+        fragment2.mView = childView2
+
+        childView1.setTag(R.id.fragment_container_view_tag, fragment1)
+        childView2.setTag(R.id.fragment_container_view_tag, fragment2)
+
         view.addView(childView1)
         view.addView(childView2)
 
         assertThat(view.childCount).isEqualTo(2)
         assertThat(view.getChildAt(1)).isEqualTo(childView2)
-
-        view.removeDetachedView(childView1, false)
-
-        assertThat(view.childCount).isEqualTo(2)
-        assertThat(view.getChildAt(1)).isEqualTo(childView2)
+        return view
     }
 
     // Disappearing child views should be drawn first before other child views.
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
index 28e73e2..3edf294 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTest.kt
@@ -108,20 +108,32 @@
             val fragmentModel = withActivity {
                 getFragment(ViewModelActivity.FRAGMENT_TAG_1).fragmentModel
             }
+            val fragmentAndroidModel = withActivity {
+                getFragment(ViewModelActivity.FRAGMENT_TAG_1).androidModel
+            }
+            val fragmentSavedStateAndroidModel = withActivity {
+                getFragment(ViewModelActivity.FRAGMENT_TAG_1).savedStateModel
+            }
             val backStackFragmentModel = withActivity {
                 getFragment(ViewModelActivity.FRAGMENT_TAG_BACK_STACK).fragmentModel
             }
             assertThat(fragmentModel.cleared).isFalse()
+            assertThat(fragmentAndroidModel.cleared).isFalse()
+            assertThat(fragmentSavedStateAndroidModel.cleared).isFalse()
             assertThat(backStackFragmentModel.cleared).isFalse()
 
             recreate()
             // recreate shouldn't clear the ViewModels
             assertThat(fragmentModel.cleared).isFalse()
+            assertThat(fragmentAndroidModel.cleared).isFalse()
+            assertThat(fragmentSavedStateAndroidModel.cleared).isFalse()
             assertThat(backStackFragmentModel.cleared).isFalse()
 
             moveToState(Lifecycle.State.DESTROYED)
             // But destroying the Activity should
             assertThat(fragmentModel.cleared).isTrue()
+            assertThat(fragmentAndroidModel.cleared).isTrue()
+            assertThat(fragmentSavedStateAndroidModel.cleared).isTrue()
             assertThat(backStackFragmentModel.cleared).isTrue()
         }
     }
@@ -134,10 +146,7 @@
                     supportFragmentManager.beginTransaction().add(it, "temp").commitNow()
                 }
             }
-            val viewModelProvider = ViewModelProvider(
-                fragment,
-                ViewModelProvider.NewInstanceFactory()
-            )
+            val viewModelProvider = ViewModelProvider(fragment)
             val vm = viewModelProvider.get(TestViewModel::class.java)
             assertThat(vm.cleared).isFalse()
             onActivity { activity ->
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTestInTransaction.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTestInTransaction.kt
index 03804cc..f281002 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTestInTransaction.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ViewModelTestInTransaction.kt
@@ -20,7 +20,6 @@
 import androidx.fragment.app.test.EmptyFragmentTestActivity
 import androidx.fragment.app.test.TestViewModel
 import androidx.lifecycle.ViewModelProvider
-import androidx.lifecycle.ViewModelStoreOwner
 import androidx.test.annotation.UiThreadTest
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
@@ -43,7 +42,7 @@
         val activity = activityRule.activity
         val fragment = TestFragment()
         activity.supportFragmentManager.beginTransaction().add(fragment, "tag").commitNow()
-        val viewModelProvider = ViewModelProvider(activity, ViewModelProvider.NewInstanceFactory())
+        val viewModelProvider = ViewModelProvider(activity)
         val viewModel = viewModelProvider.get(TestViewModel::class.java)
         assertThat(viewModel).isSameInstanceAs(fragment.viewModel)
     }
@@ -65,7 +64,7 @@
             super.onCreate(savedInstanceState)
             val fragment = TestFragment()
             childFragmentManager.beginTransaction().add(fragment, "tag").commitNow()
-            val viewModelProvider = ViewModelProvider(this, ViewModelProvider.NewInstanceFactory())
+            val viewModelProvider = ViewModelProvider(this)
             val viewModel = viewModelProvider.get(TestViewModel::class.java)
             assertThat(viewModel).isSameInstanceAs(fragment.viewModel)
             executed = true
@@ -79,10 +78,7 @@
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             val parentFragment = parentFragment
-            val provider = ViewModelProvider(
-                (parentFragment ?: requireActivity()) as ViewModelStoreOwner,
-                ViewModelProvider.NewInstanceFactory()
-            )
+            val provider = ViewModelProvider(parentFragment ?: requireActivity())
             viewModel = provider.get(TestViewModel::class.java)
             assertThat(viewModel).isNotNull()
         }
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/ViewModelActivity.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/ViewModelActivity.kt
index a058649..b63f54d 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/ViewModelActivity.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/ViewModelActivity.kt
@@ -16,10 +16,14 @@
 
 package androidx.fragment.app.test
 
+import android.app.Application
 import android.os.Bundle
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
 import androidx.fragment.test.R
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.ViewModelStore
 
@@ -48,10 +52,7 @@
                 .commit()
         }
 
-        val viewModelProvider = ViewModelProvider(
-            this,
-            ViewModelProvider.NewInstanceFactory()
-        )
+        val viewModelProvider = ViewModelProvider(this)
         activityModel = viewModelProvider.get(KEY_ACTIVITY_MODEL, TestViewModel::class.java)
         defaultActivityModel = viewModelProvider.get(TestViewModel::class.java)
     }
@@ -60,26 +61,41 @@
         lateinit var fragmentModel: TestViewModel
         lateinit var activityModel: TestViewModel
         lateinit var defaultActivityModel: TestViewModel
+        lateinit var androidModel: TestAndroidViewModel
+        lateinit var savedStateModel: TestSavedStateViewModel
 
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
-            val viewModelProvider = ViewModelProvider(
-                this,
-                ViewModelProvider.NewInstanceFactory()
-            )
+            val viewModelProvider = ViewModelProvider(this)
             fragmentModel = viewModelProvider.get(
                 KEY_FRAGMENT_MODEL,
                 TestViewModel::class.java
             )
-            val activityViewModelProvider = ViewModelProvider(
-                requireActivity(),
-                ViewModelProvider.NewInstanceFactory()
-            )
+            val activityViewModelProvider = ViewModelProvider(requireActivity())
             activityModel = activityViewModelProvider.get(
                 ViewModelActivity.KEY_ACTIVITY_MODEL,
                 TestViewModel::class.java
             )
             defaultActivityModel = activityViewModelProvider.get(TestViewModel::class.java)
+            androidModel = viewModelProvider.get(TestAndroidViewModel::class.java)
+            savedStateModel = viewModelProvider.get(TestSavedStateViewModel::class.java)
+        }
+    }
+
+    class TestAndroidViewModel(application: Application) : AndroidViewModel(application) {
+        var cleared = false
+
+        override fun onCleared() {
+            cleared = true
+        }
+    }
+
+    @Suppress("unused")
+    class TestSavedStateViewModel(val savedStateHandle: SavedStateHandle) : ViewModel() {
+        var cleared = false
+
+        override fun onCleared() {
+            cleared = true
         }
     }
 
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
index f6efea6..4dc499c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -59,12 +59,15 @@
 import androidx.core.app.SharedElementCallback;
 import androidx.core.util.DebugUtils;
 import androidx.core.view.LayoutInflaterCompat;
+import androidx.lifecycle.HasDefaultViewModelProviderFactory;
 import androidx.lifecycle.Lifecycle;
 import androidx.lifecycle.LifecycleEventObserver;
 import androidx.lifecycle.LifecycleOwner;
 import androidx.lifecycle.LifecycleRegistry;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.SavedStateViewModelFactory;
+import androidx.lifecycle.ViewModelProvider;
 import androidx.lifecycle.ViewModelStore;
 import androidx.lifecycle.ViewModelStoreOwner;
 import androidx.loader.app.LoaderManager;
@@ -94,7 +97,7 @@
  *
  */
 public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener, LifecycleOwner,
-        ViewModelStoreOwner, SavedStateRegistryOwner {
+        ViewModelStoreOwner, HasDefaultViewModelProviderFactory, SavedStateRegistryOwner {
 
     static final Object USE_DEFAULT_TRANSITION = new Object();
 
@@ -267,6 +270,8 @@
     @Nullable FragmentViewLifecycleOwner mViewLifecycleOwner;
     MutableLiveData<LifecycleOwner> mViewLifecycleOwnerLiveData = new MutableLiveData<>();
 
+    private ViewModelProvider.Factory mDefaultFactory;
+
     SavedStateRegistryController mSavedStateRegistryController;
 
     @LayoutRes
@@ -365,6 +370,28 @@
         return mFragmentManager.getViewModelStore(this);
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>The {@link #getArguments() Fragment's arguments} when this is first called will be used
+     * as the defaults to any {@link androidx.lifecycle.SavedStateHandle} passed to a view model
+     * created using this factory.</p>
+     */
+    @NonNull
+    @Override
+    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+        if (mFragmentManager == null) {
+            throw new IllegalStateException("Can't access ViewModels from detached fragment");
+        }
+        if (mDefaultFactory == null) {
+            mDefaultFactory = new SavedStateViewModelFactory(
+                    requireActivity().getApplication(),
+                    this,
+                    getArguments());
+        }
+        return mDefaultFactory;
+    }
+
     @NonNull
     @Override
     public final SavedStateRegistry getSavedStateRegistry() {
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.java
index f59c067..898a17c 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentContainerView.java
@@ -19,8 +19,11 @@
 import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.os.Bundle;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
 
@@ -50,6 +53,10 @@
  * <p>FragmentContainerView should not be used as a replacement for other ViewGroups (FrameLayout,
  * LinearLayout, etc) outside of Fragment use cases.
  *
+ * <p>FragmentContainerView will only allow views to returned by a Fragment's
+ * {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}. Attempting to add any other
+ * view will result in an {@link IllegalStateException}.
+ *
  * <p>Layout animations and transitions are disabled for FragmentContainerView. Animations should be
  * done through {@link FragmentTransaction#setCustomAnimations(int, int, int, int)}. If
  * animateLayoutChanges is set to <code>true</code> or
@@ -159,6 +166,41 @@
         super.endViewTransition(view);
     }
 
+    /**
+     * <p>FragmentContainerView will only allow views to returned by a Fragment's
+     * {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}. Attempting to add any
+     *  other view will result in an {@link IllegalStateException}.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public void addView(@NonNull View child, int index, @Nullable ViewGroup.LayoutParams params) {
+        if (FragmentManager.getViewFragment(child) == null) {
+            throw new IllegalStateException("Views added to a FragmentContainerView must be"
+                    + " associated with a Fragment. View " + child + " is not associated with a"
+                    + " Fragment.");
+        }
+        super.addView(child, index, params);
+    }
+
+    /**
+     * <p>FragmentContainerView will only allow views to returned by a Fragment's
+     * {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}. Attempting to add any
+     *  other view will result in an {@link IllegalStateException}.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    protected boolean addViewInLayout(@NonNull View child, int index,
+            @Nullable ViewGroup.LayoutParams params, boolean preventRequestLayout) {
+        if (FragmentManager.getViewFragment(child) == null) {
+            throw new IllegalStateException("Views added to a FragmentContainerView must be"
+                    + " associated with a Fragment. View " + child + " is not associated with a"
+                    + " Fragment.");
+        }
+        return super.addViewInLayout(child, index, params, preventRequestLayout);
+    }
+
     @Override
     public void removeViewAt(int index) {
         View view = getChildAt(index);
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
index c1354c8..d376369 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -780,11 +780,11 @@
      * @return the locally scoped {@link Fragment} to the given view, if found
      */
     @Nullable
-    static Fragment findViewFragment(@NonNull View view) {
+    private static Fragment findViewFragment(@NonNull View view) {
         while (view != null) {
-            Object tag = view.getTag(R.id.fragment_container_view_tag);
-            if (tag instanceof Fragment) {
-                return (Fragment) tag;
+            Fragment fragment = getViewFragment(view);
+            if (fragment != null) {
+                return fragment;
             }
             ViewParent parent = view.getParent();
             view = parent instanceof View ? (View) parent : null;
@@ -793,6 +793,20 @@
     }
 
     /**
+     * Check if this view has an associated Fragment
+     * @param view the view to search from
+     * @return the locally scoped {@link Fragment} to the given view, if found
+     */
+    @Nullable
+    static Fragment getViewFragment(@NonNull View view) {
+        Object tag = view.getTag(R.id.fragment_container_view_tag);
+        if (tag instanceof Fragment) {
+            return (Fragment) tag;
+        }
+        return null;
+    }
+
+    /**
      * Used to store the Fragment inside of its view's tag. This is done after the fragment's view
      * is created, but before the view is added to the container.
      *
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index a3e453a..f5e1ba4 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/gridlayout/build.gradle b/gridlayout/build.gradle
index efb7375..58ab795 100644
--- a/gridlayout/build.gradle
+++ b/gridlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api(ANDROIDX_ANNOTATION)
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/jetifier/jetifier/migration.config b/jetifier/jetifier/migration.config
index 03e7d2a..16ac67b 100644
--- a/jetifier/jetifier/migration.config
+++ b/jetifier/jetifier/migration.config
@@ -614,6 +614,10 @@
       "to": "ignore"
     },
     {
+      "from": "androidx/benchmark/(.*)",
+      "to": "ignore"
+    },
+    {
       "from": "androidx/camera/(.*)",
       "to": "ignore"
     },
@@ -972,6 +976,10 @@
       "to": "androidx/sharetarget"
     },
     {
+      "from": "androidx/benchmark",
+      "to": "androidx/benchmark"
+    },
+    {
       "from": "androidx/camera",
       "to": "androidx/camera"
     },
@@ -3023,6 +3031,30 @@
     },
     {
       "from": {
+        "groupId": "androidx.benchmark",
+        "artifactId": "benchmark-common",
+        "version": "{newBenchmarkVersion}"
+      },
+      "to": {
+        "groupId": "androidx.benchmark",
+        "artifactId": "benchmark-common",
+        "version": "{newBenchmarkVersion}"
+      }
+    },
+    {
+      "from": {
+        "groupId": "androidx.benchmark",
+        "artifactId": "benchmark-junit4",
+        "version": "{newBenchmarkVersion}"
+      },
+      "to": {
+        "groupId": "androidx.benchmark",
+        "artifactId": "benchmark-junit4",
+        "version": "{newBenchmarkVersion}"
+      }
+    },
+    {
+      "from": {
         "groupId": "androidx.camera",
         "artifactId": "camera-core",
         "version": "{newCameraVersion}"
@@ -3133,6 +3165,7 @@
       "newBiometricVersion": "1.0.0-alpha03",
       "newDataBindingVersion": "undefined",
       "newWorkManagerVersion": "2.0.0",
+      "newBenchmarkVersion": "1.0.0-alpha04",
       "newCameraVersion": "1.0.0-alpha01"
     }
   },
diff --git a/leanback/build.gradle b/leanback/build.gradle
index 7588656..df32fcf 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -11,7 +11,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.interpolator:interpolator:1.0.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.media:media:1.0.0")
     api("androidx.fragment:fragment:1.0.0")
diff --git a/legacy/core-utils/build.gradle b/legacy/core-utils/build.gradle
index 7a331a9..c4fed24 100644
--- a/legacy/core-utils/build.gradle
+++ b/legacy/core-utils/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     api(project(":documentfile"))
     api(project(":loader:loader"))
     api(project(":localbroadcastmanager"))
diff --git a/lifecycle/lifecycle-extensions/api/2.2.0-alpha03.txt b/lifecycle/lifecycle-extensions/api/2.2.0-alpha03.txt
index c85f1ab..273ffbf 100644
--- a/lifecycle/lifecycle-extensions/api/2.2.0-alpha03.txt
+++ b/lifecycle/lifecycle-extensions/api/2.2.0-alpha03.txt
@@ -1,12 +1,12 @@
 // Signature format: 3.0
 package androidx.lifecycle {
 
-  public class ViewModelProviders {
+  @Deprecated public class ViewModelProviders {
     ctor @Deprecated public ViewModelProviders();
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
   }
 
   @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
diff --git a/lifecycle/lifecycle-extensions/api/current.txt b/lifecycle/lifecycle-extensions/api/current.txt
index c85f1ab..273ffbf 100644
--- a/lifecycle/lifecycle-extensions/api/current.txt
+++ b/lifecycle/lifecycle-extensions/api/current.txt
@@ -1,12 +1,12 @@
 // Signature format: 3.0
 package androidx.lifecycle {
 
-  public class ViewModelProviders {
+  @Deprecated public class ViewModelProviders {
     ctor @Deprecated public ViewModelProviders();
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
   }
 
   @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
diff --git a/lifecycle/lifecycle-extensions/api/restricted_2.2.0-alpha03.txt b/lifecycle/lifecycle-extensions/api/restricted_2.2.0-alpha03.txt
index c85f1ab..273ffbf 100644
--- a/lifecycle/lifecycle-extensions/api/restricted_2.2.0-alpha03.txt
+++ b/lifecycle/lifecycle-extensions/api/restricted_2.2.0-alpha03.txt
@@ -1,12 +1,12 @@
 // Signature format: 3.0
 package androidx.lifecycle {
 
-  public class ViewModelProviders {
+  @Deprecated public class ViewModelProviders {
     ctor @Deprecated public ViewModelProviders();
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
   }
 
   @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
diff --git a/lifecycle/lifecycle-extensions/api/restricted_current.txt b/lifecycle/lifecycle-extensions/api/restricted_current.txt
index c85f1ab..273ffbf 100644
--- a/lifecycle/lifecycle-extensions/api/restricted_current.txt
+++ b/lifecycle/lifecycle-extensions/api/restricted_current.txt
@@ -1,12 +1,12 @@
 // Signature format: 3.0
 package androidx.lifecycle {
 
-  public class ViewModelProviders {
+  @Deprecated public class ViewModelProviders {
     ctor @Deprecated public ViewModelProviders();
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
-    method @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.Fragment, androidx.lifecycle.ViewModelProvider.Factory?);
+    method @Deprecated @MainThread public static androidx.lifecycle.ViewModelProvider of(androidx.fragment.app.FragmentActivity, androidx.lifecycle.ViewModelProvider.Factory?);
   }
 
   @Deprecated public static class ViewModelProviders.DefaultFactory extends androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory {
diff --git a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt
index 696c0c9..9cfd0c9 100644
--- a/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt
+++ b/lifecycle/lifecycle-extensions/src/androidTest/java/androidx/lifecycle/ViewModelProvidersFragmentTest.kt
@@ -25,6 +25,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
+@Suppress("DEPRECATION")
 @MediumTest
 @RunWith(AndroidJUnit4::class)
 class ViewModelProvidersFragmentTest {
diff --git a/lifecycle/lifecycle-extensions/src/main/java/androidx/lifecycle/ViewModelProviders.java b/lifecycle/lifecycle-extensions/src/main/java/androidx/lifecycle/ViewModelProviders.java
index 0b83b92..2bf899e 100644
--- a/lifecycle/lifecycle-extensions/src/main/java/androidx/lifecycle/ViewModelProviders.java
+++ b/lifecycle/lifecycle-extensions/src/main/java/androidx/lifecycle/ViewModelProviders.java
@@ -16,7 +16,6 @@
 
 package androidx.lifecycle;
 
-import android.app.Activity;
 import android.app.Application;
 
 import androidx.annotation.MainThread;
@@ -28,7 +27,10 @@
 
 /**
  * Utilities methods for {@link ViewModelStore} class.
+ *
+ * @deprecated Use the constructors for {@link ViewModelProvider} directly.
  */
+@Deprecated
 public class ViewModelProviders {
 
     /**
@@ -38,51 +40,44 @@
     public ViewModelProviders() {
     }
 
-    private static Application checkApplication(Activity activity) {
-        Application application = activity.getApplication();
-        if (application == null) {
-            throw new IllegalStateException("Your activity/fragment is not yet attached to "
-                    + "Application. You can't request ViewModel before onCreate call.");
-        }
-        return application;
-    }
-
-    private static Activity checkActivity(Fragment fragment) {
-        Activity activity = fragment.getActivity();
-        if (activity == null) {
-            throw new IllegalStateException("Can't create ViewModelProvider for detached fragment");
-        }
-        return activity;
-    }
-
     /**
      * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given
      * {@code fragment} is alive. More detailed explanation is in {@link ViewModel}.
      * <p>
-     * It uses {@link ViewModelProvider.AndroidViewModelFactory} to instantiate new ViewModels.
+     * It uses the {@link Fragment#getDefaultViewModelProviderFactory() default factory}
+     * to instantiate new ViewModels.
      *
      * @param fragment a fragment, in whose scope ViewModels should be retained
      * @return a ViewModelProvider instance
+     * @deprecated Use the 'by viewModels()' Kotlin property delegate or
+     * {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner)},
+     * passing in the fragment.
      */
+    @Deprecated
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull Fragment fragment) {
-        return of(fragment, null);
+        return new ViewModelProvider(fragment);
     }
 
     /**
      * Creates a {@link ViewModelProvider}, which retains ViewModels while a scope of given Activity
      * is alive. More detailed explanation is in {@link ViewModel}.
      * <p>
-     * It uses {@link ViewModelProvider.AndroidViewModelFactory} to instantiate new ViewModels.
+     * It uses the {@link FragmentActivity#getDefaultViewModelProviderFactory() default factory}
+     * to instantiate new ViewModels.
      *
      * @param activity an activity, in whose scope ViewModels should be retained
      * @return a ViewModelProvider instance
+     * @deprecated Use the 'by viewModels()' Kotlin property delegate or
+     * {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner)},
+     * passing in the activity.
      */
+    @Deprecated
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull FragmentActivity activity) {
-        return of(activity, null);
+        return new ViewModelProvider(activity);
     }
 
     /**
@@ -94,13 +89,16 @@
      * @param fragment a fragment, in whose scope ViewModels should be retained
      * @param factory  a {@code Factory} to instantiate new ViewModels
      * @return a ViewModelProvider instance
+     * @deprecated Use the 'by viewModels()' Kotlin property delegate or
+     * {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner, Factory)},
+     * passing in the fragment and factory.
      */
+    @Deprecated
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
-        Application application = checkApplication(checkActivity(fragment));
         if (factory == null) {
-            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+            factory = fragment.getDefaultViewModelProviderFactory();
         }
         return new ViewModelProvider(fragment.getViewModelStore(), factory);
     }
@@ -114,14 +112,17 @@
      * @param activity an activity, in whose scope ViewModels should be retained
      * @param factory  a {@code Factory} to instantiate new ViewModels
      * @return a ViewModelProvider instance
+     * @deprecated Use the 'by viewModels()' Kotlin property delegate or
+     * {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner, Factory)},
+     * passing in the activity and factory.
      */
+    @Deprecated
     @NonNull
     @MainThread
     public static ViewModelProvider of(@NonNull FragmentActivity activity,
             @Nullable Factory factory) {
-        Application application = checkApplication(activity);
         if (factory == null) {
-            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
+            factory = activity.getDefaultViewModelProviderFactory();
         }
         return new ViewModelProvider(activity.getViewModelStore(), factory);
     }
diff --git a/lifecycle/lifecycle-extensions/src/test/java/androidx/lifecycle/ViewModelProvidersTest.java b/lifecycle/lifecycle-extensions/src/test/java/androidx/lifecycle/ViewModelProvidersTest.java
index e21f5c1..1dc35ae 100644
--- a/lifecycle/lifecycle-extensions/src/test/java/androidx/lifecycle/ViewModelProvidersTest.java
+++ b/lifecycle/lifecycle-extensions/src/test/java/androidx/lifecycle/ViewModelProvidersTest.java
@@ -23,6 +23,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
+@SuppressWarnings("deprecation")
 @RunWith(JUnit4.class)
 public class ViewModelProvidersTest {
 
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/1.0.0-alpha03.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/1.0.0-alpha03.txt
index 53339c9..8bd77f2 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/1.0.0-alpha03.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/1.0.0-alpha03.txt
@@ -20,10 +20,7 @@
   }
 
   public final class SavedStateViewModelFactory extends androidx.lifecycle.AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment, android.os.Bundle?);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity, android.os.Bundle?);
+    ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method protected <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>, androidx.lifecycle.SavedStateHandle);
   }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
index 53339c9..8bd77f2 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/current.txt
@@ -20,10 +20,7 @@
   }
 
   public final class SavedStateViewModelFactory extends androidx.lifecycle.AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment, android.os.Bundle?);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity, android.os.Bundle?);
+    ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method protected <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>, androidx.lifecycle.SavedStateHandle);
   }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_1.0.0-alpha03.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_1.0.0-alpha03.txt
index b023830b..efd5ff3 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_1.0.0-alpha03.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_1.0.0-alpha03.txt
@@ -21,10 +21,7 @@
   }
 
   public final class SavedStateViewModelFactory extends androidx.lifecycle.AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment, android.os.Bundle?);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity, android.os.Bundle?);
+    ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method protected <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>, androidx.lifecycle.SavedStateHandle);
   }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
index b023830b..efd5ff3 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/api/restricted_current.txt
@@ -21,10 +21,7 @@
   }
 
   public final class SavedStateViewModelFactory extends androidx.lifecycle.AbstractSavedStateViewModelFactory implements androidx.lifecycle.ViewModelProvider.Factory {
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.Fragment, android.os.Bundle?);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity);
-    ctor public SavedStateViewModelFactory(androidx.fragment.app.FragmentActivity, android.os.Bundle?);
+    ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner);
     ctor public SavedStateViewModelFactory(android.app.Application, androidx.savedstate.SavedStateRegistryOwner, android.os.Bundle?);
     method protected <T extends androidx.lifecycle.ViewModel> T create(String, Class<T!>, androidx.lifecycle.SavedStateHandle);
   }
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
index 2d58931..ad09591 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
+++ b/lifecycle/lifecycle-viewmodel-savedstate/build.gradle
@@ -38,10 +38,9 @@
     api(project(":lifecycle:lifecycle-livedata-core"))
     api(project(":lifecycle:lifecycle-viewmodel"))
 
-    api project(":fragment:fragment"), {
-        exclude group: 'androidx.lifecycle', module: 'lifecycle-livedata-core'
+    androidTestImplementation project(":fragment:fragment"), {
+        exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-savedstate'
     }
-
     androidTestImplementation(TRUTH)
     androidTestImplementation(KOTLIN_STDLIB)
     androidTestImplementation(ESPRESSO_CORE)
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
index 0277b01..2da4e17 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/SavedStateFactoryTest.kt
@@ -41,8 +41,9 @@
 
     @Test
     fun testCreateAndroidVM() {
-        val savedStateVMFactory =
-            SavedStateViewModelFactory(activityRule.activity)
+        val savedStateVMFactory = SavedStateViewModelFactory(
+            activityRule.activity.application,
+            activityRule.activity)
         val vm = ViewModelProvider(ViewModelStore(), savedStateVMFactory)
         assertThat(vm.get(MyAndroidViewModel::class.java).handle).isNotNull()
         assertThat(vm.get(MyViewModel::class.java).handle).isNotNull()
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/ViewModelsWithStateTests.java b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/ViewModelsWithStateTests.java
index 5b2b458..8f0a31d 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/ViewModelsWithStateTests.java
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/androidTest/java/androidx/lifecycle/viewmodel/savedstate/ViewModelsWithStateTests.java
@@ -143,14 +143,17 @@
     private ViewModelProvider vmProvider(FakingSavedStateActivity activity) {
         if (FRAGMENT_MODE.equals(mode)) {
             Fragment fragment = activity.getFragment();
-            return new ViewModelProvider(fragment, new SavedStateViewModelFactory(fragment));
+            return new ViewModelProvider(fragment, new SavedStateViewModelFactory(
+                    fragment.requireActivity().getApplication(), fragment));
         }
-        return new ViewModelProvider(activity, new SavedStateViewModelFactory(activity));
+        return new ViewModelProvider(activity, new SavedStateViewModelFactory(
+                activity.getApplication(), activity));
     }
 
     // copy copy copy paste
     @SuppressWarnings("unchecked")
-    private static <T extends Activity> T recreateActivity(final T activity, ActivityTestRule rule)
+    private static <T extends Activity> T recreateActivity(final T activity,
+            ActivityTestRule<?> rule)
             throws Throwable {
         Instrumentation.ActivityMonitor monitor = new Instrumentation.ActivityMonitor(
                 activity.getClass().getCanonicalName(), null, false);
diff --git a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.java b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.java
index a4c48dc..59a3039 100644
--- a/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.java
+++ b/lifecycle/lifecycle-viewmodel-savedstate/src/main/java/androidx/lifecycle/SavedStateViewModelFactory.java
@@ -16,14 +16,12 @@
 
 package androidx.lifecycle;
 
-import android.app.Activity;
+import android.annotation.SuppressLint;
 import android.app.Application;
 import android.os.Bundle;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentActivity;
 import androidx.savedstate.SavedStateRegistryOwner;
 
 import java.lang.reflect.Constructor;
@@ -33,8 +31,7 @@
 /**
  * {@link androidx.lifecycle.ViewModelProvider.Factory} that can create ViewModels accessing and
  * contributing to a saved state via {@link SavedStateHandle} received in a constructor.
- * If {@code defaultArgs} bundle was passed in {@link #SavedStateViewModelFactory(Fragment, Bundle)}
- * or {@link #SavedStateViewModelFactory(FragmentActivity, Bundle)}, it will provide default
+ * If {@code defaultArgs} bundle was passed into the constructor, it will provide default
  * values in {@code SavedStateHandle}.
  * <p>
  * If ViewModel is instance of {@link androidx.lifecycle.AndroidViewModel}, it looks for a
@@ -49,55 +46,15 @@
      * Creates {@link SavedStateViewModelFactory}.
      * <p>
      * {@link androidx.lifecycle.ViewModel} created with this factory can access to saved state
-     * scoped to the given {@code fragment}.
-     *
-     * @param fragment scope of this fragment will be used for state saving
-     */
-    public SavedStateViewModelFactory(@NonNull Fragment fragment) {
-        this(fragment, null);
-    }
-
-    /**
-     * Creates {@link SavedStateViewModelFactory}.
-     * <p>
-     * {@link androidx.lifecycle.ViewModel} created with this factory can access to saved state
-     * scoped to the given {@code fragment}.
-     *
-     * @param fragment scope of this fragment will be used for state saving
-     * @param defaultArgs values from this {@code Bundle} will be used as defaults by
-     * {@link SavedStateHandle} if there is no previously saved state or previously saved state
-     * miss a value by such key.
-     */
-    public SavedStateViewModelFactory(@NonNull Fragment fragment, @Nullable Bundle defaultArgs) {
-        this(checkApplication(checkActivity(fragment)), fragment, defaultArgs);
-    }
-
-    /**
-     * Creates {@link SavedStateViewModelFactory}.
-     * <p>
-     * {@link androidx.lifecycle.ViewModel} created with this factory can access to saved state
      * scoped to the given {@code activity}.
      *
-     * @param activity scope of this activity will be used for state saving
+     * @param application an application
+     * @param owner {@link SavedStateRegistryOwner} that will provide restored state for created
+     * {@link androidx.lifecycle.ViewModel ViewModels}
      */
-    public SavedStateViewModelFactory(@NonNull FragmentActivity activity) {
-        this(activity, null);
-    }
-
-    /**
-     * Creates {@link SavedStateViewModelFactory}.
-     * <p>
-     * {@link androidx.lifecycle.ViewModel} created with this factory can access to saved state
-     * scoped to the given {@code activity}.
-     *
-     * @param activity scope of this activity will be used for state saving
-     * @param defaultArgs values from this {@code Bundle} will be used as defaults by
-     * {@link SavedStateHandle} if there is no previously saved state or previously saved state
-     * misses a value by such key.
-     */
-    public SavedStateViewModelFactory(@NonNull FragmentActivity activity,
-            @Nullable Bundle defaultArgs) {
-        this(checkApplication(activity), activity, defaultArgs);
+    public SavedStateViewModelFactory(@NonNull Application application,
+            @NonNull SavedStateRegistryOwner owner) {
+        this(application, owner, null);
     }
 
     /**
@@ -113,6 +70,7 @@
      * {@link SavedStateHandle} if there is no previously saved state or previously saved state
      * misses a value by such key.
      */
+    @SuppressLint("LambdaLast")
     public SavedStateViewModelFactory(@NonNull Application application,
             @NonNull SavedStateRegistryOwner owner,
             @Nullable Bundle defaultArgs) {
@@ -166,23 +124,4 @@
         }
         return null;
     }
-
-    private static Application checkApplication(Activity activity) {
-        Application application = activity.getApplication();
-        if (application == null) {
-            throw new IllegalStateException("Your activity/fragment is not yet attached to "
-                    + "Application. You can't request ViewModelsWithStateFactory "
-                    + "before onCreate call.");
-        }
-        return application;
-    }
-
-    private static Activity checkActivity(Fragment fragment) {
-        Activity activity = fragment.getActivity();
-        if (activity == null) {
-            throw new IllegalStateException("Can't create ViewModelsWithStateFactory"
-                    + " for detached fragment");
-        }
-        return activity;
-    }
 }
diff --git a/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha03.txt b/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha03.txt
index 1c69a2a..07a8cb5 100644
--- a/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha03.txt
+++ b/lifecycle/lifecycle-viewmodel/api/2.2.0-alpha03.txt
@@ -6,12 +6,17 @@
     method public <T extends android.app.Application> T getApplication();
   }
 
+  public interface HasDefaultViewModelProviderFactory {
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+  }
+
   public abstract class ViewModel {
     ctor public ViewModel();
     method protected void onCleared();
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
diff --git a/lifecycle/lifecycle-viewmodel/api/current.txt b/lifecycle/lifecycle-viewmodel/api/current.txt
index 1c69a2a..07a8cb5 100644
--- a/lifecycle/lifecycle-viewmodel/api/current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/current.txt
@@ -6,12 +6,17 @@
     method public <T extends android.app.Application> T getApplication();
   }
 
+  public interface HasDefaultViewModelProviderFactory {
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+  }
+
   public abstract class ViewModel {
     ctor public ViewModel();
     method protected void onCleared();
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_2.2.0-alpha03.txt b/lifecycle/lifecycle-viewmodel/api/restricted_2.2.0-alpha03.txt
index 1c69a2a..07a8cb5 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_2.2.0-alpha03.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_2.2.0-alpha03.txt
@@ -6,12 +6,17 @@
     method public <T extends android.app.Application> T getApplication();
   }
 
+  public interface HasDefaultViewModelProviderFactory {
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+  }
+
   public abstract class ViewModel {
     ctor public ViewModel();
     method protected void onCleared();
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
diff --git a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
index 1c69a2a..07a8cb5 100644
--- a/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
+++ b/lifecycle/lifecycle-viewmodel/api/restricted_current.txt
@@ -6,12 +6,17 @@
     method public <T extends android.app.Application> T getApplication();
   }
 
+  public interface HasDefaultViewModelProviderFactory {
+    method public androidx.lifecycle.ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+  }
+
   public abstract class ViewModel {
     ctor public ViewModel();
     method protected void onCleared();
   }
 
   public class ViewModelProvider {
+    ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStoreOwner, androidx.lifecycle.ViewModelProvider.Factory);
     ctor public ViewModelProvider(androidx.lifecycle.ViewModelStore, androidx.lifecycle.ViewModelProvider.Factory);
     method @MainThread public <T extends androidx.lifecycle.ViewModel> T get(Class<T!>);
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/HasDefaultViewModelProviderFactory.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/HasDefaultViewModelProviderFactory.java
new file mode 100644
index 0000000..1db6658
--- /dev/null
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/HasDefaultViewModelProviderFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 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.annotation.NonNull;
+
+/**
+ * Interface that marks a {@link ViewModelStoreOwner} as having a default
+ * {@link ViewModelProvider.Factory} for use with
+ * {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner)}.
+ */
+public interface HasDefaultViewModelProviderFactory {
+    /**
+     * Returns the default {@link ViewModelProvider.Factory} that should be
+     * used when no custom {@code Factory} is provided to the
+     * {@link ViewModelProvider} constructors.
+     *
+     * @return a {@code ViewModelProvider.Factory}
+     */
+    @NonNull
+    ViewModelProvider.Factory getDefaultViewModelProviderFactory();
+}
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModel.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModel.java
index 0709327..259430f 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModel.java
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModel.java
@@ -54,7 +54,7 @@
  *     protected void onCreate(Bundle savedInstanceState) {
  *         super.onCreate(savedInstanceState);
  *         setContentView(R.layout.user_activity_layout);
- *         final UserModel viewModel = ViewModelProviders.of(this).get(UserModel.class);
+ *         final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
  *         viewModel.userLiveData.observer(this, new Observer<User>() {
  *            {@literal @}Override
  *             public void onChanged(@Nullable User data) {
@@ -99,7 +99,7 @@
  * <pre>
  * public class MyFragment extends Fragment {
  *     public void onStart() {
- *         UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);
+ *         UserModel userModel = new ViewModelProvider(requireActivity()).get(UserModel.class);
  *     }
  * }
  * </pre>
diff --git a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
index 56d9f1b..e66da15 100644
--- a/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
+++ b/lifecycle/lifecycle-viewmodel/src/main/java/androidx/lifecycle/ViewModelProvider.java
@@ -27,7 +27,7 @@
  * An utility class that provides {@code ViewModels} for a scope.
  * <p>
  * Default {@code ViewModelProvider} for an {@code Activity} or a {@code Fragment} can be obtained
- * from {@link androidx.lifecycle.ViewModelProviders} class.
+ * by passing it to {@link ViewModelProvider#ViewModelProvider(ViewModelStoreOwner)}.
  */
 @SuppressWarnings("WeakerAccess")
 public class ViewModelProvider {
@@ -82,6 +82,21 @@
     private final ViewModelStore mViewModelStore;
 
     /**
+     * Creates {@code ViewModelProvider}. This will create {@code ViewModels}
+     * and retain them in a store of the given {@code ViewModelStoreOwner}.
+     * <p>
+     * This method will use the
+     * {@link HasDefaultViewModelProviderFactory#getDefaultViewModelProviderFactory() default factory}
+     * if the owner implements {@link HasDefaultViewModelProviderFactory}. Otherwise, a
+     * {@link NewInstanceFactory} will be used.
+     */
+    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
+        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
+                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
+                : NewInstanceFactory.getInstance());
+    }
+
+    /**
      * Creates {@code ViewModelProvider}, which will create {@code ViewModels} via the given
      * {@code Factory} and retain them in a store of the given {@code ViewModelStoreOwner}.
      *
@@ -172,6 +187,21 @@
      */
     public static class NewInstanceFactory implements Factory {
 
+        private static NewInstanceFactory sInstance;
+
+        /**
+         * Retrieve a singleton instance of NewInstanceFactory.
+         *
+         * @return A valid {@link NewInstanceFactory}
+         */
+        @NonNull
+        static NewInstanceFactory getInstance() {
+            if (sInstance == null) {
+                sInstance = new NewInstanceFactory();
+            }
+            return sInstance;
+        }
+
         @SuppressWarnings("ClassNewInstance")
         @NonNull
         @Override
diff --git a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
index dd9470f..0d5783c 100644
--- a/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
+++ b/lifecycle/lifecycle-viewmodel/src/test/java/androidx/lifecycle/ViewModelProviderTest.java
@@ -85,6 +85,17 @@
     }
 
     @Test
+    public void testCustomDefaultFactory() {
+        final ViewModelStore store = new ViewModelStore();
+        final CountingFactory factory = new CountingFactory();
+        ViewModelStoreOwnerWithFactory owner = new ViewModelStoreOwnerWithFactory(store, factory);
+        ViewModelProvider provider = new ViewModelProvider(owner);
+        ViewModel1 viewModel = provider.get(ViewModel1.class);
+        assertThat(viewModel, is(provider.get(ViewModel1.class)));
+        assertThat(factory.mCalled, is(1));
+    }
+
+    @Test
     public void testKeyedFactory() {
         final ViewModelStore store = new ViewModelStore();
         ViewModelStoreOwner owner = new ViewModelStoreOwner() {
@@ -107,6 +118,30 @@
         provider.get("customkey", ViewModel1.class);
     }
 
+    public static class ViewModelStoreOwnerWithFactory implements
+            ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
+        private final ViewModelStore mStore;
+        private final ViewModelProvider.Factory mFactory;
+
+        ViewModelStoreOwnerWithFactory(@NonNull ViewModelStore store,
+                @NonNull ViewModelProvider.Factory factory) {
+            mStore = store;
+            mFactory = factory;
+        }
+
+        @NonNull
+        @Override
+        public ViewModelStore getViewModelStore() {
+            return mStore;
+        }
+
+        @NonNull
+        @Override
+        public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+            return mFactory;
+        }
+    }
+
     public static class ViewModel1 extends ViewModel {
         boolean mCleared;
 
@@ -118,4 +153,15 @@
 
     public static class ViewModel2 extends ViewModel {
     }
+
+    public static class CountingFactory extends NewInstanceFactory {
+        int mCalled = 0;
+
+        @Override
+        @NonNull
+        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
+            mCalled++;
+            return super.create(modelClass);
+        }
+    }
 }
diff --git a/media/build.gradle b/media/build.gradle
index f0a49ef..863a93c 100644
--- a/media/build.gradle
+++ b/media/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java b/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
index 8f43365..a6bf8dd 100644
--- a/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
+++ b/media/src/main/java/android/support/v4/media/session/MediaControllerCompat.java
@@ -53,8 +53,8 @@
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.core.app.BundleCompat;
-import androidx.core.app.ComponentActivity;
 import androidx.media.AudioAttributesCompat;
+import androidx.media.R;
 import androidx.media.VolumeProviderCompat;
 import androidx.versionedparcelable.ParcelUtils;
 import androidx.versionedparcelable.VersionedParcelable;
@@ -144,26 +144,11 @@
     public static final String COMMAND_ARGUMENT_INDEX =
             "android.support.v4.media.session.command.ARGUMENT_INDEX";
 
-    private static class MediaControllerExtraData extends ComponentActivity.ExtraData {
-        private final MediaControllerCompat mMediaController;
-
-        MediaControllerExtraData(MediaControllerCompat mediaController) {
-            mMediaController = mediaController;
-        }
-
-        MediaControllerCompat getMediaController() {
-            return mMediaController;
-        }
-    }
-
     /**
      * Sets a {@link MediaControllerCompat} in the {@code activity} for later retrieval via
      * {@link #getMediaController(Activity)}.
      *
-     * <p>This is compatible with {@link Activity#setMediaController(MediaController)}.
-     * If {@code activity} inherits {@link androidx.fragment.app.FragmentActivity}, the
-     * {@code mediaController} will be saved in the {@code activity}. In addition to that,
-     * on API 21 and later, {@link Activity#setMediaController(MediaController)} will be
+     * <p>On API 21 and later, {@link Activity#setMediaController(MediaController)} will also be
      * called.</p>
      *
      * @param activity The activity to set the {@code mediaController} in, must not be null.
@@ -174,10 +159,8 @@
      */
     public static void setMediaController(@NonNull Activity activity,
             MediaControllerCompat mediaController) {
-        if (activity instanceof ComponentActivity) {
-            ((ComponentActivity) activity).putExtraData(
-                    new MediaControllerExtraData(mediaController));
-        }
+        activity.getWindow().getDecorView().setTag(
+                R.id.media_controller_compat_view_tag, mediaController);
         if (android.os.Build.VERSION.SDK_INT >= 21) {
             MediaController controllerFwk = null;
             if (mediaController != null) {
@@ -200,10 +183,10 @@
      * @see #setMediaController(Activity, MediaControllerCompat)
      */
     public static MediaControllerCompat getMediaController(@NonNull Activity activity) {
-        if (activity instanceof ComponentActivity) {
-            MediaControllerExtraData extraData =
-                    ((ComponentActivity) activity).getExtraData(MediaControllerExtraData.class);
-            return extraData != null ? extraData.getMediaController() : null;
+        Object tag = activity.getWindow().getDecorView()
+                .getTag(R.id.media_controller_compat_view_tag);
+        if (tag instanceof MediaControllerCompat) {
+            return (MediaControllerCompat) tag;
         } else if (android.os.Build.VERSION.SDK_INT >= 21) {
             MediaController controllerFwk = activity.getMediaController();
             if (controllerFwk == null) {
diff --git a/media/src/main/res/values/ids.xml b/media/src/main/res/values/ids.xml
new file mode 100644
index 0000000..2fa8e5c
--- /dev/null
+++ b/media/src/main/res/values/ids.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+        <item type="id" name="media_controller_compat_view_tag" />
+</resources>
\ No newline at end of file
diff --git a/media2/common/src/main/java/androidx/media2/common/SessionPlayer.java b/media2/common/src/main/java/androidx/media2/common/SessionPlayer.java
index 2d1b17f..c67153a 100644
--- a/media2/common/src/main/java/androidx/media2/common/SessionPlayer.java
+++ b/media2/common/src/main/java/androidx/media2/common/SessionPlayer.java
@@ -452,8 +452,8 @@
      * @return the size of the video. The width and height of size could be 0 if there is no video
      * or the size has not been determined yet.
      * The {@link PlayerCallback} can be registered via {@link #registerPlayerCallback} to
-     * receive a notification {@link PlayerCallback#onVideoSizeChangedInternal} when the size
-     * is available.
+     * receive a notification {@link PlayerCallback#onVideoSizeChanged(SessionPlayer, VideoSize)}
+     * when the size is available.
      *
      * @hide
      */
@@ -1338,6 +1338,16 @@
         }
 
         /**
+         * @deprecated Use {@link #onVideoSizeChanged(SessionPlayer, VideoSize)} instead.
+         * @hide
+         */
+        @Deprecated
+        @RestrictTo(LIBRARY_GROUP)
+        public void onVideoSizeChangedInternal(
+                @NonNull SessionPlayer player, @NonNull MediaItem item, @NonNull VideoSize size) {
+        }
+
+        /**
          * Called to indicate the video size
          * <p>
          * The video size (width and height) could be 0 if there was no video,
@@ -1348,16 +1358,14 @@
          * is called.
          *
          * @param player the player associated with this callback
-         * @param item the MediaItem of this media item
          * @param size the size of the video
          * @see #getVideoSizeInternal()
          *
          * @hide
          */
-        // TODO: Add onVideoSizeChanged and deprecate this method (b/132928418)
+        // TODO: Unhide this method (b/132928418)
         @RestrictTo(LIBRARY_GROUP)
-        public void onVideoSizeChangedInternal(
-                @NonNull SessionPlayer player, @NonNull MediaItem item, @NonNull VideoSize size) {
+        public void onVideoSizeChanged(@NonNull SessionPlayer player, @NonNull VideoSize size) {
         }
 
         /**
diff --git a/media2/integration-tests/testapp/build.gradle b/media2/integration-tests/testapp/build.gradle
index b269e6a..ffefd37 100644
--- a/media2/integration-tests/testapp/build.gradle
+++ b/media2/integration-tests/testapp/build.gradle
@@ -30,7 +30,7 @@
     implementation(project(":media2:media2-player"))
     implementation(project(":media2:media2-widget"))
     implementation("androidx.appcompat:appcompat:1.0.2")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
 }
 
 android {
diff --git a/media2/media2-exoplayer/src/main/libs/exoplayer-media2.jar b/media2/media2-exoplayer/src/main/libs/exoplayer-media2.jar
index dffa337..121b6d1 100755
--- a/media2/media2-exoplayer/src/main/libs/exoplayer-media2.jar
+++ b/media2/media2-exoplayer/src/main/libs/exoplayer-media2.jar
Binary files differ
diff --git a/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java b/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
index 1cf11d4..00e85db 100644
--- a/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
+++ b/media2/player/src/androidTest/java/androidx/media2/player/MediaPlayerTest.java
@@ -199,6 +199,16 @@
         MediaPlayer.PlayerCallback callback = new MediaPlayer.PlayerCallback() {
             @Override
             public void onVideoSizeChanged(MediaPlayer mp, MediaItem dsd, VideoSize size) {
+                assertVideoSizeEquals(size);
+            }
+
+            @Override
+            public void onVideoSizeChanged(@NonNull SessionPlayer player,
+                    @NonNull androidx.media2.common.VideoSize size) {
+                assertVideoSizeEquals(new VideoSize(size.getWidth(), size.getHeight()));
+            }
+
+            private void assertVideoSizeEquals(VideoSize size) {
                 if (size.getWidth() == 0 && size.getHeight() == 0) {
                     // A size of 0x0 can be sent initially one time when using NuPlayer.
                     assertFalse(onVideoSizeChangedCalled.isSignalled());
@@ -226,7 +236,7 @@
         mPlayer.prepare();
         mPlayer.play();
 
-        onVideoSizeChangedCalled.waitForSignal();
+        onVideoSizeChangedCalled.waitForCountedSignals(2);
         onVideoRenderingStartCalled.waitForSignal();
 
         mPlayer.setPlayerVolume(volume);
@@ -299,6 +309,16 @@
         MediaPlayer.PlayerCallback callback = new MediaPlayer.PlayerCallback() {
             @Override
             public void onVideoSizeChanged(MediaPlayer mp, MediaItem dsd, VideoSize size) {
+                assertVideoSizeEquals(size);
+            }
+
+            @Override
+            public void onVideoSizeChanged(@NonNull SessionPlayer player,
+                    @NonNull androidx.media2.common.VideoSize size) {
+                assertVideoSizeEquals(new VideoSize(size.getWidth(), size.getHeight()));
+            }
+
+            private void assertVideoSizeEquals(VideoSize size) {
                 if (size.getWidth() == 0 && size.getHeight() == 0) {
                     // A size of 0x0 can be sent initially one time when using NuPlayer.
                     assertFalse(onVideoSizeChangedCalled.isSignalled());
@@ -326,7 +346,7 @@
         mPlayer.prepare();
         mPlayer.play();
 
-        onVideoSizeChangedCalled.waitForSignal();
+        onVideoSizeChangedCalled.waitForCountedSignals(2);
         onVideoRenderingStartCalled.waitForSignal();
     }
 
diff --git a/media2/player/src/main/java/androidx/media2/player/AudioFocusHandler.java b/media2/player/src/main/java/androidx/media2/player/AudioFocusHandler.java
index 8738f1d..54797a6 100644
--- a/media2/player/src/main/java/androidx/media2/player/AudioFocusHandler.java
+++ b/media2/player/src/main/java/androidx/media2/player/AudioFocusHandler.java
@@ -280,7 +280,7 @@
                 // want to have more finer grained control. (e.g. adding audio focus listener)
                 return AudioManager.AUDIOFOCUS_NONE;
             }
-            // Javadoc here means 'The different types of focus reuqests' written in the
+            // Javadoc here means 'The different types of focus requests' written in the
             // {@link AudioFocusRequest}.
             switch (audioAttributesCompat.getUsage()) {
                 // USAGE_VOICE_COMMUNICATION_SIGNALLING is for DTMF that may happen multiple times
diff --git a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
index 56e8aac..4142751 100644
--- a/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
+++ b/media2/player/src/main/java/androidx/media2/player/MediaPlayer.java
@@ -428,7 +428,6 @@
             .setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_DEFAULT)
             .build();
 
-    private static final int CALL_COMPLETE_PLAYLIST_BASE = -1000;
     private static final int END_OF_PLAYLIST = -1;
     private static final int NO_MEDIA_ITEM = -2;
 
@@ -504,21 +503,27 @@
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         @MediaPlayer2.CallCompleted final int mCallType;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
-        final ResolvableFuture mFuture;
+        final ResolvableFuture<? extends PlayerResult> mFuture;
         @SuppressWarnings("WeakerAccess") /* synthetic access */
         final SessionPlayer.TrackInfo mTrackInfo;
 
         @SuppressWarnings("WeakerAccess") /* synthetic access */
-        PendingCommand(int callType, ResolvableFuture future) {
+        PendingCommand(int callType, ResolvableFuture<? extends PlayerResult> future) {
             this(callType, future, null);
         }
 
         @SuppressWarnings("WeakerAccess") /* synthetic access */
-        PendingCommand(int callType, ResolvableFuture future, SessionPlayer.TrackInfo trackInfo) {
+        PendingCommand(int callType, ResolvableFuture<? extends PlayerResult> future,
+                SessionPlayer.TrackInfo trackInfo) {
             mCallType = callType;
             mFuture = future;
             mTrackInfo = trackInfo;
         }
+
+        @SuppressWarnings("unchecked")
+        <V extends PlayerResult> void setResult(V value) {
+            ((ResolvableFuture<V>) mFuture).set(value);
+        }
     }
 
     /* A list for tracking the commands submitted to MediaPlayer2.*/
@@ -622,7 +627,7 @@
     /* A list of pending operations within this MediaPlayer that will be executed sequentially. */
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     @GuardedBy("mPendingFutures")
-    final ArrayDeque<PendingFuture<? super PlayerResult>> mPendingFutures = new ArrayDeque<>();
+    final ArrayDeque<PendingFuture<? extends PlayerResult>> mPendingFutures = new ArrayDeque<>();
 
     private final Object mStateLock = new Object();
     @GuardedBy("mStateLock")
@@ -686,7 +691,8 @@
     @GuardedBy("mPendingCommands")
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     void addPendingCommandLocked(
-            int callType, final ResolvableFuture future, final Object token) {
+            int callType, final ResolvableFuture<? extends PlayerResult> future,
+            final Object token) {
         final PendingCommand pendingCommand = new PendingCommand(callType, future);
         mPendingCommands.add(pendingCommand);
         addFutureListener(pendingCommand, future, token);
@@ -695,17 +701,16 @@
     @GuardedBy("mPendingCommands")
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     void addPendingCommandWithTrackInfoLocked(
-            int callType, final ResolvableFuture future, final SessionPlayer.TrackInfo trackInfo,
-            final Object token) {
+            int callType, final ResolvableFuture<? extends PlayerResult> future,
+            final SessionPlayer.TrackInfo trackInfo, final Object token) {
         final PendingCommand pendingCommand = new PendingCommand(callType, future, trackInfo);
         mPendingCommands.add(pendingCommand);
         addFutureListener(pendingCommand, future, token);
     }
 
-    @GuardedBy("mPendingCommands")
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    void addFutureListener(final PendingCommand pendingCommand, final ResolvableFuture future,
-            final Object token) {
+    void addFutureListener(final PendingCommand pendingCommand,
+            final ResolvableFuture<? extends PlayerResult> future, final Object token) {
         future.addListener(new Runnable() {
             @Override
             public void run() {
@@ -721,8 +726,7 @@
         }, mExecutor);
     }
 
-    @SuppressWarnings("unchecked")
-    private void addPendingFuture(final PendingFuture pendingFuture) {
+    private void addPendingFuture(final PendingFuture<? extends PlayerResult> pendingFuture) {
         synchronized (mPendingFutures) {
             mPendingFutures.add(pendingFuture);
             executePendingFutures();
@@ -1776,7 +1780,7 @@
         }
         // Cancel the pending futures.
         synchronized (mPendingFutures) {
-            for (PendingFuture f : mPendingFutures) {
+            for (PendingFuture<? extends PlayerResult> f : mPendingFutures) {
                 if (f.mExecuteCalled && !f.isDone() && !f.isCancelled()) {
                     f.cancel(true);
                 }
@@ -2976,7 +2980,7 @@
         return (value > maxValue) ? maxValue : value;
     }
 
-    @SuppressWarnings({"WeakerAccess", "unchecked"}) /* synthetic access */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
     void handleCallComplete(MediaPlayer2 mp, final MediaItem item, int what, int status) {
         PendingCommand expected;
         synchronized (mPendingCommands) {
@@ -3014,13 +3018,14 @@
                 case MediaPlayer2.CALL_COMPLETED_SET_DATA_SOURCE:
                 case MediaPlayer2.CALL_COMPLETED_SKIP_TO_NEXT:
                     final List<SessionPlayer.TrackInfo> tracks = mp.getTrackInfo();
+                    final androidx.media2.common.VideoSize videoSize = getVideoSizeInternal();
                     notifySessionPlayerCallback(new SessionPlayerCallbackNotifier() {
                         @Override
                         public void callCallback(
                                 SessionPlayer.PlayerCallback callback) {
                             callback.onCurrentMediaItemChanged(MediaPlayer.this, item);
-                            callback.onVideoSizeChangedInternal(MediaPlayer.this,
-                                    getCurrentMediaItem(), getVideoSizeInternal());
+                            callback.onVideoSizeChanged(MediaPlayer.this, videoSize);
+                            callback.onVideoSizeChangedInternal(MediaPlayer.this, item, videoSize);
                             callback.onTrackInfoChanged(MediaPlayer.this, tracks);
                         }
                     });
@@ -3066,20 +3071,20 @@
         if (what != MediaPlayer2.CALL_COMPLETED_PREPARE_DRM) {
             Integer resultCode = sResultCodeMap.containsKey(status)
                     ? sResultCodeMap.get(status) : RESULT_ERROR_UNKNOWN;
-            expected.mFuture.set(new PlayerResult(resultCode, item));
+            expected.setResult(new PlayerResult(resultCode, item));
         } else {
             Integer resultCode = sPrepareDrmStatusMap.containsKey(status)
                     ? sPrepareDrmStatusMap.get(status) : DrmResult.RESULT_ERROR_PREPARATION_ERROR;
-            expected.mFuture.set(new DrmResult(resultCode, item));
+            expected.setResult(new DrmResult(resultCode, item));
         }
         executePendingFutures();
     }
 
     private void executePendingFutures() {
         synchronized (mPendingFutures) {
-            Iterator<PendingFuture<? super PlayerResult>> it = mPendingFutures.iterator();
+            Iterator<PendingFuture<? extends PlayerResult>> it = mPendingFutures.iterator();
             while (it.hasNext()) {
-                PendingFuture f = it.next();
+                PendingFuture<? extends PlayerResult> f = it.next();
                 if (f.isCancelled() || f.execute()) {
                     mPendingFutures.removeFirst();
                 } else {
@@ -3088,7 +3093,7 @@
             }
             // Execute skip futures earlier for making them be skipped.
             while (it.hasNext()) {
-                PendingFuture f = it.next();
+                PendingFuture<? extends PlayerResult> f = it.next();
                 if (!f.mIsSeekTo) {
                     break;
                 }
@@ -3129,6 +3134,7 @@
                 notifySessionPlayerCallback(new SessionPlayerCallbackNotifier() {
                     @Override
                     public void callCallback(SessionPlayer.PlayerCallback callback) {
+                        callback.onVideoSizeChanged(MediaPlayer.this, commonSize);
                         callback.onVideoSizeChangedInternal(MediaPlayer.this, item, commonSize);
                     }
                 });
@@ -3257,9 +3263,12 @@
                 @NonNull MediaPlayer mp, @NonNull MediaItem item, @NonNull VideoSize size) { }
 
         /**
+         * @deprecated Use
+         * {@link #onVideoSizeChanged(SessionPlayer, androidx.media2.common.VideoSize)} instead.
          * @hide
          */
         @RestrictTo(LIBRARY_GROUP)
+        @Deprecated
         @Override
         public void onVideoSizeChangedInternal(
                 @NonNull SessionPlayer player, @NonNull MediaItem item,
@@ -3508,7 +3517,7 @@
         DrmInfo(MediaPlayer2.DrmInfo info) {
             mMp2DrmInfo = info;
         }
-    };
+    }
 
     /**
      * Interface definition of a callback to be invoked when the app
diff --git a/media2/player/src/main/java/androidx/media2/player/MediaPlayer2.java b/media2/player/src/main/java/androidx/media2/player/MediaPlayer2.java
index 3cb98ea..379bfac 100644
--- a/media2/player/src/main/java/androidx/media2/player/MediaPlayer2.java
+++ b/media2/player/src/main/java/androidx/media2/player/MediaPlayer2.java
@@ -690,8 +690,8 @@
      * Returns the audio session ID.
      *
      * @return the audio session ID. {@see #setAudioSessionId(int)}
-     * Note that the audio session ID is 0 only if a problem occured when the MediaPlayer2 was
-     * contructed.
+     * Note that the audio session ID is 0 only if a problem occurred when the MediaPlayer2 was
+     * constructed.
      */
     public abstract int getAudioSessionId();
 
diff --git a/media2/player/src/main/java/androidx/media2/player/MediaTimestamp.java b/media2/player/src/main/java/androidx/media2/player/MediaTimestamp.java
index 63bb050..8d33205 100644
--- a/media2/player/src/main/java/androidx/media2/player/MediaTimestamp.java
+++ b/media2/player/src/main/java/androidx/media2/player/MediaTimestamp.java
@@ -103,8 +103,12 @@
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj) return true;
-        if (obj == null || getClass() != obj.getClass()) return false;
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
 
         final MediaTimestamp that = (MediaTimestamp) obj;
         return (this.mMediaTimeUs == that.mMediaTimeUs)
diff --git a/media2/player/src/main/java/androidx/media2/player/exoplayer/DurationProvidingMediaSource.java b/media2/player/src/main/java/androidx/media2/player/exoplayer/DurationProvidingMediaSource.java
index 79aeb0a..5c52b8f 100644
--- a/media2/player/src/main/java/androidx/media2/player/exoplayer/DurationProvidingMediaSource.java
+++ b/media2/player/src/main/java/androidx/media2/player/exoplayer/DurationProvidingMediaSource.java
@@ -20,7 +20,6 @@
 
 import android.annotation.SuppressLint;
 
-import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.media2.exoplayer.external.C;
 import androidx.media2.exoplayer.external.Timeline;
@@ -65,6 +64,13 @@
     }
 
     @Override
+    protected void onChildSourceInfoRefreshed(Void id,
+            MediaSource mediaSource, Timeline timeline) {
+        mCurrentTimeline = timeline;
+        refreshSourceInfo(timeline);
+    }
+
+    @Override
     public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
         return mMediaSource.createPeriod(id, allocator, startPositionUs);
     }
@@ -74,11 +80,4 @@
         mMediaSource.releasePeriod(mediaPeriod);
     }
 
-    @Override
-    protected void onChildSourceInfoRefreshed(
-            Void id, MediaSource mediaSource, Timeline timeline, @Nullable Object manifest) {
-        mCurrentTimeline = timeline;
-        refreshSourceInfo(timeline, manifest);
-    }
-
 }
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java b/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
index 36e8ff2..57af209 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
@@ -1649,8 +1649,9 @@
     @Test
     public void testGetVideoSize() throws InterruptedException {
         prepareLooper();
+        final MediaItem item = TestUtils.createMediaItemWithMetadata();
         final VideoSize testVideoSize = new VideoSize(100, 42);
-        final CountDownLatch latch = new CountDownLatch(1);
+        final CountDownLatch latch = new CountDownLatch(2);
         final ControllerCallback callback = new ControllerCallback() {
             @Override
             public void onVideoSizeChanged(@NonNull MediaController controller,
@@ -1659,8 +1660,16 @@
                 assertEquals(testVideoSize, videoSize);
                 latch.countDown();
             }
+
+            @Override
+            public void onVideoSizeChanged(@NonNull MediaController controller,
+                    @NonNull VideoSize videoSize) {
+                assertEquals(testVideoSize, videoSize);
+                latch.countDown();
+            }
         };
         MediaController controller = createController(mSession.getToken(), true, null, callback);
+        mPlayer.notifyCurrentMediaItemChanged(item);
         mPlayer.notifyVideoSizeChanged(testVideoSize);
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(testVideoSize, controller.getVideoSize());
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/TestBrowserCallback.java b/media2/session/src/androidTest/java/androidx/media2/session/TestBrowserCallback.java
index 0d7bed7..cb17489 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/TestBrowserCallback.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/TestBrowserCallback.java
@@ -183,6 +183,12 @@
     }
 
     @Override
+    public void onVideoSizeChanged(@NonNull MediaController controller,
+            @NonNull VideoSize videoSize) {
+        mCallbackProxy.onVideoSizeChanged(controller, videoSize);
+    }
+
+    @Override
     public void onSubtitleData(@NonNull MediaController controller, @NonNull MediaItem item,
             @NonNull SessionPlayer.TrackInfo track, @NonNull SubtitleData data) {
         mCallbackProxy.onSubtitleData(controller, item, track, data);
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaController.java b/media2/session/src/main/java/androidx/media2/session/MediaController.java
index 4185834..bbe069d 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaController.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaController.java
@@ -1883,16 +1883,25 @@
         public void onPlaybackCompleted(@NonNull MediaController controller) {}
 
         /**
+         * @deprecated Use {@link #onVideoSizeChanged(MediaController, VideoSize)} instead.
+         * @hide
+         */
+        @RestrictTo(LIBRARY_GROUP)
+        @Deprecated
+        public void onVideoSizeChanged(@NonNull MediaController controller, @NonNull MediaItem item,
+                @NonNull VideoSize videoSize) {}
+
+        /**
          * Called when video size is changed.
          *
          * @param controller the controller for this event
-         * @param item the media item for which the video size changed
          * @param videoSize the size of video
          *
          * @hide
          */
+        // TODO: Unhide this (b/134749006)
         @RestrictTo(LIBRARY_GROUP)
-        public void onVideoSizeChanged(@NonNull MediaController controller, @NonNull MediaItem item,
+        public void onVideoSizeChanged(@NonNull MediaController controller,
                 @NonNull VideoSize videoSize) {}
 
         /**
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaControllerImplBase.java b/media2/session/src/main/java/androidx/media2/session/MediaControllerImplBase.java
index 755a17e..3ceb640 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaControllerImplBase.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaControllerImplBase.java
@@ -1144,9 +1144,11 @@
         });
     }
 
-    void notifyVideoSizeChanged(final MediaItem item, final VideoSize videoSize) {
+    void notifyVideoSizeChanged(final VideoSize videoSize) {
+        final MediaItem currentItem;
         synchronized (mLock) {
             mVideoSize = videoSize;
+            currentItem = mCurrentMediaItem;
         }
         mInstance.notifyControllerCallback(new ControllerCallbackRunnable() {
             @Override
@@ -1154,7 +1156,11 @@
                 if (!mInstance.isConnected()) {
                     return;
                 }
-                callback.onVideoSizeChanged(mInstance, item, videoSize);
+
+                if (currentItem != null) {
+                    callback.onVideoSizeChanged(mInstance, currentItem, videoSize);
+                }
+                callback.onVideoSizeChanged(mInstance, videoSize);
             }
         });
     }
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaControllerStub.java b/media2/session/src/main/java/androidx/media2/session/MediaControllerStub.java
index 142dca2..8e16d21 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaControllerStub.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaControllerStub.java
@@ -242,23 +242,18 @@
 
     @Override
     public void onVideoSizeChanged(int seq, final ParcelImpl item, final ParcelImpl videoSize) {
-        if (item == null || videoSize == null) {
+        if (videoSize == null) {
             return;
         }
         dispatchControllerTask(new ControllerTask() {
             @Override
             public void run(MediaControllerImplBase controller) {
-                MediaItem itemObj = MediaParcelUtils.fromParcelable(item);
-                if (itemObj == null) {
-                    Log.w(TAG, "onVideoSizeChanged(): Ignoring null MediaItem");
-                    return;
-                }
                 VideoSize size = MediaParcelUtils.fromParcelable(videoSize);
                 if (size == null) {
                     Log.w(TAG, "onVideoSizeChanged(): Ignoring null VideoSize");
                     return;
                 }
-                controller.notifyVideoSizeChanged(itemObj, size);
+                controller.notifyVideoSizeChanged(size);
             }
         });
     }
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaLibraryServiceLegacyStub.java b/media2/session/src/main/java/androidx/media2/session/MediaLibraryServiceLegacyStub.java
index 062046a..7244f81 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaLibraryServiceLegacyStub.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaLibraryServiceLegacyStub.java
@@ -492,8 +492,7 @@
         }
 
         @Override
-        final void onVideoSizeChanged(int seq, @NonNull MediaItem item,
-                @NonNull VideoSize videoSize) {
+        void onVideoSizeChanged(int seq, @NonNull VideoSize videoSize) throws RemoteException {
             // No-op. BrowserCompat doesn't understand Controller features.
         }
 
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaSession.java b/media2/session/src/main/java/androidx/media2/session/MediaSession.java
index e9b13ad..d601bd7 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaSession.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaSession.java
@@ -1208,8 +1208,8 @@
                 int currentIdx, int previousIdx, int nextIdx) throws RemoteException;
         abstract void onPlaybackCompleted(int seq) throws RemoteException;
         abstract void onDisconnected(int seq) throws RemoteException;
-        abstract void onVideoSizeChanged(int seq, @NonNull MediaItem item,
-                @NonNull VideoSize videoSize) throws RemoteException;
+        abstract void onVideoSizeChanged(int seq, @NonNull VideoSize videoSize)
+                throws RemoteException;
         abstract void onTrackInfoChanged(int seq, List<TrackInfo> trackInfos,
                 TrackInfo selectedVideoTrack, TrackInfo selectedAudioTrack,
                 TrackInfo selectedSubtitleTrack, TrackInfo selectedMetadataTrack)
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaSessionImplBase.java b/media2/session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
index 7f42fc3..eee1bea 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaSessionImplBase.java
@@ -1536,17 +1536,22 @@
         }
 
         @Override
-        public void onVideoSizeChangedInternal(@NonNull final SessionPlayer player,
-                @NonNull final MediaItem item, @NonNull final VideoSize videoSize) {
+        public void onVideoSizeChanged(@NonNull SessionPlayer player, @NonNull VideoSize size) {
             dispatchRemoteControllerTask(player, new RemoteControllerTask() {
                 @Override
                 public void run(ControllerCb callback, int seq) throws RemoteException {
-                    callback.onVideoSizeChanged(seq, item, videoSize);
+                    callback.onVideoSizeChanged(seq, size);
                 }
             });
         }
 
         @Override
+        public void onVideoSizeChangedInternal(@NonNull final SessionPlayer player,
+                @NonNull final MediaItem item, @NonNull final VideoSize videoSize) {
+            onVideoSizeChanged(player, videoSize);
+        }
+
+        @Override
         public void onTrackInfoChanged(@NonNull SessionPlayer player,
                 @NonNull final List<TrackInfo> trackInfos) {
             final MediaSessionImplBase session = getSession();
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaSessionLegacyStub.java b/media2/session/src/main/java/androidx/media2/session/MediaSessionLegacyStub.java
index 367034f..4776445 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaSessionLegacyStub.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaSessionLegacyStub.java
@@ -732,7 +732,7 @@
         }
 
         @Override
-        void onVideoSizeChanged(int seq, @NonNull MediaItem item, @NonNull VideoSize videoSize) {
+        void onVideoSizeChanged(int seq, @NonNull VideoSize videoSize) throws RemoteException {
             // no-op
         }
 
@@ -947,7 +947,7 @@
         }
 
         @Override
-        void onVideoSizeChanged(int seq, @NonNull MediaItem item, @NonNull VideoSize videoSize) {
+        void onVideoSizeChanged(int seq, @NonNull VideoSize videoSize) throws RemoteException {
             // no-op
         }
 
diff --git a/media2/session/src/main/java/androidx/media2/session/MediaSessionStub.java b/media2/session/src/main/java/androidx/media2/session/MediaSessionStub.java
index 0507f33..6833d59 100644
--- a/media2/session/src/main/java/androidx/media2/session/MediaSessionStub.java
+++ b/media2/session/src/main/java/androidx/media2/session/MediaSessionStub.java
@@ -1432,11 +1432,9 @@
         }
 
         @Override
-        void onVideoSizeChanged(int seq, @NonNull MediaItem item, @NonNull VideoSize videoSize)
-                throws RemoteException {
-            ParcelImpl itemParcel = MediaParcelUtils.toParcelable(item);
+        void onVideoSizeChanged(int seq, @NonNull VideoSize videoSize) throws RemoteException {
             ParcelImpl videoSizeParcel = MediaParcelUtils.toParcelable(videoSize);
-            mIControllerCallback.onVideoSizeChanged(seq, itemParcel, videoSizeParcel);
+            mIControllerCallback.onVideoSizeChanged(seq, null, videoSizeParcel);
         }
 
         @Override
diff --git a/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerCallbackTest.java b/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerCallbackTest.java
index 8674218..9230345 100644
--- a/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerCallbackTest.java
+++ b/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/MediaControllerCallbackTest.java
@@ -865,7 +865,7 @@
         prepareLooper();
 
         final VideoSize testSize = new VideoSize(100, 42);
-        final CountDownLatch latch = new CountDownLatch(1);
+        final CountDownLatch latch = new CountDownLatch(2);
         final MediaController.ControllerCallback callback =
                 new MediaController.ControllerCallback() {
                     @Override
@@ -875,10 +875,18 @@
                         assertEquals(testSize, videoSize);
                         latch.countDown();
                     }
+
+                    @Override
+                    public void onVideoSizeChanged(@NonNull MediaController controller,
+                            @NonNull VideoSize videoSize) {
+                        assertEquals(testSize, videoSize);
+                        latch.countDown();
+                    }
                 };
 
         MediaController controller = createController(mRemoteSession2.getToken(), true, null,
                 callback);
+        mRemoteSession2.getMockPlayer().notifyCurrentMediaItemChanged(INDEX_FOR_UNKONWN_ITEM);
         mRemoteSession2.getMockPlayer().notifyVideoSizeChanged(testSize);
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
diff --git a/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/TestBrowserCallback.java b/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/TestBrowserCallback.java
index b7d38fb..70073cd 100644
--- a/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/TestBrowserCallback.java
+++ b/media2/session/version-compat-tests/current/client/src/androidTest/java/androidx/media2/test/client/tests/TestBrowserCallback.java
@@ -189,6 +189,12 @@
     }
 
     @Override
+    public void onVideoSizeChanged(@NonNull MediaController controller,
+            @NonNull VideoSize videoSize) {
+        mCallbackProxy.onVideoSizeChanged(controller, videoSize);
+    }
+
+    @Override
     public void onTrackInfoChanged(@NonNull MediaController controller,
             @NonNull List<SessionPlayer.TrackInfo> trackInfos) {
         mCallbackProxy.onTrackInfoChanged(controller, trackInfos);
diff --git a/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockPlayer.java b/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockPlayer.java
index eeee0e8..cbf4673 100644
--- a/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockPlayer.java
+++ b/media2/session/version-compat-tests/current/service/src/androidTest/java/androidx/media2/test/service/MockPlayer.java
@@ -622,6 +622,7 @@
                 @Override
                 public void run() {
                     callback.onVideoSizeChangedInternal(MockPlayer.this, dummyItem, videoSize);
+                    callback.onVideoSizeChanged(MockPlayer.this, videoSize);
                 }
             });
         }
diff --git a/navigation/benchmark/build.gradle b/navigation/benchmark/build.gradle
index 0a308dd..ad5d976 100644
--- a/navigation/benchmark/build.gradle
+++ b/navigation/benchmark/build.gradle
@@ -22,6 +22,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
index e20b2c8..3b2698d 100644
--- a/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
+++ b/navigation/navigation-runtime/src/androidTest/java/androidx/navigation/NavControllerTest.kt
@@ -16,11 +16,14 @@
 
 package androidx.navigation
 
+import android.app.Application
 import android.content.Context
 import android.net.Uri
 import android.os.Bundle
 import android.os.Parcel
 import android.os.Parcelable
+import androidx.lifecycle.AndroidViewModel
+import androidx.lifecycle.ViewModelProvider
 import androidx.lifecycle.ViewModelStore
 import androidx.navigation.test.R
 import androidx.navigation.testing.TestNavigator
@@ -890,6 +893,25 @@
     }
 
     @Test
+    fun testGetViewModelStoreOwnerAndroidViewModel() {
+        val navController = createNavController()
+        navController.setViewModelStore(ViewModelStore())
+        val navGraph = navController.navigatorProvider.navigation(
+            id = 1,
+            startDestination = R.id.start_test
+        ) {
+            test(R.id.start_test)
+        }
+        navController.setGraph(navGraph, null)
+
+        val owner = navController.getViewModelStoreOwner(navGraph.id)
+        assertThat(owner).isNotNull()
+        val viewModelProvider = ViewModelProvider(owner)
+        val viewModel = viewModelProvider[TestAndroidViewModel::class.java]
+        assertThat(viewModel).isNotNull()
+    }
+
+    @Test
     fun testSaveRestoreGetViewModelStoreOwner() {
         val hostStore = ViewModelStore()
         val navController = createNavController()
@@ -966,6 +988,8 @@
     }
 }
 
+class TestAndroidViewModel(application: Application) : AndroidViewModel(application)
+
 /**
  * [TestNavigator] that helps with testing saving and restoring state.
  */
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntry.java b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntry.java
index 8aaa08c..0b9c4e5d 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntry.java
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntry.java
@@ -16,10 +16,14 @@
 
 package androidx.navigation;
 
+import android.app.Application;
+import android.content.Context;
 import android.os.Bundle;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.lifecycle.HasDefaultViewModelProviderFactory;
+import androidx.lifecycle.ViewModelProvider;
 import androidx.lifecycle.ViewModelStore;
 import androidx.lifecycle.ViewModelStoreOwner;
 
@@ -28,7 +32,8 @@
 /**
  * Representation of an entry in the back stack of a {@link NavController}.
  */
-final class NavBackStackEntry implements ViewModelStoreOwner {
+final class NavBackStackEntry implements ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
+    private final Context mContext;
     private final NavDestination mDestination;
     private final Bundle mArgs;
 
@@ -37,13 +42,17 @@
     final UUID mId;
     private NavControllerViewModel mNavControllerViewModel;
 
-    NavBackStackEntry(@NonNull NavDestination destination, @Nullable Bundle args,
+    NavBackStackEntry(@NonNull Context context,
+            @NonNull NavDestination destination, @Nullable Bundle args,
             @Nullable NavControllerViewModel navControllerViewModel) {
-        this(UUID.randomUUID(), destination, args, navControllerViewModel);
+        this(context, destination, args, navControllerViewModel, UUID.randomUUID());
     }
 
-    NavBackStackEntry(@NonNull UUID uuid, @NonNull NavDestination destination,
-            @Nullable Bundle args, @Nullable NavControllerViewModel navControllerViewModel) {
+    NavBackStackEntry(@NonNull Context context,
+            @NonNull NavDestination destination, @Nullable Bundle args,
+            @Nullable NavControllerViewModel navControllerViewModel,
+            @NonNull UUID uuid) {
+        mContext = context;
         mId = uuid;
         mDestination = destination;
         mArgs = args;
@@ -77,4 +86,11 @@
     public ViewModelStore getViewModelStore() {
         return mNavControllerViewModel.getViewModelStore(mId);
     }
+
+    @NonNull
+    @Override
+    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
+        return ViewModelProvider.AndroidViewModelFactory.getInstance(
+                (Application) mContext.getApplicationContext());
+    }
 }
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.java b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.java
new file mode 100644
index 0000000..a39a6e1
--- /dev/null
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavBackStackEntryState.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2019 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.navigation;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import java.util.UUID;
+
+@SuppressLint("BanParcelableUsage")
+final class NavBackStackEntryState implements Parcelable {
+
+    private final UUID mUUID;
+    private final int mDestinationId;
+    private final Bundle mArgs;
+
+    NavBackStackEntryState(NavBackStackEntry entry) {
+        mUUID = entry.mId;
+        mDestinationId = entry.getDestination().getId();
+        mArgs = entry.getArguments();
+    }
+
+    @SuppressWarnings("WeakerAccess")
+    NavBackStackEntryState(Parcel in) {
+        mUUID = UUID.fromString(in.readString());
+        mDestinationId = in.readInt();
+        mArgs = in.readBundle(getClass().getClassLoader());
+    }
+
+    @NonNull
+    UUID getUUID() {
+        return mUUID;
+    }
+
+    int getDestinationId() {
+        return mDestinationId;
+    }
+
+    @Nullable
+    Bundle getArgs() {
+        return mArgs;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int i) {
+        parcel.writeString(mUUID.toString());
+        parcel.writeInt(mDestinationId);
+        parcel.writeBundle(mArgs);
+    }
+
+    public static final Parcelable.Creator<NavBackStackEntryState> CREATOR =
+            new Parcelable.Creator<NavBackStackEntryState>() {
+                @Override
+                public NavBackStackEntryState createFromParcel(Parcel in) {
+                    return new NavBackStackEntryState(in);
+                }
+
+                @Override
+                public NavBackStackEntryState[] newArray(int size) {
+                    return new NavBackStackEntryState[size];
+                }
+            };
+}
diff --git a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
index 3c8c015..112e24e 100644
--- a/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
+++ b/navigation/navigation-runtime/src/main/java/androidx/navigation/NavController.java
@@ -42,7 +42,6 @@
 import java.util.Deque;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.UUID;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -64,11 +63,8 @@
             "android-support-nav:controller:navigatorState";
     private static final String KEY_NAVIGATOR_STATE_NAMES =
             "android-support-nav:controller:navigatorState:names";
-    private static final String KEY_BACK_STACK_UUIDS =
-            "android-support-nav:controller:backStackUUIDs";
-    private static final String KEY_BACK_STACK_IDS = "android-support-nav:controller:backStackIds";
-    private static final String KEY_BACK_STACK_ARGS =
-            "android-support-nav:controller:backStackArgs";
+    private static final String KEY_BACK_STACK =
+            "android-support-nav:controller:backStack";
     static final String KEY_DEEP_LINK_IDS = "android-support-nav:controller:deepLinkIds";
     static final String KEY_DEEP_LINK_EXTRAS =
             "android-support-nav:controller:deepLinkExtras";
@@ -85,9 +81,7 @@
     private NavInflater mInflater;
     private NavGraph mGraph;
     private Bundle mNavigatorStateToRestore;
-    private String[] mBackStackUUIDsToRestore;
-    private int[] mBackStackIdsToRestore;
-    private Parcelable[] mBackStackArgsToRestore;
+    private Parcelable[] mBackStackToRestore;
     private boolean mDeepLinkHandled;
 
     private final Deque<NavBackStackEntry> mBackStack = new ArrayDeque<>();
@@ -474,25 +468,23 @@
                 }
             }
         }
-        if (mBackStackUUIDsToRestore != null) {
-            for (int index = 0; index < mBackStackUUIDsToRestore.length; index++) {
-                UUID uuid = UUID.fromString(mBackStackUUIDsToRestore[index]);
-                int destinationId = mBackStackIdsToRestore[index];
-                Bundle args = (Bundle) mBackStackArgsToRestore[index];
-                NavDestination node = findDestination(destinationId);
+        if (mBackStackToRestore != null) {
+            for (Parcelable parcelable : mBackStackToRestore) {
+                NavBackStackEntryState state = (NavBackStackEntryState) parcelable;
+                NavDestination node = findDestination(state.getDestinationId());
                 if (node == null) {
                     throw new IllegalStateException("unknown destination during restore: "
-                            + mContext.getResources().getResourceName(destinationId));
+                            + mContext.getResources().getResourceName(state.getDestinationId()));
                 }
+                Bundle args = state.getArgs();
                 if (args != null) {
                     args.setClassLoader(mContext.getClassLoader());
                 }
-                mBackStack.add(new NavBackStackEntry(uuid, node, args, mViewModel));
+                mBackStack.add(new NavBackStackEntry(mContext, node, args, mViewModel,
+                        state.getUUID()));
             }
             updateOnBackPressedCallbackEnabled();
-            mBackStackUUIDsToRestore = null;
-            mBackStackIdsToRestore = null;
-            mBackStackArgsToRestore = null;
+            mBackStackToRestore = null;
         }
         if (mGraph != null && mBackStack.isEmpty()) {
             boolean deepLinked = !mDeepLinkHandled && mActivity != null
@@ -873,7 +865,7 @@
             }
             // The mGraph should always be on the back stack after you navigate()
             if (mBackStack.isEmpty()) {
-                mBackStack.add(new NavBackStackEntry(mGraph, finalArgs, mViewModel));
+                mBackStack.add(new NavBackStackEntry(mContext, mGraph, finalArgs, mViewModel));
             }
             // Now ensure all intermediate NavGraphs are put on the back stack
             // to ensure that global actions work.
@@ -882,13 +874,14 @@
             while (destination != null && findDestination(destination.getId()) == null) {
                 NavGraph parent = destination.getParent();
                 if (parent != null) {
-                    hierarchy.addFirst(new NavBackStackEntry(parent, finalArgs, mViewModel));
+                    hierarchy.addFirst(new NavBackStackEntry(mContext, parent, finalArgs,
+                            mViewModel));
                 }
                 destination = parent;
             }
             mBackStack.addAll(hierarchy);
             // And finally, add the new destination with its default args
-            NavBackStackEntry newBackStackEntry = new NavBackStackEntry(newDest,
+            NavBackStackEntry newBackStackEntry = new NavBackStackEntry(mContext, newDest,
                     newDest.addInDefaultArgs(finalArgs), mViewModel);
             mBackStack.add(newBackStackEntry);
         }
@@ -971,18 +964,12 @@
             if (b == null) {
                 b = new Bundle();
             }
-            String[] backStackUUIDs = new String[mBackStack.size()];
-            int[] backStackIds = new int[mBackStack.size()];
-            Parcelable[] backStackArgs = new Parcelable[mBackStack.size()];
+            Parcelable[] backStack = new Parcelable[mBackStack.size()];
             int index = 0;
             for (NavBackStackEntry backStackEntry : mBackStack) {
-                backStackUUIDs[index] = backStackEntry.mId.toString();
-                backStackIds[index] = backStackEntry.getDestination().getId();
-                backStackArgs[index++] = backStackEntry.getArguments();
+                backStack[index++] = new NavBackStackEntryState(backStackEntry);
             }
-            b.putStringArray(KEY_BACK_STACK_UUIDS, backStackUUIDs);
-            b.putIntArray(KEY_BACK_STACK_IDS, backStackIds);
-            b.putParcelableArray(KEY_BACK_STACK_ARGS, backStackArgs);
+            b.putParcelableArray(KEY_BACK_STACK, backStack);
         }
         if (mDeepLinkHandled) {
             if (b == null) {
@@ -1011,9 +998,7 @@
         navState.setClassLoader(mContext.getClassLoader());
 
         mNavigatorStateToRestore = navState.getBundle(KEY_NAVIGATOR_STATE);
-        mBackStackUUIDsToRestore = navState.getStringArray(KEY_BACK_STACK_UUIDS);
-        mBackStackIdsToRestore = navState.getIntArray(KEY_BACK_STACK_IDS);
-        mBackStackArgsToRestore = navState.getParcelableArray(KEY_BACK_STACK_ARGS);
+        mBackStackToRestore = navState.getParcelableArray(KEY_BACK_STACK);
         mDeepLinkHandled = navState.getBoolean(KEY_DEEP_LINK_HANDLED);
     }
 
diff --git a/paging/common/api/3.0.0-alpha01.txt b/paging/common/api/3.0.0-alpha01.txt
index 9e3841a..0d44da6 100644
--- a/paging/common/api/3.0.0-alpha01.txt
+++ b/paging/common/api/3.0.0-alpha01.txt
@@ -71,7 +71,6 @@
 
   public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
     ctor public ItemKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data);
   }
 
@@ -111,13 +110,11 @@
 
   public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
   }
 
   public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
   }
@@ -331,7 +328,6 @@
 
   public abstract static class PositionalDataSource.LoadInitialCallback<T> {
     ctor public PositionalDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
     method public abstract void onResult(java.util.List<? extends T> data, int position);
   }
@@ -346,7 +342,6 @@
 
   public abstract static class PositionalDataSource.LoadRangeCallback<T> {
     ctor public PositionalDataSource.LoadRangeCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data);
   }
 
diff --git a/paging/common/api/api_lint.ignore b/paging/common/api/api_lint.ignore
index a443331..dec4b46 100644
--- a/paging/common/api/api_lint.ignore
+++ b/paging/common/api/api_lint.ignore
@@ -1,22 +1,12 @@
 // Baseline format: 1.0
 DocumentExceptions: androidx.paging.DataSource#getExecutor():
     Method DataSource.getExecutor appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
-DocumentExceptions: androidx.paging.ItemKeyedDataSource.LoadCallback#onError(Throwable):
-    Method LoadCallback.onError appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
-DocumentExceptions: androidx.paging.PageKeyedDataSource.LoadCallback#onError(Throwable):
-    Method LoadCallback.onError appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
-DocumentExceptions: androidx.paging.PageKeyedDataSource.LoadInitialCallback#onError(Throwable):
-    Method LoadInitialCallback.onError appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
 DocumentExceptions: androidx.paging.PagedList#loadAround(int):
     Method PagedList.loadAround appears to be throwing java.lang.IndexOutOfBoundsException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
 DocumentExceptions: androidx.paging.PagedList.Config.Builder#build():
     Method Builder.build appears to be throwing java.lang.IllegalArgumentException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
 DocumentExceptions: androidx.paging.PagedList.Config.Builder#setPageSize(int):
     Method Builder.setPageSize appears to be throwing java.lang.IllegalArgumentException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
-DocumentExceptions: androidx.paging.PositionalDataSource.LoadInitialCallback#onError(Throwable):
-    Method LoadInitialCallback.onError appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
-DocumentExceptions: androidx.paging.PositionalDataSource.LoadRangeCallback#onError(Throwable):
-    Method LoadRangeCallback.onError appears to be throwing java.lang.IllegalStateException; this should be listed in the documentation; see https://android.github.io/kotlin-guides/interop.html#document-exceptions
 
 
 EqualsAndHashCode: androidx.paging.DataSource.BaseResult#equals(Object):
diff --git a/paging/common/api/current.txt b/paging/common/api/current.txt
index 9e3841a..0d44da6 100644
--- a/paging/common/api/current.txt
+++ b/paging/common/api/current.txt
@@ -71,7 +71,6 @@
 
   public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
     ctor public ItemKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data);
   }
 
@@ -111,13 +110,11 @@
 
   public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
   }
 
   public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
   }
@@ -331,7 +328,6 @@
 
   public abstract static class PositionalDataSource.LoadInitialCallback<T> {
     ctor public PositionalDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
     method public abstract void onResult(java.util.List<? extends T> data, int position);
   }
@@ -346,7 +342,6 @@
 
   public abstract static class PositionalDataSource.LoadRangeCallback<T> {
     ctor public PositionalDataSource.LoadRangeCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data);
   }
 
diff --git a/paging/common/api/restricted_3.0.0-alpha01.txt b/paging/common/api/restricted_3.0.0-alpha01.txt
index e0ce8bc..73c6e1a 100644
--- a/paging/common/api/restricted_3.0.0-alpha01.txt
+++ b/paging/common/api/restricted_3.0.0-alpha01.txt
@@ -75,7 +75,6 @@
 
   public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
     ctor public ItemKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data);
   }
 
@@ -115,13 +114,11 @@
 
   public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
   }
 
   public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
   }
@@ -365,7 +362,6 @@
 
   public abstract static class PositionalDataSource.LoadInitialCallback<T> {
     ctor public PositionalDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
     method public abstract void onResult(java.util.List<? extends T> data, int position);
   }
@@ -380,7 +376,6 @@
 
   public abstract static class PositionalDataSource.LoadRangeCallback<T> {
     ctor public PositionalDataSource.LoadRangeCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data);
   }
 
diff --git a/paging/common/api/restricted_current.txt b/paging/common/api/restricted_current.txt
index e0ce8bc..73c6e1a 100644
--- a/paging/common/api/restricted_current.txt
+++ b/paging/common/api/restricted_current.txt
@@ -75,7 +75,6 @@
 
   public abstract static class ItemKeyedDataSource.LoadCallback<Value> {
     ctor public ItemKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data);
   }
 
@@ -115,13 +114,11 @@
 
   public abstract static class PageKeyedDataSource.LoadCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? adjacentPageKey);
   }
 
   public abstract static class PageKeyedDataSource.LoadInitialCallback<Key, Value> {
     ctor public PageKeyedDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends Value> data, int position, int totalCount, Key? previousPageKey, Key? nextPageKey);
     method public abstract void onResult(java.util.List<? extends Value> data, Key? previousPageKey, Key? nextPageKey);
   }
@@ -365,7 +362,6 @@
 
   public abstract static class PositionalDataSource.LoadInitialCallback<T> {
     ctor public PositionalDataSource.LoadInitialCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data, int position, int totalCount);
     method public abstract void onResult(java.util.List<? extends T> data, int position);
   }
@@ -380,7 +376,6 @@
 
   public abstract static class PositionalDataSource.LoadRangeCallback<T> {
     ctor public PositionalDataSource.LoadRangeCallback();
-    method public void onError(Throwable error);
     method public abstract void onResult(java.util.List<? extends T> data);
   }
 
diff --git a/paging/common/src/main/kotlin/androidx/paging/ItemKeyedDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/ItemKeyedDataSource.kt
index 5acb252..969e289 100644
--- a/paging/common/src/main/kotlin/androidx/paging/ItemKeyedDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/ItemKeyedDataSource.kt
@@ -23,7 +23,6 @@
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlin.coroutines.resume
-import kotlin.coroutines.resumeWithException
 
 /**
  * Incremental data loader for paging keyed content, where loaded content uses previously loaded
@@ -177,21 +176,6 @@
          * @param data List of items loaded from the [ItemKeyedDataSource].
          */
         abstract fun onResult(data: List<Value>)
-
-        /**
-         * Called to report an error from a DataSource.
-         *
-         * Call this method to report an error from [loadInitial], [loadBefore], or [loadAfter]
-         * methods.
-         *
-         * @param error The error that occurred during loading.
-         */
-        open fun onError(error: Throwable) {
-            // TODO: remove default implementation in 3.0
-            throw IllegalStateException(
-                "You must implement onError if implementing your own load callback"
-            )
-        }
     }
 
     @Suppress("RedundantVisibilityModifier") // Metalava doesn't inherit visibility properly.
@@ -220,10 +204,6 @@
                 override fun onResult(data: List<Value>) {
                     cont.resume(InitialResult(data))
                 }
-
-                override fun onError(error: Throwable) {
-                    cont.resumeWithException(error)
-                }
             })
         }
 
@@ -346,8 +326,4 @@
         override fun onResult(data: List<Value>) {
             resume(Result(data))
         }
-
-        override fun onError(error: Throwable) {
-            resumeWithException(error)
-        }
     }
diff --git a/paging/common/src/main/kotlin/androidx/paging/PageKeyedDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/PageKeyedDataSource.kt
index 4d133ac..25d5f3e 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PageKeyedDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PageKeyedDataSource.kt
@@ -22,7 +22,6 @@
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlin.coroutines.resume
-import kotlin.coroutines.resumeWithException
 
 /**
  * Incremental data loader for page-keyed content, where requests return keys for next/previous
@@ -170,20 +169,6 @@
          * can be loaded after.
          */
         abstract fun onResult(data: List<Value>, previousPageKey: Key?, nextPageKey: Key?)
-
-        /**
-         * Called to report an error from a DataSource.
-         *
-         * Call this method to report an error from [loadInitial].
-         *
-         * @param error The error that occurred during loading.
-         */
-        open fun onError(error: Throwable) {
-            // TODO: remove default implementation in 3.0
-            throw IllegalStateException(
-                "You must implement onError if implementing your own load callback"
-            )
-        }
     }
 
     /**
@@ -219,21 +204,6 @@
          * direction.
          */
         abstract fun onResult(data: List<Value>, adjacentPageKey: Key?)
-
-        /**
-         * Called to report an error from a DataSource.
-         *
-         * Call this method to report an error from your PageKeyedDataSource's [loadBefore] and
-         * [loadAfter] methods.
-         *
-         * @param error The error that occurred during loading.
-         */
-        open fun onError(error: Throwable) {
-            // TODO: remove default implementation in 3.0
-            throw IllegalStateException(
-                "You must implement onError if implementing your own load callback"
-            )
-        }
     }
 
     /**
@@ -271,10 +241,6 @@
                 override fun onResult(data: List<Value>, previousPageKey: Key?, nextPageKey: Key?) {
                     cont.resume(InitialResult(data, previousPageKey, nextPageKey))
                 }
-
-                override fun onError(error: Throwable) {
-                    cont.resumeWithException(error)
-                }
             })
         }
 
@@ -377,8 +343,4 @@
         override fun onResult(data: List<Value>, adjacentPageKey: Key?) {
             resume(Result(data, adjacentPageKey))
         }
-
-        override fun onError(error: Throwable) {
-            resumeWithException(error)
-        }
     }
diff --git a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
index 4386bc7..6d56579 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PagedList.kt
@@ -1127,8 +1127,8 @@
      * Retry any retryable errors associated with this [PagedList].
      *
      * If for example a network [PagedSource] append timed out, calling this method will retry the
-     * failed append load. Note that your [PagedSource] will need to pass `true` to `onError()` to
-     * signify the error as retryable.
+     * failed append load. Note that your [PagedSource] will need to implement
+     * [PagedSource.isRetryableError] to return `true` for errors that are retryable.
      *
      * You can observe loading state via [addWeakLoadStateListener], though generally this is done
      * through the [PagedListAdapter][androidx.paging.PagedListAdapter] or
diff --git a/paging/common/src/main/kotlin/androidx/paging/PositionalDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/PositionalDataSource.kt
index 6365c7c..64b9fb4 100644
--- a/paging/common/src/main/kotlin/androidx/paging/PositionalDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/PositionalDataSource.kt
@@ -24,7 +24,6 @@
 import androidx.paging.PositionalDataSource.LoadInitialCallback
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlin.coroutines.resume
-import kotlin.coroutines.resumeWithException
 
 /**
  * Position-based data loader for a fixed-size, countable data set, supporting fixed-size loads at
@@ -182,20 +181,6 @@
          * before the items in data that can be provided by this [DataSource], pass N.
          */
         abstract fun onResult(data: List<T>, position: Int)
-
-        /**
-         * Called to report an error from a DataSource.
-         *
-         * Call this method to report an error from [loadInitial].
-         *
-         * @param error The error that occurred during loading.
-         */
-        open fun onError(error: Throwable) {
-            // TODO: remove default implementation in 3.0
-            throw IllegalStateException(
-                "You must implement onError if implementing your own load callback"
-            )
-        }
     }
 
     /**
@@ -217,20 +202,6 @@
          * unless at end of list.
          */
         abstract fun onResult(data: List<T>)
-
-        /**
-         * Called to report an error from a [DataSource].
-         *
-         * Call this method to report an error from [loadRange].
-         *
-         * @param error The error that occurred during loading.
-         */
-        open fun onError(error: Throwable) {
-            // TODO: remove default implementation in 3.0
-            throw IllegalStateException(
-                "You must implement onError if implementing your own load callback"
-            )
-        }
     }
 
     /**
@@ -424,10 +395,6 @@
                     }
                 }
 
-                override fun onError(error: Throwable) {
-                    cont.resumeWithException(error)
-                }
-
                 private fun resume(params: LoadInitialParams, result: InitialResult<T>) {
                     if (params.placeholdersEnabled) {
                         result.validateForInitialTiling(params.pageSize)
@@ -459,10 +426,6 @@
                         else -> cont.resume(RangeResult(data))
                     }
                 }
-
-                override fun onError(error: Throwable) {
-                    cont.resumeWithException(error)
-                }
             })
         }
 
diff --git a/paging/common/src/main/kotlin/androidx/paging/WrapperItemKeyedDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/WrapperItemKeyedDataSource.kt
index 65047b9..386a370 100644
--- a/paging/common/src/main/kotlin/androidx/paging/WrapperItemKeyedDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/WrapperItemKeyedDataSource.kt
@@ -54,7 +54,7 @@
     }
 
     override fun loadInitial(params: LoadInitialParams<K>, callback: LoadInitialCallback<B>) {
-        source.loadInitial(params, object : ItemKeyedDataSource.LoadInitialCallback<A>() {
+        source.loadInitial(params, object : LoadInitialCallback<A>() {
             override fun onResult(data: List<A>, position: Int, totalCount: Int) {
                 callback.onResult(convertWithStashedKeys(data), position, totalCount)
             }
@@ -62,34 +62,22 @@
             override fun onResult(data: List<A>) {
                 callback.onResult(convertWithStashedKeys(data))
             }
-
-            override fun onError(error: Throwable) {
-                callback.onError(error)
-            }
         })
     }
 
     override fun loadAfter(params: LoadParams<K>, callback: LoadCallback<B>) {
-        source.loadAfter(params, object : ItemKeyedDataSource.LoadCallback<A>() {
+        source.loadAfter(params, object : LoadCallback<A>() {
             override fun onResult(data: List<A>) {
                 callback.onResult(convertWithStashedKeys(data))
             }
-
-            override fun onError(error: Throwable) {
-                callback.onError(error)
-            }
         })
     }
 
     override fun loadBefore(params: LoadParams<K>, callback: LoadCallback<B>) {
-        source.loadBefore(params, object : ItemKeyedDataSource.LoadCallback<A>() {
+        source.loadBefore(params, object : LoadCallback<A>() {
             override fun onResult(data: List<A>) {
                 callback.onResult(convertWithStashedKeys(data))
             }
-
-            override fun onError(error: Throwable) {
-                callback.onError(error)
-            }
         })
     }
 
diff --git a/paging/common/src/main/kotlin/androidx/paging/WrapperPageKeyedDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/WrapperPageKeyedDataSource.kt
index c49b480..2f17e3a 100644
--- a/paging/common/src/main/kotlin/androidx/paging/WrapperPageKeyedDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/WrapperPageKeyedDataSource.kt
@@ -34,7 +34,7 @@
     override fun invalidate() = source.invalidate()
 
     override fun loadInitial(params: LoadInitialParams<K>, callback: LoadInitialCallback<K, B>) {
-        source.loadInitial(params, object : PageKeyedDataSource.LoadInitialCallback<K, A>() {
+        source.loadInitial(params, object : LoadInitialCallback<K, A>() {
             override fun onResult(
                 data: List<A>,
                 position: Int,
@@ -50,26 +50,20 @@
                 val convertedData = convert(listFunction, data)
                 callback.onResult(convertedData, previousPageKey, nextPageKey)
             }
-
-            override fun onError(error: Throwable) = callback.onError(error)
         })
     }
 
     override fun loadBefore(params: LoadParams<K>, callback: LoadCallback<K, B>) {
-        source.loadBefore(params, object : PageKeyedDataSource.LoadCallback<K, A>() {
+        source.loadBefore(params, object : LoadCallback<K, A>() {
             override fun onResult(data: List<A>, adjacentPageKey: K?) =
                 callback.onResult(convert(listFunction, data), adjacentPageKey)
-
-            override fun onError(error: Throwable) = callback.onError(error)
         })
     }
 
     override fun loadAfter(params: LoadParams<K>, callback: LoadCallback<K, B>) {
-        source.loadAfter(params, object : PageKeyedDataSource.LoadCallback<K, A>() {
+        source.loadAfter(params, object : LoadCallback<K, A>() {
             override fun onResult(data: List<A>, adjacentPageKey: K?) =
                 callback.onResult(convert(listFunction, data), adjacentPageKey)
-
-            override fun onError(error: Throwable) = callback.onError(error)
         })
     }
 }
diff --git a/paging/common/src/main/kotlin/androidx/paging/WrapperPositionalDataSource.kt b/paging/common/src/main/kotlin/androidx/paging/WrapperPositionalDataSource.kt
index 683d670..8308e87 100644
--- a/paging/common/src/main/kotlin/androidx/paging/WrapperPositionalDataSource.kt
+++ b/paging/common/src/main/kotlin/androidx/paging/WrapperPositionalDataSource.kt
@@ -40,16 +40,12 @@
 
             override fun onResult(data: List<A>, position: Int) =
                 callback.onResult(convert(listFunction, data), position)
-
-            override fun onError(error: Throwable) = callback.onError(error)
         })
     }
 
     override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<B>) {
         source.loadRange(params, object : LoadRangeCallback<A>() {
             override fun onResult(data: List<A>) = callback.onResult(convert(listFunction, data))
-
-            override fun onError(error: Throwable) = callback.onError(error)
         })
     }
 }
diff --git a/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
index b847ea6..4068366 100644
--- a/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/ItemKeyedDataSourceTest.kt
@@ -88,7 +88,6 @@
     fun loadInitial_nullKey() = runBlocking {
         val dataSource = ItemDataSource()
 
-        // dispatchLoadInitial(null, count) == dispatchLoadInitial(count)
         val result = loadInitial(dataSource, null, 10, true)
 
         assertEquals(0, result.leadingNulls)
@@ -212,18 +211,10 @@
         private val counted: Boolean = true,
         private val items: List<Item> = ITEMS_BY_NAME_ID
     ) : ItemKeyedDataSource<Key, Item>() {
-        private var error = false
-
         override fun loadInitial(
             params: LoadInitialParams<Key>,
             callback: LoadInitialCallback<Item>
         ) {
-            if (error) {
-                callback.onError(EXCEPTION)
-                error = false
-                return
-            }
-
             val key = params.requestedInitialKey ?: Key("", Int.MAX_VALUE)
             val start = maxOf(0, findFirstIndexAfter(key) - params.requestedLoadSize / 2)
             val endExclusive = minOf(start + params.requestedLoadSize, items.size)
@@ -236,12 +227,6 @@
         }
 
         override fun loadAfter(params: LoadParams<Key>, callback: LoadCallback<Item>) {
-            if (error) {
-                callback.onError(EXCEPTION)
-                error = false
-                return
-            }
-
             val start = findFirstIndexAfter(params.key)
             val endExclusive = minOf(start + params.requestedLoadSize, items.size)
 
@@ -249,12 +234,6 @@
         }
 
         override fun loadBefore(params: LoadParams<Key>, callback: LoadCallback<Item>) {
-            if (error) {
-                callback.onError(EXCEPTION)
-                error = false
-                return
-            }
-
             val firstIndexBefore = findFirstIndexBefore(params.key)
             val endExclusive = maxOf(0, firstIndexBefore + 1)
             val start = maxOf(0, firstIndexBefore - params.requestedLoadSize + 1)
@@ -277,10 +256,6 @@
                 KEY_COMPARATOR.compare(key, getKey(items[it])) > 0
             } ?: -1
         }
-
-        fun enqueueError() {
-            error = true
-        }
     }
 
     private fun performLoadInitial(
@@ -408,10 +383,6 @@
                 override fun onResult(data: List<A>) {
                     callback.onResult(convert(data))
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -420,10 +391,6 @@
                 override fun onResult(data: List<A>) {
                     callback.onResult(convert(data))
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -432,10 +399,6 @@
                 override fun onResult(data: List<A>) {
                     callback.onResult(convert(data))
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -473,12 +436,8 @@
             loadInitialCallback
         )
         verify(loadInitialCallback).onResult(
-            ITEMS_BY_NAME_ID.subList(0, 10).map { DecoratedItem(it) })
-        //     error
-        orig.enqueueError()
-        wrapper.loadInitial(initParams, loadInitialCallback)
-        verify(loadInitialCallback).onError(EXCEPTION)
-        verifyNoMoreInteractions(loadInitialCallback)
+            ITEMS_BY_NAME_ID.subList(0, 10).map { DecoratedItem(it) }
+        )
 
         val key = orig.getKey(ITEMS_BY_NAME_ID[20])
         @Suppress("UNCHECKED_CAST")
@@ -487,22 +446,12 @@
         // load after
         wrapper.loadAfter(ItemKeyedDataSource.LoadParams(key, 10), loadCallback)
         verify(loadCallback).onResult(ITEMS_BY_NAME_ID.subList(21, 31).map { DecoratedItem(it) })
-        // load after - error
-        orig.enqueueError()
-        wrapper.loadAfter(ItemKeyedDataSource.LoadParams(key, 10), loadCallback)
-        verify(loadCallback).onError(EXCEPTION)
-        verifyNoMoreInteractions(loadCallback)
 
         // load before
         @Suppress("UNCHECKED_CAST")
         loadCallback = mock()
         wrapper.loadBefore(ItemKeyedDataSource.LoadParams(key, 10), loadCallback)
         verify(loadCallback).onResult(ITEMS_BY_NAME_ID.subList(10, 20).map { DecoratedItem(it) })
-        // load before - error
-        orig.enqueueError()
-        wrapper.loadBefore(ItemKeyedDataSource.LoadParams(key, 10), loadCallback)
-        verify(loadCallback).onError(EXCEPTION)
-        verifyNoMoreInteractions(loadCallback)
 
         // verify invalidation
         orig.invalidate()
@@ -555,7 +504,5 @@
                 (Math.random() * 200).toInt().toString() + " fake st."
             )
         }.sortedWith(ITEM_COMPARATOR)
-
-        private val EXCEPTION = Exception()
     }
 }
diff --git a/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
index 9d795f8..af58970 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PageKeyedDataSourceTest.kt
@@ -57,7 +57,6 @@
             callback: LoadInitialCallback<String, Item>
         ) {
             if (error) {
-                callback.onError(EXCEPTION)
                 error = false
                 return
             }
@@ -68,7 +67,6 @@
 
         override fun loadBefore(params: LoadParams<String>, callback: LoadCallback<String, Item>) {
             if (error) {
-                callback.onError(EXCEPTION)
                 error = false
                 return
             }
@@ -79,7 +77,6 @@
 
         override fun loadAfter(params: LoadParams<String>, callback: LoadCallback<String, Item>) {
             if (error) {
-                callback.onError(EXCEPTION)
                 error = false
                 return
             }
@@ -399,10 +396,6 @@
                 override fun onResult(data: List<A>, previousPageKey: K?, nextPageKey: K?) {
                     callback.onResult(convert(data), previousPageKey, nextPageKey)
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -411,10 +404,6 @@
                 override fun onResult(data: List<A>, adjacentPageKey: K?) {
                     callback.onResult(convert(data), adjacentPageKey)
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -423,10 +412,6 @@
                 override fun onResult(data: List<A>, adjacentPageKey: K?) {
                     callback.onResult(convert(data), adjacentPageKey)
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -471,7 +456,6 @@
         // load after - error
         orig.enqueueError()
         wrapper.loadAfter(PageKeyedDataSource.LoadParams(expectedInitial.next, 4), loadCallback)
-        verify(loadCallback).onError(EXCEPTION)
         verifyNoMoreInteractions(loadCallback)
 
         // load before
@@ -487,7 +471,6 @@
         // load before - error
         orig.enqueueError()
         wrapper.loadBefore(PageKeyedDataSource.LoadParams(expectedAfter.prev, 4), loadCallback)
-        verify(loadCallback).onError(EXCEPTION)
         verifyNoMoreInteractions(loadCallback)
 
         // verify invalidation
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
index 5146591b..4cad7b8 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PagedListTest.kt
@@ -23,7 +23,6 @@
 import kotlinx.coroutines.async
 import kotlinx.coroutines.runBlocking
 import org.junit.Assert.assertEquals
-import org.junit.Assert.fail
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
@@ -101,17 +100,14 @@
 
     @Test
     fun createAsyncThrow() {
-        val dataSource = object : PositionalDataSource<String>() {
-            override fun loadInitial(
-                params: LoadInitialParams,
-                callback: LoadInitialCallback<String>
-            ) {
-                callback.onError(Exception())
+        val pagedSource = object : PagedSource<Int, String>() {
+            override val keyProvider = KeyProvider.Positional<String>()
+
+            override suspend fun load(params: LoadParams<Int>): LoadResult<Int, String> {
+                throw Exception()
             }
 
-            override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<String>) {
-                fail("no load range expected")
-            }
+            override fun isRetryableError(error: Throwable) = false
         }
 
         val config = PagedList.Config.Builder()
@@ -122,7 +118,7 @@
         assertFails {
             val job = testCoroutineScope.async(backgroundThread.asCoroutineDispatcher()) {
                 PagedList.create(
-                    PagedSourceWrapper(dataSource),
+                    pagedSource,
                     testCoroutineScope,
                     mainThread,
                     backgroundThread,
diff --git a/paging/common/src/test/kotlin/androidx/paging/PagedSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/PagedSourceTest.kt
new file mode 100644
index 0000000..3ef86fb
--- /dev/null
+++ b/paging/common/src/test/kotlin/androidx/paging/PagedSourceTest.kt
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2019 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 androidx.paging.PagedSource.LoadParams
+import androidx.paging.PagedSource.LoadResult
+import androidx.paging.PagedSource.LoadResult.Companion.COUNT_UNDEFINED
+import androidx.paging.PagedSource.LoadType
+import kotlinx.coroutines.runBlocking
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import kotlin.test.assertFailsWith
+
+@RunWith(JUnit4::class)
+class PagedSourceTest {
+
+    // ----- STANDARD -----
+
+    private suspend fun loadInitial(
+        pagedSource: ItemDataSource,
+        key: Key?,
+        initialLoadSize: Int,
+        enablePlaceholders: Boolean
+    ): LoadResult<Key, Item> {
+        return pagedSource.load(
+            LoadParams(
+                LoadType.INITIAL,
+                key,
+                initialLoadSize,
+                enablePlaceholders,
+                10
+            )
+        )
+    }
+
+    @Test
+    fun loadInitial() {
+        runBlocking {
+            val pagedSource = ItemDataSource()
+            val key = pagedSource.keyProvider.getKey(ITEMS_BY_NAME_ID[49])
+            val result = loadInitial(pagedSource, key, 10, true)
+
+            assertEquals(45, result.itemsBefore)
+            assertEquals(ITEMS_BY_NAME_ID.subList(45, 55), result.data)
+            assertEquals(45, result.itemsAfter)
+
+            // Verify error is propagated correctly.
+            pagedSource.enqueueError()
+            val errorParams = LoadParams(LoadType.INITIAL, key, 10, false, 10)
+            assertFailsWith<CustomException> {
+                pagedSource.load(errorParams)
+            }
+        }
+    }
+
+    @Test
+    fun loadInitial_keyMatchesSingleItem() = runBlocking {
+        val pagedSource = ItemDataSource(items = ITEMS_BY_NAME_ID.subList(0, 1))
+
+        // this is tricky, since load after and load before with the passed key will fail
+        val result =
+            loadInitial(pagedSource, pagedSource.keyProvider.getKey(ITEMS_BY_NAME_ID[0]), 20, true)
+
+        assertEquals(0, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(0, 1), result.data)
+        assertEquals(0, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_keyMatchesLastItem() = runBlocking {
+        val pagedSource = ItemDataSource()
+
+        // tricky, because load after key is empty, so another load before and load after required
+        val key = pagedSource.keyProvider.getKey(ITEMS_BY_NAME_ID.last())
+        val result = loadInitial(pagedSource, key, 20, true)
+
+        assertEquals(90, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(90, 100), result.data)
+        assertEquals(0, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_nullKey() = runBlocking {
+        val dataSource = ItemDataSource()
+
+        val result = loadInitial(dataSource, null, 10, true)
+
+        assertEquals(0, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(0, 10), result.data)
+        assertEquals(90, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_keyPastEndOfList() = runBlocking {
+        val dataSource = ItemDataSource()
+
+        // if key is past entire data set, should return last items in data set
+        val key = Key("fz", 0)
+        val result = loadInitial(dataSource, key, 10, true)
+
+        // NOTE: ideally we'd load 10 items here, but it adds complexity and unpredictability to
+        // do: load after was empty, so pass full size to load before, since this can incur larger
+        // loads than requested (see keyMatchesLastItem test)
+        assertEquals(95, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(95, 100), result.data)
+        assertEquals(0, result.itemsAfter)
+    }
+
+    // ----- UNCOUNTED -----
+
+    @Test
+    fun loadInitial_disablePlaceholders() = runBlocking {
+        val dataSource = ItemDataSource()
+
+        // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
+        val key = dataSource.keyProvider.getKey(ITEMS_BY_NAME_ID[49])
+        val result = loadInitial(dataSource, key, 10, false)
+
+        assertEquals(COUNT_UNDEFINED, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(45, 55), result.data)
+        assertEquals(COUNT_UNDEFINED, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_uncounted() = runBlocking {
+        val dataSource = ItemDataSource(counted = false)
+
+        // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
+        val key = dataSource.keyProvider.getKey(ITEMS_BY_NAME_ID[49])
+        val result = loadInitial(dataSource, key, 10, true)
+
+        assertEquals(COUNT_UNDEFINED, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(45, 55), result.data)
+        assertEquals(COUNT_UNDEFINED, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_nullKey_uncounted() = runBlocking {
+        val dataSource = ItemDataSource(counted = false)
+
+        val result = loadInitial(dataSource, null, 10, true)
+
+        assertEquals(COUNT_UNDEFINED, result.itemsBefore)
+        assertEquals(ITEMS_BY_NAME_ID.subList(0, 10), result.data)
+        assertEquals(COUNT_UNDEFINED, result.itemsAfter)
+    }
+
+    // ----- EMPTY -----
+
+    @Test
+    fun loadInitial_empty() = runBlocking {
+        val dataSource = ItemDataSource(items = ArrayList())
+
+        // dispatchLoadInitial(key, count) == null padding, loadAfter(key, count), null padding
+        val key = dataSource.keyProvider.getKey(ITEMS_BY_NAME_ID[49])
+        val result = loadInitial(dataSource, key, 10, true)
+
+        assertEquals(0, result.itemsBefore)
+        assertTrue(result.data.isEmpty())
+        assertEquals(0, result.itemsAfter)
+    }
+
+    @Test
+    fun loadInitial_nullKey_empty() = runBlocking {
+        val dataSource = ItemDataSource(items = ArrayList())
+        val result = loadInitial(dataSource, null, 10, true)
+
+        assertEquals(0, result.itemsBefore)
+        assertTrue(result.data.isEmpty())
+        assertEquals(0, result.itemsAfter)
+    }
+
+    // ----- Other behavior -----
+
+    @Test
+    fun loadBefore() {
+        val dataSource = ItemDataSource()
+
+        runBlocking {
+            val key = dataSource.keyProvider.getKey(ITEMS_BY_NAME_ID[5])
+            val params = LoadParams(LoadType.START, key, 5, false, 5)
+            val observed = dataSource.load(params).data
+
+            assertEquals(ITEMS_BY_NAME_ID.subList(0, 5), observed)
+
+            // Verify error is propagated correctly.
+            dataSource.enqueueError()
+            assertFailsWith<CustomException> {
+                val errorParams = LoadParams(LoadType.START, key, 5, false, 5)
+                dataSource.load(errorParams)
+            }
+        }
+    }
+
+    @Test
+    fun loadAfter() {
+        val dataSource = ItemDataSource()
+
+        runBlocking {
+            val key = dataSource.keyProvider.getKey(ITEMS_BY_NAME_ID[5])
+            val params = LoadParams(LoadType.END, key, 5, false, 5)
+            val observed = dataSource.load(params).data
+
+            assertEquals(ITEMS_BY_NAME_ID.subList(6, 11), observed)
+
+            // Verify error is propagated correctly.
+            dataSource.enqueueError()
+            assertFailsWith<CustomException> {
+                val errorParams = LoadParams(LoadType.END, key, 5, false, 5)
+                dataSource.load(errorParams)
+            }
+        }
+    }
+
+    internal data class Key(val name: String, val id: Int)
+
+    internal data class Item(
+        val name: String,
+        val id: Int,
+        val balance: Double,
+        val address: String
+    )
+
+    internal class ItemDataSource(
+        private val counted: Boolean = true,
+        private val items: List<Item> = ITEMS_BY_NAME_ID
+    ) : PagedSource<Key, Item>() {
+        private var error = false
+
+        override val keyProvider = object : KeyProvider.ItemKey<Key, Item>() {
+            override fun getKey(item: Item) = Key(item.name, item.id)
+        }
+
+        override suspend fun load(params: LoadParams<Key>): LoadResult<Key, Item> {
+            return when (params.loadType) {
+                LoadType.INITIAL -> loadInitial(params)
+                LoadType.START -> loadBefore(params)
+                LoadType.END -> loadAfter(params)
+            }
+        }
+
+        override fun isRetryableError(error: Throwable) = false
+
+        private fun loadInitial(params: LoadParams<Key>): LoadResult<Key, Item> {
+            if (error) {
+                error = false
+                throw EXCEPTION
+            }
+
+            val key = params.key ?: Key("", Int.MAX_VALUE)
+            val start = maxOf(0, findFirstIndexAfter(key) - params.loadSize / 2)
+            val endExclusive = minOf(start + params.loadSize, items.size)
+
+            return if (params.placeholdersEnabled && counted) {
+                val data = items.subList(start, endExclusive)
+                LoadResult(
+                    itemsBefore = start,
+                    itemsAfter = items.size - data.size - start,
+                    data = data,
+                    offset = start
+                )
+            } else {
+                LoadResult(data = items.subList(start, endExclusive), offset = 0)
+            }
+        }
+
+        private fun loadAfter(params: LoadParams<Key>): LoadResult<Key, Item> {
+            if (error) {
+                error = false
+                throw EXCEPTION
+            }
+
+            val start = findFirstIndexAfter(params.key!!)
+            val endExclusive = minOf(start + params.loadSize, items.size)
+
+            return LoadResult(data = items.subList(start, endExclusive), offset = 0)
+        }
+
+        private fun loadBefore(params: LoadParams<Key>): LoadResult<Key, Item> {
+            if (error) {
+                error = false
+                throw EXCEPTION
+            }
+
+            val firstIndexBefore = findFirstIndexBefore(params.key!!)
+            val endExclusive = maxOf(0, firstIndexBefore + 1)
+            val start = maxOf(0, firstIndexBefore - params.loadSize + 1)
+
+            return LoadResult(data = items.subList(start, endExclusive), offset = 0)
+        }
+
+        private fun findFirstIndexAfter(key: Key): Int {
+            return items.indices.firstOrNull {
+                KEY_COMPARATOR.compare(key, keyProvider.getKey(items[it])) < 0
+            } ?: items.size
+        }
+
+        private fun findFirstIndexBefore(key: Key): Int {
+            return items.indices.reversed().firstOrNull {
+                KEY_COMPARATOR.compare(key, keyProvider.getKey(items[it])) > 0
+            } ?: -1
+        }
+
+        fun enqueueError() {
+            error = true
+        }
+    }
+
+    class CustomException : Exception()
+
+    companion object {
+        private val ITEM_COMPARATOR = compareBy<Item> { it.name }.thenByDescending { it.id }
+        private val KEY_COMPARATOR = compareBy<Key> { it.name }.thenByDescending { it.id }
+
+        private val ITEMS_BY_NAME_ID = List(100) {
+            val names = Array(10) { index -> "f" + ('a' + index) }
+            Item(
+                names[it % 10],
+                it,
+                Math.random() * 1000,
+                (Math.random() * 200).toInt().toString() + " fake st."
+            )
+        }.sortedWith(ITEM_COMPARATOR)
+
+        private val EXCEPTION = CustomException()
+    }
+}
diff --git a/paging/common/src/test/kotlin/androidx/paging/PositionalDataSourceTest.kt b/paging/common/src/test/kotlin/androidx/paging/PositionalDataSourceTest.kt
index 5c449fe..475fc4f 100644
--- a/paging/common/src/test/kotlin/androidx/paging/PositionalDataSourceTest.kt
+++ b/paging/common/src/test/kotlin/androidx/paging/PositionalDataSourceTest.kt
@@ -287,10 +287,6 @@
                 override fun onResult(data: List<A>, position: Int) {
                     callback.onResult(convert(data), position)
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -299,10 +295,6 @@
                 override fun onResult(data: List<A>) {
                     callback.onResult(convert(data))
                 }
-
-                override fun onError(error: Throwable) {
-                    callback.onError(error)
-                }
             })
         }
 
@@ -321,7 +313,6 @@
 
         override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<T>) {
             if (error) {
-                callback.onError(ERROR)
                 error = false
                 return
             }
@@ -338,7 +329,6 @@
 
         override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<T>) {
             if (error) {
-                callback.onError(ERROR)
                 error = false
                 return
             }
@@ -368,7 +358,6 @@
         // load initial - error
         orig.enqueueError()
         wrapper.loadInitial(initParams, loadInitialCallback)
-        verify(loadInitialCallback).onError(ERROR)
         verifyNoMoreInteractions(loadInitialCallback)
 
         // load range
@@ -380,7 +369,6 @@
         // load range - error
         orig.enqueueError()
         wrapper.loadRange(PositionalDataSource.LoadRangeParams(2, 3), loadRangeCallback)
-        verify(loadRangeCallback).onError(ERROR)
         verifyNoMoreInteractions(loadRangeCallback)
 
         // check invalidation behavior
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/ItemDataSource.kt b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/ItemDataSource.kt
index cc831a34..44b20ff 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/ItemDataSource.kt
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/ItemDataSource.kt
@@ -18,22 +18,30 @@
 
 import android.graphics.Color
 import androidx.annotation.ColorInt
-import androidx.paging.PositionalDataSource
+import androidx.paging.PagedSource
 import java.util.ArrayList
 import java.util.concurrent.atomic.AtomicBoolean
 
 val dataSourceError = AtomicBoolean(false)
+
 /**
  * Sample data source with artificial data.
  */
-internal class ItemDataSource : PositionalDataSource<Item>() {
+internal class ItemDataSource : PagedSource<Int, Item>() {
+    override val keyProvider = KeyProvider.Positional<Item>()
+
+    override suspend fun load(params: LoadParams<Int>) = when (params.loadType) {
+        LoadType.INITIAL -> loadInitial(params)
+        else -> loadRange(params)
+    }
+
     class RetryableItemError : Exception()
 
     private val mGenerationId = sGenerationId++
 
-    private fun loadRangeInternal(startPosition: Int, loadCount: Int): List<Item>? {
+    private fun loadRangeInternal(startPosition: Int, loadCount: Int): List<Item> {
         val items = ArrayList<Item>()
-        val end = Math.min(COUNT, startPosition + loadCount)
+        val end = minOf(COUNT, startPosition + loadCount)
         val bgColor = COLORS[mGenerationId % COLORS.size]
 
         Thread.sleep(1000)
@@ -45,41 +53,68 @@
             items.add(Item(i, "item $i", bgColor))
         }
         if (dataSourceError.compareAndSet(true, false)) {
-            return null
+            throw RetryableItemError()
         }
         return items
     }
 
+    override fun isRetryableError(error: Throwable): Boolean {
+        return error is RetryableItemError
+    }
+
     companion object {
         private const val COUNT = 60
 
         @ColorInt
         private val COLORS = intArrayOf(Color.RED, Color.BLUE, Color.BLACK)
-
         private var sGenerationId: Int = 0
     }
 
-    override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback<Item>) {
-        val position = computeInitialLoadPosition(params, COUNT)
-        val loadSize = computeInitialLoadSize(params, position, COUNT)
+    // TODO: Clean up logic only pertinent to tiling.
+    private fun computeStartPosition(params: LoadParams<Int>): Int {
+        val requestedStartPosition = params.key?.let { key ->
+            var initialPosition = key
+
+            if (params.placeholdersEnabled) {
+                // snap load size to page multiple (minimum two)
+                val initialLoadSize = maxOf(params.loadSize / params.pageSize, 2) * params.pageSize
+
+                // move start so the load is centered around the key, not starting at it
+                val idealStart = initialPosition - initialLoadSize / 2
+                initialPosition = maxOf(0, idealStart / params.pageSize * params.pageSize)
+            } else {
+                // not tiled, so don't try to snap or force multiple of a page size
+                initialPosition -= params.loadSize / 2
+            }
+
+            initialPosition
+        } ?: 0
+
+        var pageStart = requestedStartPosition / params.pageSize * params.pageSize
+
+        // maximum start pos is that which will encompass end of list
+        val maximumLoadPage =
+            (COUNT - params.loadSize + params.pageSize - 1) / params.pageSize * params.pageSize
+        pageStart = minOf(maximumLoadPage, pageStart)
+
+        // minimum start position is 0
+        return maxOf(0, pageStart)
+    }
+
+    private fun loadInitial(params: LoadParams<Int>): LoadResult<Int, Item> {
+        val position = computeStartPosition(params)
+        val loadSize = minOf(COUNT - position, params.loadSize)
         val data = loadRangeInternal(position, loadSize)
-        if (data == null) {
-            callback.onError(RetryableItemError())
-        } else {
-            callback.onResult(data, position, COUNT)
-        }
+        return LoadResult(
+            itemsBefore = position,
+            itemsAfter = COUNT - data.size - position,
+            data = data,
+            offset = 0
+        )
     }
 
-    override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<Item>) {
-        val data = loadRangeInternal(params.startPosition, params.loadSize)
-        if (data == null) {
-            callback.onError(RetryableItemError())
-        } else {
-            callback.onResult(data)
-        }
-    }
-
-    override fun isRetryableError(error: Throwable): Boolean {
-        return error is RetryableItemError
+    private fun loadRange(params: LoadParams<Int>): LoadResult<Int, Item> {
+        val data = loadRangeInternal(params.key ?: 0, params.loadSize)
+        return LoadResult(data = data, offset = 0)
     }
 }
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/PagedListItemViewModel.java b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/PagedListItemViewModel.java
index 5f2c5f3..31263ea 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/PagedListItemViewModel.java
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/custom/PagedListItemViewModel.java
@@ -16,12 +16,16 @@
 
 package androidx.paging.integration.testapp.custom;
 
+import android.annotation.SuppressLint;
+
 import androidx.annotation.NonNull;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.ViewModel;
-import androidx.paging.DataSource;
 import androidx.paging.LivePagedListBuilder;
 import androidx.paging.PagedList;
+import androidx.paging.PagedSource;
+
+import kotlin.jvm.functions.Function0;
 
 /**
  * Sample ViewModel backed by an artificial data source
@@ -30,22 +34,22 @@
     private ItemDataSource mDataSource;
     private final Object mDataSourceLock = new Object();
 
-    private final DataSource.Factory<Integer, Item> mFactory =
-            new DataSource.Factory<Integer, Item>() {
-        @NonNull
-        @Override
-        public DataSource<Integer, Item> create() {
-            ItemDataSource newDataSource = new ItemDataSource();
-            synchronized (mDataSourceLock) {
-                mDataSource = newDataSource;
-                return mDataSource;
-            }
-        }
-    };
+    private final Function0<PagedSource<Integer, Item>> mFactory =
+            new Function0<PagedSource<Integer, Item>>() {
+                @SuppressLint("SyntheticAccessor")
+                @NonNull
+                @Override
+                public PagedSource<Integer, Item> invoke() {
+                    ItemDataSource newDataSource = new ItemDataSource();
+                    synchronized (mDataSourceLock) {
+                        mDataSource = newDataSource;
+                        return mDataSource;
+                    }
+                }
+            };
 
     private LiveData<PagedList<Item>> mLivePagedList =
-            new LivePagedListBuilder<>(mFactory, 10)
-                    .build();
+            new LivePagedListBuilder<>(mFactory, 10).build();
 
     void invalidateList() {
         synchronized (mDataSourceLock) {
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListActivity.java b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListActivity.java
index 9f3d041..501ec82 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListActivity.java
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListActivity.java
@@ -43,8 +43,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_room_recycler_view);
         // TODO use by viewModels() once this class switches to Kotlin
-        final CustomerViewModel viewModel = new ViewModelProvider(this,
-                ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()))
+        final CustomerViewModel viewModel = new ViewModelProvider(this)
                 .get(CustomerViewModel.class);
 
         mRecyclerView = findViewById(R.id.recyclerview);
diff --git a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListRxActivity.java b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListRxActivity.java
index 54fe3bf..359c9b9 100644
--- a/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListRxActivity.java
+++ b/paging/integration-tests/testapp/src/main/java/androidx/paging/integration/testapp/room/RoomPagedListRxActivity.java
@@ -41,8 +41,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_recycler_view);
         // TODO use by viewModels() once this class switches to Kotlin
-        mViewModel = new ViewModelProvider(this,
-                ViewModelProvider.AndroidViewModelFactory.getInstance(getApplication()))
+        mViewModel = new ViewModelProvider(this)
                 .get(CustomerViewModel.class);
 
         RecyclerView recyclerView = findViewById(R.id.recyclerview);
diff --git a/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
index 303a62f..d10028a 100644
--- a/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
+++ b/paging/runtime/src/androidTest/java/androidx/paging/LivePagedListBuilderTest.kt
@@ -80,9 +80,9 @@
         ArchTaskExecutor.getInstance().setDelegate(null)
     }
 
-    class MockDataSourceFactory : DataSource.Factory<Int, String>() {
-        override fun create(): DataSource<Int, String> {
-            return MockDataSource()
+    class MockDataSourceFactory {
+        fun create(): PagedSource<Int, String> {
+            return MockPagedSource()
         }
 
         var throwable: Throwable? = null
@@ -91,28 +91,35 @@
             throwable = RETRYABLE_EXCEPTION
         }
 
-        private inner class MockDataSource : PositionalDataSource<String>() {
-            override fun loadInitial(
-                params: LoadInitialParams,
-                callback: LoadInitialCallback<String>
-            ) {
+        private inner class MockPagedSource : PagedSource<Int, String>() {
+            override val keyProvider = KeyProvider.Positional<String>()
+
+            override suspend fun load(params: LoadParams<Int>) = when (params.loadType) {
+                LoadType.INITIAL -> loadInitial(params)
+                else -> loadRange()
+            }
+
+            override fun isRetryableError(error: Throwable) = error === RETRYABLE_EXCEPTION
+
+            private fun loadInitial(params: LoadParams<Int>): LoadResult<Int, String> {
                 assertEquals(2, params.pageSize)
 
-                if (throwable != null) {
-
-                    callback.onError(throwable!!)
+                throwable?.let { error ->
                     throwable = null
-                } else {
-                    callback.onResult(listOf("a", "b"), 0, 4)
+                    throw error
                 }
+
+                val data = listOf("a", "b")
+                return LoadResult(
+                    itemsBefore = 0,
+                    itemsAfter = 4 - data.size,
+                    data = data,
+                    offset = 0
+                )
             }
 
-            override fun loadRange(params: LoadRangeParams, callback: LoadRangeCallback<String>) {
-                callback.onResult(listOf("c", "d"))
-            }
-
-            override fun isRetryableError(error: Throwable): Boolean {
-                return error === RETRYABLE_EXCEPTION
+            private fun loadRange(): LoadResult<Int, String> {
+                return LoadResult(data = listOf("c", "d"), offset = 0)
             }
         }
     }
@@ -121,8 +128,7 @@
     fun executorBehavior() {
         // specify a background executor via builder, and verify it gets used for all loads,
         // overriding default arch IO executor
-        @Suppress("DEPRECATION")
-        val livePagedList = LivePagedListBuilder(MockDataSourceFactory(), 2)
+        val livePagedList = LivePagedListBuilder(MockDataSourceFactory()::create, 2)
             .setFetchExecutor(backgroundExecutor)
             .build()
 
@@ -161,8 +167,7 @@
         val factory = MockDataSourceFactory()
         factory.enqueueRetryableError()
 
-        @Suppress("DEPRECATION")
-        val livePagedList = LivePagedListBuilder(factory, 2)
+        val livePagedList = LivePagedListBuilder(factory::create, 2)
             .setFetchExecutor(backgroundExecutor)
             .build()
 
diff --git a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
index 304af35..39754e2 100644
--- a/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
+++ b/paging/runtime/src/main/java/androidx/paging/AsyncPagedListDiffer.kt
@@ -68,7 +68,7 @@
  *     @Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
+ *         MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
  *         RecyclerView recyclerView = findViewById(R.id.user_list);
  *         final UserAdapter adapter = new UserAdapter();
  *         viewModel.usersList.observe(this, pagedList -> adapter.submitList(pagedList));
diff --git a/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt b/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
index e3849ad..a40db41 100644
--- a/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
+++ b/paging/runtime/src/main/java/androidx/paging/PagedListAdapter.kt
@@ -59,7 +59,7 @@
  *     @Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
+ *         MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
  *         RecyclerView recyclerView = findViewById(R.id.user_list);
  *         UserAdapter&lt;User> adapter = new UserAdapter();
  *         viewModel.usersList.observe(this, pagedList -> adapter.submitList(pagedList));
diff --git a/palette/palette/build.gradle b/palette/palette/build.gradle
index 1a785db..87eb258b 100644
--- a/palette/palette/build.gradle
+++ b/palette/palette/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     annotationProcessor(NULLAWAY)
diff --git a/percentlayout/percentlayout/build.gradle b/percentlayout/percentlayout/build.gradle
index 5b2ac05..e5c8470 100644
--- a/percentlayout/percentlayout/build.gradle
+++ b/percentlayout/percentlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api(ANDROIDX_ANNOTATION)
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/preference/build.gradle b/preference/build.gradle
index 43b0f07..8235c7a 100644
--- a/preference/build.gradle
+++ b/preference/build.gradle
@@ -30,7 +30,7 @@
     implementation("androidx.annotation:annotation:1.1.0")
     api("androidx.appcompat:appcompat:1.1.0-rc01")
     // TODO: change to alpha05 after release
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
     api("androidx.recyclerview:recyclerview:1.0.0")
diff --git a/recyclerview/recyclerview-benchmark/build.gradle b/recyclerview/recyclerview-benchmark/build.gradle
index 985934e..8b18e14 100644
--- a/recyclerview/recyclerview-benchmark/build.gradle
+++ b/recyclerview/recyclerview-benchmark/build.gradle
@@ -19,6 +19,7 @@
     id("AndroidXPlugin")
     id("com.android.library")
     id("kotlin-android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/recyclerview/recyclerview-selection/build.gradle b/recyclerview/recyclerview-selection/build.gradle
index ac2f787..a364be0 100644
--- a/recyclerview/recyclerview-selection/build.gradle
+++ b/recyclerview/recyclerview-selection/build.gradle
@@ -27,7 +27,7 @@
 dependencies {
     api(project(":recyclerview:recyclerview"))
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/recyclerview/recyclerview/build.gradle b/recyclerview/recyclerview/build.gradle
index 16d7734..4ec3faf 100644
--- a/recyclerview/recyclerview/build.gradle
+++ b/recyclerview/recyclerview/build.gradle
@@ -11,7 +11,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc02")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.customview:customview:1.0.0")
 
diff --git a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerExtraLayoutSpaceTest.java b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerExtraLayoutSpaceTest.java
index 40e4916..70b1225 100644
--- a/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerExtraLayoutSpaceTest.java
+++ b/recyclerview/recyclerview/src/androidTest/java/androidx/recyclerview/widget/LinearLayoutManagerExtraLayoutSpaceTest.java
@@ -304,7 +304,7 @@
                 mRecordExtraLayoutSpace = false;
                 mRecordedExtraLayoutSpace[0] = extraLayoutSpace[0];
                 mRecordedExtraLayoutSpace[1] = extraLayoutSpace[1];
-                getViewTreeObserver().addOnDrawListener(mLayoutRecorder);
+                getViewTreeObserver().addOnPreDrawListener(mLayoutRecorder);
             }
         }
 
@@ -316,7 +316,7 @@
         }
     }
 
-    class LayoutBoundsRecorder implements ViewTreeObserver.OnDrawListener {
+    class LayoutBoundsRecorder implements ViewTreeObserver.OnPreDrawListener {
         private final OrientationHelper mHelper;
         private final int[][] mBounds;
 
@@ -331,16 +331,17 @@
         }
 
         @Override
-        public void onDraw() {
+        public boolean onPreDraw() {
             if (!mHasRecorded) {
                 recordBounds();
                 mRecyclerView.post(new Runnable() {
                     @Override
                     public void run() {
-                        getViewTreeObserver().removeOnDrawListener(LayoutBoundsRecorder.this);
+                        getViewTreeObserver().removeOnPreDrawListener(LayoutBoundsRecorder.this);
                     }
                 });
             }
+            return true;
         }
 
         private void recordBounds() {
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/AsyncListDiffer.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/AsyncListDiffer.java
index 1c345be03..c1fdb87 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/AsyncListDiffer.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/AsyncListDiffer.java
@@ -67,7 +67,7 @@
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
+ *         MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
  *         RecyclerView recyclerView = findViewById(R.id.user_list);
  *         UserAdapter adapter = new UserAdapter();
  *         viewModel.usersList.observe(this, list -> adapter.submitList(list));
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/ListAdapter.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/ListAdapter.java
index d00e84c..6b1ad73 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/ListAdapter.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/ListAdapter.java
@@ -50,7 +50,7 @@
  *     {@literal @}Override
  *     public void onCreate(Bundle savedState) {
  *         super.onCreate(savedState);
- *         MyViewModel viewModel = ViewModelProviders.of(this).get(MyViewModel.class);
+ *         MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
  *         RecyclerView recyclerView = findViewById(R.id.user_list);
  *         UserAdapter&lt;User> adapter = new UserAdapter();
  *         viewModel.usersList.observe(this, list -> adapter.submitList(list));
diff --git a/room/benchmark/build.gradle b/room/benchmark/build.gradle
index 966d074..b13c3b9 100644
--- a/room/benchmark/build.gradle
+++ b/room/benchmark/build.gradle
@@ -20,6 +20,7 @@
     id("com.android.library")
     id("kotlin-android")
     id("kotlin-kapt")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
index 0c30d5c..4e926c7 100644
--- a/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
+++ b/samples/Support4Demos/src/main/java/com/example/android/supportv4/widget/BaseSwipeRefreshLayoutActivity.java
@@ -132,8 +132,7 @@
         setContentView(getLayoutId());
 
         // TODO use by viewModels() once this class switches to Kotlin
-        mViewModel = new ViewModelProvider(this,
-                new ViewModelProvider.NewInstanceFactory()).get(MyViewModel.class);
+        mViewModel = new ViewModelProvider(this).get(MyViewModel.class);
         mViewModel.refreshDone.observe(this, event -> {
             if (event.getContentIfNotHandled() != null) {
                 mSwipeRefreshWidget.setRefreshing(false);
diff --git a/sharetarget/build.gradle b/sharetarget/build.gradle
index b750a70..cc27624 100644
--- a/sharetarget/build.gradle
+++ b/sharetarget/build.gradle
@@ -25,7 +25,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     api(GUAVA_LISTENABLE_FUTURE)
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha02")
diff --git a/slices/benchmark/build.gradle b/slices/benchmark/build.gradle
index ecb41ad..f7cb0db 100644
--- a/slices/benchmark/build.gradle
+++ b/slices/benchmark/build.gradle
@@ -21,6 +21,7 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 914633c..63bbe8d 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -28,7 +28,7 @@
     implementation(project(":slice-core"))
     api(project(":remotecallback"))
     implementation "androidx.annotation:annotation:1.1.0"
-    implementation "androidx.core:core:1.1.0-rc01"
+    implementation "androidx.core:core:1.1.0"
     implementation project(':collection:collection')
 }
 
diff --git a/slidingpanelayout/build.gradle b/slidingpanelayout/build.gradle
index b9732d5..7738665 100644
--- a/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     api(project(":customview"))
 }
 
diff --git a/swiperefreshlayout/build.gradle b/swiperefreshlayout/build.gradle
index 1309851..46c3da4 100644
--- a/swiperefreshlayout/build.gradle
+++ b/swiperefreshlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
     api("androidx.interpolator:interpolator:1.0.0")
 
     androidTestImplementation(JUNIT)
diff --git a/textclassifier/api/1.0.0-alpha03.txt b/textclassifier/api/1.0.0-alpha03.txt
index 974299f..21567f3 100644
--- a/textclassifier/api/1.0.0-alpha03.txt
+++ b/textclassifier/api/1.0.0-alpha03.txt
@@ -2,7 +2,7 @@
 package androidx.textclassifier {
 
   public final class ConversationAction {
-    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle!);
+    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle);
     method public androidx.core.app.RemoteActionCompat? getAction();
     method @FloatRange(from=0, to=1) public float getConfidenceScore();
     method public android.os.Bundle getExtras();
diff --git a/textclassifier/api/current.txt b/textclassifier/api/current.txt
index 974299f..21567f3 100644
--- a/textclassifier/api/current.txt
+++ b/textclassifier/api/current.txt
@@ -2,7 +2,7 @@
 package androidx.textclassifier {
 
   public final class ConversationAction {
-    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle!);
+    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle);
     method public androidx.core.app.RemoteActionCompat? getAction();
     method @FloatRange(from=0, to=1) public float getConfidenceScore();
     method public android.os.Bundle getExtras();
diff --git a/textclassifier/api/restricted_1.0.0-alpha03.txt b/textclassifier/api/restricted_1.0.0-alpha03.txt
index e335921..2bfef3d 100644
--- a/textclassifier/api/restricted_1.0.0-alpha03.txt
+++ b/textclassifier/api/restricted_1.0.0-alpha03.txt
@@ -2,7 +2,7 @@
 package androidx.textclassifier {
 
   public final class ConversationAction {
-    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle!);
+    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle);
     method public androidx.core.app.RemoteActionCompat? getAction();
     method @FloatRange(from=0, to=1) public float getConfidenceScore();
     method public android.os.Bundle getExtras();
diff --git a/textclassifier/api/restricted_current.txt b/textclassifier/api/restricted_current.txt
index e335921..2bfef3d 100644
--- a/textclassifier/api/restricted_current.txt
+++ b/textclassifier/api/restricted_current.txt
@@ -2,7 +2,7 @@
 package androidx.textclassifier {
 
   public final class ConversationAction {
-    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle!);
+    method public static androidx.textclassifier.ConversationAction createFromBundle(android.os.Bundle);
     method public androidx.core.app.RemoteActionCompat? getAction();
     method @FloatRange(from=0, to=1) public float getConfidenceScore();
     method public android.os.Bundle getExtras();
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
index d2cd121..92508eb 100644
--- a/textclassifier/build.gradle
+++ b/textclassifier/build.gradle
@@ -13,7 +13,7 @@
     api("androidx.annotation:annotation:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     // TODO: change to 1.1.0-alpha04 after release
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/textclassifier/src/main/java/androidx/textclassifier/ConversationAction.java b/textclassifier/src/main/java/androidx/textclassifier/ConversationAction.java
index 9aa9288..866e49c 100644
--- a/textclassifier/src/main/java/androidx/textclassifier/ConversationAction.java
+++ b/textclassifier/src/main/java/androidx/textclassifier/ConversationAction.java
@@ -32,7 +32,12 @@
 
 import java.lang.annotation.Retention;
 
-/** Represents the action suggested by a {@link TextClassifier} on a given conversation. */
+/**
+ * Represents an action suggested by a {@link TextClassifier} on a given conversation.
+ *
+ * @see TextClassifier#suggestConversationActions(ConversationActions.Request)
+ * @see ConversationActions
+ */
 public final class ConversationAction {
 
     private static final String EXTRA_TYPE = "type";
@@ -214,7 +219,7 @@
      * Converts a bundle that was created using {@link #toBundle()} to a {@link ConversationAction}.
      */
     @NonNull
-    public static ConversationAction createFromBundle(Bundle bundle) {
+    public static ConversationAction createFromBundle(@NonNull Bundle bundle) {
         return new ConversationAction(
                 bundle.getString(EXTRA_TYPE),
                 (RemoteActionCompat) ParcelUtils.getVersionedParcelable(bundle, EXTRA_ACTION),
diff --git a/textclassifier/src/main/java/androidx/textclassifier/ConversationActions.java b/textclassifier/src/main/java/androidx/textclassifier/ConversationActions.java
index d7129dc..3ba6f20 100644
--- a/textclassifier/src/main/java/androidx/textclassifier/ConversationActions.java
+++ b/textclassifier/src/main/java/androidx/textclassifier/ConversationActions.java
@@ -36,6 +36,8 @@
 
 /**
  * Represents a list of actions suggested by a {@link TextClassifier} on a given conversation.
+ * <p>
+ * This is an object to store the result of {@link TextClassifier#suggestConversationActions(Request)}.
  *
  * @see TextClassifier#suggestConversationActions(Request)
  */
diff --git a/textclassifier/src/main/java/androidx/textclassifier/widget/ToolbarController.java b/textclassifier/src/main/java/androidx/textclassifier/widget/ToolbarController.java
index 26f0c7f..45c481f 100644
--- a/textclassifier/src/main/java/androidx/textclassifier/widget/ToolbarController.java
+++ b/textclassifier/src/main/java/androidx/textclassifier/widget/ToolbarController.java
@@ -226,18 +226,18 @@
     }
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
-    static void updateRectCoordinates(Rect rect, TextView textView, int start, int end) {
-        final int[] startXY = getCoordinates(textView, start);
-        final int[] endXY = getCoordinates(textView, end);
+    static void updateRectCoordinates(Rect rect, TextView textView, int startIndex, int endIndex) {
+        final int[] startXY = getCoordinates(textView, startIndex, /* startCoordinate= */ true);
+        final int[] endXY = getCoordinates(textView, endIndex, /* startCoordinate= */false);
         rect.set(startXY[0], startXY[1], endXY[0], endXY[1]);
         rect.sort();
     }
 
-    private static int[] getCoordinates(TextView textView, int index) {
+    private static int[] getCoordinates(TextView textView, int index, boolean startCoordinate) {
         final Layout layout = textView.getLayout();
         final int line = layout.getLineForOffset(index);
         final int x = (int) layout.getPrimaryHorizontal(index);
-        final int y = layout.getLineTop(line);
+        final int y = (startCoordinate) ? layout.getLineTop(line) : layout.getLineBottom(line);
         final int[] xy = new int[2];
         textView.getLocationOnScreen(xy);
         return new int[]{
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index b4cbc11..902b0d5 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/ui/integration-tests/benchmark/build.gradle b/ui/integration-tests/benchmark/build.gradle
index 43ecf2c..ab94dc5 100644
--- a/ui/integration-tests/benchmark/build.gradle
+++ b/ui/integration-tests/benchmark/build.gradle
@@ -24,6 +24,7 @@
     id("com.android.library")
     id("AndroidXUiPlugin")
     id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/ui/integration-tests/benchmark/src/main/java/androidx/ui/benchmark/BenchmarksExtensions.kt b/ui/integration-tests/benchmark/src/main/java/androidx/ui/benchmark/BenchmarksExtensions.kt
index fefbde1..bc6446b 100644
--- a/ui/integration-tests/benchmark/src/main/java/androidx/ui/benchmark/BenchmarksExtensions.kt
+++ b/ui/integration-tests/benchmark/src/main/java/androidx/ui/benchmark/BenchmarksExtensions.kt
@@ -231,9 +231,8 @@
             }
             testCase.recomposeSyncAssertHadChanges()
         }
+        activity.disposeComposition()
     }
-
-    activity.disposeComposition()
 }
 
 /**
@@ -255,9 +254,8 @@
             }
             testCase.measure()
         }
+        activity.disposeComposition()
     }
-
-    activity.disposeComposition()
 }
 
 /**
@@ -280,9 +278,8 @@
             }
             testCase.layout()
         }
+        activity.disposeComposition()
     }
-
-    activity.disposeComposition()
 }
 
 /**
@@ -310,7 +307,6 @@
                 testCase.finishDraw()
             }
         }
+        activity.disposeComposition()
     }
-
-    activity.disposeComposition()
 }
diff --git a/ui/ui-foundation/api/1.0.0-alpha01.txt b/ui/ui-foundation/api/1.0.0-alpha01.txt
index 26ee3a8..5edc08e 100644
--- a/ui/ui-foundation/api/1.0.0-alpha01.txt
+++ b/ui/ui-foundation/api/1.0.0-alpha01.txt
@@ -17,6 +17,11 @@
     method public static void DeterminateProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, kotlin.jvm.functions.Function0<kotlin.Unit> children);
   }
 
+  public final class DialogKt {
+    ctor public DialogKt();
+    method public static void Dialog(kotlin.jvm.functions.Function0<kotlin.Unit> onCloseRequest, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class SimpleImageKt {
     ctor public SimpleImageKt();
     method public static void SimpleImage(androidx.ui.painting.Image image, androidx.ui.graphics.Color? tint = null);
diff --git a/ui/ui-foundation/api/current.txt b/ui/ui-foundation/api/current.txt
index 26ee3a8..5edc08e 100644
--- a/ui/ui-foundation/api/current.txt
+++ b/ui/ui-foundation/api/current.txt
@@ -17,6 +17,11 @@
     method public static void DeterminateProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, kotlin.jvm.functions.Function0<kotlin.Unit> children);
   }
 
+  public final class DialogKt {
+    ctor public DialogKt();
+    method public static void Dialog(kotlin.jvm.functions.Function0<kotlin.Unit> onCloseRequest, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class SimpleImageKt {
     ctor public SimpleImageKt();
     method public static void SimpleImage(androidx.ui.painting.Image image, androidx.ui.graphics.Color? tint = null);
diff --git a/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt b/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
index 26ee3a8..5edc08e 100644
--- a/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
@@ -17,6 +17,11 @@
     method public static void DeterminateProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, kotlin.jvm.functions.Function0<kotlin.Unit> children);
   }
 
+  public final class DialogKt {
+    ctor public DialogKt();
+    method public static void Dialog(kotlin.jvm.functions.Function0<kotlin.Unit> onCloseRequest, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class SimpleImageKt {
     ctor public SimpleImageKt();
     method public static void SimpleImage(androidx.ui.painting.Image image, androidx.ui.graphics.Color? tint = null);
diff --git a/ui/ui-foundation/api/restricted_current.txt b/ui/ui-foundation/api/restricted_current.txt
index 26ee3a8..5edc08e 100644
--- a/ui/ui-foundation/api/restricted_current.txt
+++ b/ui/ui-foundation/api/restricted_current.txt
@@ -17,6 +17,11 @@
     method public static void DeterminateProgressIndicator(@FloatRange(from=0.0, to=1.0) float progress, kotlin.jvm.functions.Function0<kotlin.Unit> children);
   }
 
+  public final class DialogKt {
+    ctor public DialogKt();
+    method public static void Dialog(kotlin.jvm.functions.Function0<kotlin.Unit> onCloseRequest, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class SimpleImageKt {
     ctor public SimpleImageKt();
     method public static void SimpleImage(androidx.ui.painting.Image image, androidx.ui.graphics.Color? tint = null);
diff --git a/ui/ui-foundation/build.gradle b/ui/ui-foundation/build.gradle
index e2568bd..105aab3 100644
--- a/ui/ui-foundation/build.gradle
+++ b/ui/ui-foundation/build.gradle
@@ -40,6 +40,7 @@
     implementation project(":ui:ui-animation")
     implementation project(':ui:ui-framework')
     implementation project(':ui:ui-layout')
+    implementation project(':ui:ui-platform')
     implementation project(':ui:ui-text')
 
     testImplementation(ANDROIDX_TEST_RULES)
@@ -48,6 +49,7 @@
 
     androidTestImplementation project(':ui:ui-test')
 
+    androidTestImplementation(ANDROIDX_TEST_UIAUTOMATOR)
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(ANDROIDX_TEST_RUNNER)
     androidTestImplementation(JUNIT)
diff --git a/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/DialogSample.kt b/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/DialogSample.kt
new file mode 100644
index 0000000..2c01062c
--- /dev/null
+++ b/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/DialogSample.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.ui.foundation.samples
+
+import androidx.annotation.Sampled
+import androidx.compose.Composable
+import androidx.compose.composer
+import androidx.compose.state
+import androidx.compose.unaryPlus
+import androidx.ui.core.Text
+import androidx.ui.foundation.Dialog
+
+@Sampled
+@Composable
+fun DialogSample() {
+    val openDialog = +state { true }
+
+    if (openDialog.value) {
+        Dialog(onCloseRequest = { openDialog.value = false }) {
+            Text("This is a Dialog. Click outside to dismiss.")
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DialogUiTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DialogUiTest.kt
new file mode 100644
index 0000000..0bfd0af
--- /dev/null
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/DialogUiTest.kt
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2019 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.ui.foundation
+
+import androidx.test.filters.MediumTest
+import androidx.ui.test.createComposeRule
+import androidx.compose.composer
+import androidx.compose.state
+import androidx.compose.unaryPlus
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import androidx.ui.core.Text
+import androidx.ui.test.assertDoesNotExist
+import androidx.ui.test.assertIsVisible
+import androidx.ui.test.doClick
+import androidx.ui.test.findByText
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@MediumTest
+@RunWith(JUnit4::class)
+class DialogUiTest {
+    @get:Rule
+    val composeTestRule = createComposeRule(disableTransitions = true)
+
+    private val defaultText = "dialogText"
+
+    @Test
+    fun dialogTest_isShowingContent() {
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = {}) {
+                    Text(defaultText)
+                }
+            }
+        }
+
+        findByText(defaultText).assertIsVisible()
+    }
+
+    @Test
+    fun dialogTest_isNotDismissed_whenClicked() {
+        val textBeforeClick = "textBeforeClick"
+        val textAfterClick = "textAfterClick"
+
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+            val text = +state { textBeforeClick }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = {
+                    showDialog.value = false
+                }) {
+                    Clickable(onClick = { text.value = textAfterClick }) {
+                        Text(text = text.value)
+                    }
+                }
+            }
+        }
+
+        findByText(textBeforeClick).assertIsVisible()
+
+        // Click inside the dialog
+        findByText(textBeforeClick).doClick()
+
+        // Check that the Clickable was pressed and that the Dialog is still visible
+        findByText(textAfterClick).assertIsVisible()
+    }
+
+    @Test
+    fun dialogTest_isDismissed_whenSpecified() {
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = { showDialog.value = false }) {
+                    Text(defaultText)
+                }
+            }
+        }
+
+        findByText(defaultText).assertIsVisible()
+
+        // Click outside the dialog to dismiss it
+        val outsideX = 0
+        val outsideY = composeTestRule.displayMetrics.heightPixels / 2
+        UiDevice.getInstance(getInstrumentation()).click(outsideX, outsideY)
+
+        assertDoesNotExist { label.equals(defaultText) }
+    }
+
+    @Test
+    fun dialogTest_isNotDismissed_whenNotSpecified() {
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = {}) {
+                    Text(defaultText)
+                }
+            }
+        }
+
+        findByText(defaultText).assertIsVisible()
+
+        // Click outside the dialog to try to dismiss it
+        val outsideX = 0
+        val outsideY = composeTestRule.displayMetrics.heightPixels / 2
+        UiDevice.getInstance(getInstrumentation()).click(outsideX, outsideY)
+
+        // The Dialog should still be visible
+        findByText(defaultText).assertIsVisible()
+    }
+
+    @Test
+    fun dialogTest_isDismissed_whenSpecified_backButtonPressed() {
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = { showDialog.value = false }) {
+                    Text(defaultText)
+                }
+            }
+        }
+
+        findByText(defaultText).assertIsVisible()
+
+        // Click the back button to dismiss the Dialog
+        UiDevice.getInstance(getInstrumentation()).pressBack()
+
+        assertDoesNotExist { label.equals(defaultText) }
+    }
+
+    @Test
+    fun dialogTest_isNotDismissed_whenNotSpecified_backButtonPressed() {
+        composeTestRule.setContent {
+            val showDialog = +state { true }
+
+            if (showDialog.value) {
+                Dialog(onCloseRequest = {}) {
+                    Text(defaultText)
+                }
+            }
+        }
+
+        findByText(defaultText).assertIsVisible()
+
+        // Click the back button to try to dismiss the dialog
+        UiDevice.getInstance(getInstrumentation()).pressBack()
+
+        // The Dialog should still be visible
+        findByText(defaultText).assertIsVisible()
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
new file mode 100644
index 0000000..8ccc5b6
--- /dev/null
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 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.ui.foundation
+
+import android.app.Dialog
+import android.content.Context
+import android.view.MotionEvent
+import android.widget.FrameLayout
+import androidx.compose.Children
+import androidx.compose.Composable
+import androidx.compose.ambient
+import androidx.compose.disposeComposition
+import androidx.compose.memo
+import androidx.compose.onActive
+import androidx.compose.onCommit
+import androidx.compose.onDispose
+import androidx.compose.unaryPlus
+import androidx.ui.core.ContextAmbient
+import androidx.ui.core.setContent
+
+/**
+ * Opens a dialog with the given content.
+ *
+ * The dialog is visible as long as it is part of the composition hierarchy.
+ * In order to let the user dismiss the Dialog, the implementation of [onCloseRequest] should
+ * contain a way to remove to remove the dialog from the composition hierarchy.
+ *
+ * Example usage:
+ *
+ * @sample androidx.ui.foundation.samples.DialogSample
+ *
+ * @param onCloseRequest Executes when the user tries to dismiss the Dialog.
+ * @param children The content to be displayed inside the dialog.
+ */
+@Composable
+fun Dialog(onCloseRequest: () -> Unit, @Children children: @Composable() () -> Unit) {
+    val context = +ambient(ContextAmbient)
+
+    val dialog = +memo { DialogWrapper(context, onCloseRequest) }
+
+    +onActive {
+        dialog.show()
+
+        onDispose {
+            dialog.dismiss()
+            dialog.disposeComposition()
+        }
+    }
+
+    +onCommit {
+        dialog.setContent(children)
+    }
+}
+
+private class DialogWrapper(context: Context, val onCloseRequest: () -> Unit) : Dialog(context) {
+    val frameLayout = FrameLayout(context)
+    init {
+        setContentView(frameLayout)
+    }
+
+    fun setContent(@Children children: @Composable() () -> Unit) {
+        frameLayout.setContent(children)
+    }
+
+    fun disposeComposition() {
+        frameLayout.disposeComposition()
+    }
+
+    override fun onTouchEvent(event: MotionEvent): Boolean {
+        val result = super.onTouchEvent(event)
+        if (result) {
+            onCloseRequest()
+        }
+
+        return result
+    }
+
+    override fun cancel() {
+        // Prevents the dialog from dismissing itself
+        return
+    }
+
+    override fun onBackPressed() {
+        onCloseRequest()
+    }
+}
diff --git a/ui/ui-framework/api/1.0.0-alpha01.txt b/ui/ui-framework/api/1.0.0-alpha01.txt
index b53ffe0..c7820fa 100644
--- a/ui/ui-framework/api/1.0.0-alpha01.txt
+++ b/ui/ui-framework/api/1.0.0-alpha01.txt
@@ -296,16 +296,16 @@
 package androidx.ui.core.selection {
 
   public final class Selection {
-    ctor public Selection(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
-    method public androidx.ui.engine.geometry.Rect component1();
-    method public androidx.ui.engine.geometry.Rect component2();
+    ctor public Selection(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition component1();
+    method public androidx.ui.core.PxPosition component2();
     method public androidx.ui.core.LayoutCoordinates? component3();
     method public androidx.ui.core.LayoutCoordinates? component4();
-    method public androidx.ui.core.selection.Selection copy(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.selection.Selection copy(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition getEndCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getEndLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getEndOffset();
+    method public androidx.ui.core.PxPosition getStartCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getStartLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getStartOffset();
   }
 
   public final class SelectionContainerKt {
diff --git a/ui/ui-framework/api/current.txt b/ui/ui-framework/api/current.txt
index b53ffe0..c7820fa 100644
--- a/ui/ui-framework/api/current.txt
+++ b/ui/ui-framework/api/current.txt
@@ -296,16 +296,16 @@
 package androidx.ui.core.selection {
 
   public final class Selection {
-    ctor public Selection(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
-    method public androidx.ui.engine.geometry.Rect component1();
-    method public androidx.ui.engine.geometry.Rect component2();
+    ctor public Selection(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition component1();
+    method public androidx.ui.core.PxPosition component2();
     method public androidx.ui.core.LayoutCoordinates? component3();
     method public androidx.ui.core.LayoutCoordinates? component4();
-    method public androidx.ui.core.selection.Selection copy(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.selection.Selection copy(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition getEndCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getEndLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getEndOffset();
+    method public androidx.ui.core.PxPosition getStartCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getStartLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getStartOffset();
   }
 
   public final class SelectionContainerKt {
diff --git a/ui/ui-framework/api/restricted_1.0.0-alpha01.txt b/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
index b53ffe0..c7820fa 100644
--- a/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
@@ -296,16 +296,16 @@
 package androidx.ui.core.selection {
 
   public final class Selection {
-    ctor public Selection(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
-    method public androidx.ui.engine.geometry.Rect component1();
-    method public androidx.ui.engine.geometry.Rect component2();
+    ctor public Selection(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition component1();
+    method public androidx.ui.core.PxPosition component2();
     method public androidx.ui.core.LayoutCoordinates? component3();
     method public androidx.ui.core.LayoutCoordinates? component4();
-    method public androidx.ui.core.selection.Selection copy(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.selection.Selection copy(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition getEndCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getEndLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getEndOffset();
+    method public androidx.ui.core.PxPosition getStartCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getStartLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getStartOffset();
   }
 
   public final class SelectionContainerKt {
diff --git a/ui/ui-framework/api/restricted_current.txt b/ui/ui-framework/api/restricted_current.txt
index b53ffe0..c7820fa 100644
--- a/ui/ui-framework/api/restricted_current.txt
+++ b/ui/ui-framework/api/restricted_current.txt
@@ -296,16 +296,16 @@
 package androidx.ui.core.selection {
 
   public final class Selection {
-    ctor public Selection(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
-    method public androidx.ui.engine.geometry.Rect component1();
-    method public androidx.ui.engine.geometry.Rect component2();
+    ctor public Selection(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition component1();
+    method public androidx.ui.core.PxPosition component2();
     method public androidx.ui.core.LayoutCoordinates? component3();
     method public androidx.ui.core.LayoutCoordinates? component4();
-    method public androidx.ui.core.selection.Selection copy(androidx.ui.engine.geometry.Rect startOffset, androidx.ui.engine.geometry.Rect endOffset, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.selection.Selection copy(androidx.ui.core.PxPosition startCoordinates, androidx.ui.core.PxPosition endCoordinates, androidx.ui.core.LayoutCoordinates? startLayoutCoordinates, androidx.ui.core.LayoutCoordinates? endLayoutCoordinates);
+    method public androidx.ui.core.PxPosition getEndCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getEndLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getEndOffset();
+    method public androidx.ui.core.PxPosition getStartCoordinates();
     method public androidx.ui.core.LayoutCoordinates? getStartLayoutCoordinates();
-    method public androidx.ui.engine.geometry.Rect getStartOffset();
   }
 
   public final class SelectionContainerKt {
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
index 6da979c..7e1680cb 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
@@ -285,13 +285,12 @@
                             onSelectionChange = { internalSelection.value = it },
                             textPainter = textPainter
                         )
-
                         if (!textSelectionProcessor.isSelected) return null
 
                         // TODO(qqd): Determine a set of coordinates around a character that we need.
                         return Selection(
-                            startOffset = textSelectionProcessor.startOffset,
-                            endOffset = textSelectionProcessor.endOffset,
+                            startCoordinates = textSelectionProcessor.startCoordinates,
+                            endCoordinates = textSelectionProcessor.endCoordinates,
                             startLayoutCoordinates =
                             if (textSelectionProcessor.containsWholeSelectionStart) {
                                 layoutCoordinates.value!!
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
index f4c753a..6e2dd35 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/Selection.kt
@@ -17,24 +17,30 @@
 package androidx.ui.core.selection
 
 import androidx.ui.core.LayoutCoordinates
-import androidx.ui.engine.geometry.Rect
+import androidx.ui.core.PxPosition
 
 /**
  * Data class of Selection.
  */
 data class Selection(
     /**
-     * A box around the character at the start offset as Rect. This box' height is the line height,
-     * and the width is the advance. Note: It is temporary to use Rect.
+     * The coordinates of the graphical position for selection start character offset.
+     *
+     * This graphical position is the point at the left bottom corner for LTR
+     * character, or right bottom corner for RTL character.
+     *
+     * This coordinates is in child widget coordinates system.
      */
-    // TODO(qqd): After solving the problem of getting the coordinates of a character, figure out
-    // what should the startOffset and endOffset should be.
-    val startOffset: Rect,
+    val startCoordinates: PxPosition,
     /**
-     * A box around the character at the end offset as Rect. This box' height is the line height,
-     * and the width is the advance. Note: It is temporary to use Rect.
+     * The coordinates of the graphical position for selection end character offset.
+     *
+     * This graphical position is the point at the left bottom corner for LTR
+     * character, or right bottom corner for RTL character.
+     *
+     * This coordinates is in child widget coordinates system.
      */
-    val endOffset: Rect,
+    val endCoordinates: PxPosition,
     /**
      * The layout coordinates of the child which contains the start of the selection. If the child
      * does not contain the start of the selection, this should be null.
@@ -51,13 +57,13 @@
         var currentSelection = this.copy()
         if (other.startLayoutCoordinates != null) {
             currentSelection = currentSelection.copy(
-                startOffset = other.startOffset,
+                startCoordinates = other.startCoordinates,
                 startLayoutCoordinates = other.startLayoutCoordinates
             )
         }
         if (other.endLayoutCoordinates != null) {
             currentSelection = currentSelection.copy(
-                endOffset = other.endOffset,
+                endCoordinates = other.endCoordinates,
                 endLayoutCoordinates = other.endLayoutCoordinates
             )
         }
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
index 54f078c..a3bd5e5 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
@@ -25,11 +25,9 @@
 import androidx.ui.core.IntPx
 import androidx.ui.core.Layout
 import androidx.ui.core.OnPositioned
-import androidx.ui.core.PxPosition
 import androidx.ui.core.gesture.DragGestureDetector
 import androidx.ui.core.gesture.PressIndicatorGestureDetector
 import androidx.ui.core.ipx
-import androidx.ui.core.px
 import androidx.ui.core.round
 
 /**
@@ -129,17 +127,11 @@
                 ) {
                     val startOffset = manager.containerLayoutCoordinates.childToLocal(
                         selection.startLayoutCoordinates,
-                        PxPosition(
-                            selection.startOffset.left.px,
-                            selection.startOffset.bottom.px
-                        )
+                        selection.startCoordinates
                     )
                     val endOffset = manager.containerLayoutCoordinates.childToLocal(
                         selection.endLayoutCoordinates,
-                        PxPosition(
-                            selection.endOffset.right.px,
-                            selection.endOffset.bottom.px
-                        )
+                        selection.endCoordinates
                     )
                     start.place(startOffset.x - HANDLE_WIDTH, startOffset.y)
                     end.place(endOffset.x, endOffset.y)
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
index 99e2fa3..d7edee4 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionManager.kt
@@ -21,7 +21,6 @@
 import androidx.ui.core.PxPosition
 import androidx.ui.core.gesture.DragObserver
 import androidx.ui.core.px
-import androidx.ui.engine.geometry.Rect
 
 internal class SelectionManager : SelectionRegistrar {
     /**
@@ -99,11 +98,15 @@
         onSelectionChange(result)
     }
 
-    // Get the coordinates of a character. Currently, it's the middle point of the left edge of the
-    // bounding box of the character. This is a temporary solution.
-    // TODO(qqd): Read how Android solve this problem.
-    fun getCoordinatesForCharacter(box: Rect): PxPosition {
-        return PxPosition(box.left.px, box.top.px + (box.bottom.px - box.top.px) / 2)
+    /**
+     * Adjust coordinates for given text offset.
+     *
+     * Currently [android.text.Layout.getLineBottom] returns y coordinates of the next
+     * line's top offset, which is not included in current line's hit area. To be able to
+     * hit current line, move up this y coordinates by 1 pixel.
+     */
+    fun getAdjustedCoordinates(p: PxPosition): PxPosition {
+        return PxPosition(p.x, p.y - 1.px)
     }
 
     fun handleDragObserver(dragStartHandle: Boolean): DragObserver {
@@ -121,11 +124,11 @@
                 // The position of the character where the drag gesture should begin. This is in
                 // the widget coordinates.
                 val beginCoordinates =
-                    getCoordinatesForCharacter(
+                    getAdjustedCoordinates(
                         if (dragStartHandle) {
-                            selection!!.startOffset
+                            selection!!.startCoordinates
                         } else {
-                            selection!!.endOffset
+                            selection!!.endCoordinates
                         }
                     )
                 // Convert the position where drag gesture begins from widget coordinates to
@@ -150,7 +153,7 @@
                     } else {
                         containerLayoutCoordinates.childToLocal(
                             selection!!.startLayoutCoordinates!!,
-                            getCoordinatesForCharacter(selection!!.startOffset)
+                            getAdjustedCoordinates(selection!!.startCoordinates)
                         )
                     }
 
@@ -158,7 +161,7 @@
                     if (dragStartHandle) {
                         containerLayoutCoordinates.childToLocal(
                             selection!!.endLayoutCoordinates!!,
-                            getCoordinatesForCharacter(selection!!.endOffset)
+                            getAdjustedCoordinates(selection!!.endCoordinates)
                         )
                     } else {
                         dragBeginPosition + dragTotalDistance
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionProcessor.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionProcessor.kt
index 70819c7..23419ed 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionProcessor.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionProcessor.kt
@@ -18,7 +18,6 @@
 
 import androidx.ui.core.PxPosition
 import androidx.ui.core.px
-import androidx.ui.engine.geometry.Rect
 import androidx.ui.text.TextSelection
 import androidx.ui.text.TextPainter
 import kotlin.math.max
@@ -38,21 +37,24 @@
     /** The TextPainter object from Text widget. */
     val textPainter: TextPainter
 ) {
-    // TODO(qqd): Determine a set of coordinates around a character that we need.
     /**
-     * The bounding box of the character at the start character offset as Rect. The bounding box
-     * includes the top, bottom, left, and right of the character. Note: It is temporary to use
-     * Rect.
+     * The coordinates of the graphical position for selection start character offset.
+     *
+     * This graphical position is the point at the left bottom corner for LTR
+     * character, or right bottom corner for RTL character.
+     *
+     * This coordinates is in child widget coordinates system.
      */
-    // TODO(qqd): After solving the problem of getting the coordinates of a character, figure out
-    // what should the startOffset and endOffset should be.
-    internal var startOffset = Rect.zero
+    internal var startCoordinates: PxPosition = PxPosition.Origin
     /**
-     * The bounding box of the character at the end character offset as Rect. The bounding box
-     * includes the top, bottom, left, and right of the character. Note: It is temporary to use
-     * Rect.
+     * The coordinates of the graphical position for selection end character offset.
+     *
+     * This graphical position is the point at the left bottom corner for LTR
+     * character, or right bottom corner for RTL character.
+     *
+     * This coordinates is in child widget coordinates system.
      */
-    internal var endOffset = Rect.zero
+    internal var endCoordinates: PxPosition = PxPosition.Origin
     /**
      * A flag to check if the text widget contains the whole selection's start.
      */
@@ -95,22 +97,12 @@
             val wordBoundary = textPainter.getWordBoundary(textSelectionStart)
             textSelectionStart = wordBoundary.start
             textSelectionEnd = wordBoundary.end
-        } else {
-            // Currently the implementation of selection is inclusive-inclusive which is a temporary
-            // workaround, but inclusive-exclusive in Android. Thus before calling drawing selection
-            // background, make the selection matches Android behaviour.
-            textSelectionEnd = textSelectionEnd + 1
         }
 
         onSelectionChange(TextSelection(textSelectionStart, textSelectionEnd))
 
-        // Currently the implementation of selection is inclusive-inclusive which is a temporary
-        // workaround, but inclusive-exclusive in Android. Thus make the selection end matches Crane
-        // behaviour.
-        textSelectionEnd = textSelectionEnd - 1
-
-        startOffset = textPainter.getBoundingBox(textSelectionStart)
-        endOffset = textPainter.getBoundingBox(textSelectionEnd)
+        startCoordinates = getSelectionHandleCoordinates(textSelectionStart)
+        endCoordinates = getSelectionHandleCoordinates(textSelectionEnd)
 
         this.containsWholeSelectionStart = containsWholeSelectionStart
         this.containsWholeSelectionEnd = containsWholeSelectionEnd
@@ -155,4 +147,13 @@
         }
         return Pair(selectionBorder, containsWholeSelectionBorder)
     }
+
+    private fun getSelectionHandleCoordinates(offset: Int): PxPosition {
+        val left = textPainter.getPrimaryHorizontal(offset)
+
+        val line = textPainter.getLineForOffset(offset)
+        val bottom = textPainter.getLineBottom(line)
+
+        return PxPosition(left.px, bottom.px)
+    }
 }
diff --git a/ui/ui-layout/build.gradle b/ui/ui-layout/build.gradle
index d467d30..2af0b7e 100644
--- a/ui/ui-layout/build.gradle
+++ b/ui/ui-layout/build.gradle
@@ -27,6 +27,7 @@
     id("com.android.library")
     id("AndroidXUiPlugin")
     id("org.jetbrains.kotlin.android")
+    id("androidx.benchmark")
 }
 
 dependencies {
diff --git a/ui/ui-text/api/1.0.0-alpha01.txt b/ui/ui-text/api/1.0.0-alpha01.txt
index b3eed96..59a09a0 100644
--- a/ui/ui-text/api/1.0.0-alpha01.txt
+++ b/ui/ui-text/api/1.0.0-alpha01.txt
@@ -78,7 +78,6 @@
 
   public interface Paragraph {
     method public float getBaseline();
-    method public androidx.ui.engine.geometry.Rect getBoundingBox(int offset);
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
     method public boolean getDidExceedMaxLines();
     method public float getHeight();
diff --git a/ui/ui-text/api/current.txt b/ui/ui-text/api/current.txt
index b3eed96..59a09a0 100644
--- a/ui/ui-text/api/current.txt
+++ b/ui/ui-text/api/current.txt
@@ -78,7 +78,6 @@
 
   public interface Paragraph {
     method public float getBaseline();
-    method public androidx.ui.engine.geometry.Rect getBoundingBox(int offset);
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
     method public boolean getDidExceedMaxLines();
     method public float getHeight();
diff --git a/ui/ui-text/api/restricted_1.0.0-alpha01.txt b/ui/ui-text/api/restricted_1.0.0-alpha01.txt
index e44dfa9..cb841ce 100644
--- a/ui/ui-text/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-text/api/restricted_1.0.0-alpha01.txt
@@ -92,7 +92,6 @@
 
   public interface Paragraph {
     method public float getBaseline();
-    method public androidx.ui.engine.geometry.Rect getBoundingBox(int offset);
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
     method public boolean getDidExceedMaxLines();
     method public float getHeight();
diff --git a/ui/ui-text/api/restricted_current.txt b/ui/ui-text/api/restricted_current.txt
index e44dfa9..cb841ce 100644
--- a/ui/ui-text/api/restricted_current.txt
+++ b/ui/ui-text/api/restricted_current.txt
@@ -92,7 +92,6 @@
 
   public interface Paragraph {
     method public float getBaseline();
-    method public androidx.ui.engine.geometry.Rect getBoundingBox(int offset);
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
     method public boolean getDidExceedMaxLines();
     method public float getHeight();
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/Paragraph.kt b/ui/ui-text/src/main/java/androidx/ui/text/Paragraph.kt
index 145b6ac..a6a8156 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/Paragraph.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/Paragraph.kt
@@ -15,6 +15,7 @@
  */
 package androidx.ui.text
 
+import androidx.annotation.RestrictTo
 import androidx.ui.core.Density
 import androidx.ui.core.PxPosition
 import androidx.ui.engine.geometry.Rect
@@ -103,19 +104,47 @@
     /** Returns the right x Coordinate of the given line. */
     fun getLineRight(lineIndex: Int): Float
 
+    /**
+     * Returns the bottom y coordinate of the given line.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getLineBottom(lineIndex: Int): Float
+
     /** Returns the height of the given line. */
     fun getLineHeight(lineIndex: Int): Float
 
     /** Returns the width of the given line. */
     fun getLineWidth(lineIndex: Int): Float
 
+    /**
+     * Returns the line number on which the specified text offset appears.
+     * If you ask for a position before 0, you get 0; if you ask for a position
+     * beyond the end of the text, you get the last line.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getLineForOffset(offset: Int): Int
+
+    /**
+     * Get the primary horizontal position for the specified text offset.
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getPrimaryHorizontal(offset: Int): Float
+
     /** Returns the character offset closest to the given graphical position. */
     fun getOffsetForPosition(position: PxPosition): Int
 
     /**
      * Returns the bounding box as Rect of the character for given character offset. Rect
      * includes the top, bottom, left and right of a character.
+     *
+     * @hide
      */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
     fun getBoundingBox(offset: Int): Rect
 
     /**
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
index 67e1eed..7880c2d 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
@@ -471,6 +471,41 @@
         canvas.drawRect(cursorRect, Paint().apply { this.color = Color.Black })
     }
 
+    /**
+     * Returns the bottom y coordinate of the given line.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getLineBottom(lineIndex: Int): Float {
+        assert(!needsLayout)
+        return paragraph!!.getLineBottom(lineIndex)
+    }
+
+    /**
+     * Returns the line number on which the specified text offset appears.
+     * If you ask for a position before 0, you get 0; if you ask for a position
+     * beyond the end of the text, you get the last line.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getLineForOffset(offset: Int): Int {
+        assert(!needsLayout)
+        return paragraph!!.getLineForOffset(offset)
+    }
+
+    /**
+     * Get the primary horizontal position for the specified text offset.
+     *
+     * @hide
+     */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    fun getPrimaryHorizontal(offset: Int): Float {
+        assert(!needsLayout)
+        return paragraph!!.getPrimaryHorizontal(offset)
+    }
+
     /** Returns the character offset closest to the given graphical position. */
     fun getOffsetForPosition(position: PxPosition): Int {
         assert(!needsLayout)
@@ -503,4 +538,4 @@
         assert(!needsLayout)
         return paragraph!!.getWordBoundary(offset)
     }
-}
\ No newline at end of file
+}
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/platform/AndroidParagraph.kt b/ui/ui-text/src/main/java/androidx/ui/text/platform/AndroidParagraph.kt
index 7ed0a23..054eb01 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/platform/AndroidParagraph.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/platform/AndroidParagraph.kt
@@ -267,10 +267,17 @@
 
     override fun getLineRight(lineIndex: Int): Float = ensureLayout.getLineRight(lineIndex)
 
+    override fun getLineBottom(lineIndex: Int): Float = ensureLayout.getLineBottom(lineIndex)
+
     override fun getLineHeight(lineIndex: Int): Float = ensureLayout.getLineHeight(lineIndex)
 
     override fun getLineWidth(lineIndex: Int): Float = ensureLayout.getLineWidth(lineIndex)
 
+    override fun getLineForOffset(offset: Int): Int = ensureLayout.getLineForOffset(offset)
+
+    override fun getPrimaryHorizontal(offset: Int): Float =
+        ensureLayout.getPrimaryHorizontal(offset)
+
     /**
      * @return true if the given line is ellipsized, else false.
      */
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
index 2559de8..f1f7e65 100644
--- a/viewpager/build.gradle
+++ b/viewpager/build.gradle
@@ -17,7 +17,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     api(project(":customview"))
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index 9de6aa7..29ea26d 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -27,7 +27,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0-rc01")
+    implementation("androidx.core:core:1.1.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
     api("androidx.recyclerview:recyclerview:1.1.0-beta01")
     implementation("androidx.collection:collection:1.1.0")
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
new file mode 100644
index 0000000..4a3337c
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/TransientStateFragmentTest.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 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 android.view.View
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.FragmentManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.TimeUnit.MILLISECONDS
+
+/**
+ * Verifies that [androidx.viewpager2.adapter.FragmentStateAdapter] can handle [Fragment]s
+ * having transient state.
+ */
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class TransientStateFragmentTest : BaseTest() {
+    private val orientation = ORIENTATION_HORIZONTAL
+    private val totalPages = 10
+    private val adapterProvider = fragmentAdapterProviderValueId
+    private val timeoutMs = 3000L
+
+    @Test
+    fun test_swipeBetweenPages() {
+        setUpTest(orientation).apply {
+            val expectedValues = stringSequence(totalPages)
+            val adapter = adapterProvider(expectedValues)
+
+            val fragmentManager = activity.supportFragmentManager
+
+            val transientStateCallback = createTransientStateCallback()
+            fragmentManager.registerFragmentLifecycleCallbacks(transientStateCallback, false)
+            setAdapterSync(adapter)
+
+            assertBasicState(0)
+            listOf(1, 0, 1, 2, 3, 4, 3).plus(4 until totalPages).forEach { target ->
+                val latch = viewPager.addWaitForIdleLatch()
+                swipe(viewPager.currentItem, target)
+                latch.await(timeoutMs, MILLISECONDS)
+                assertBasicState(target)
+            }
+
+            fragmentManager.unregisterFragmentLifecycleCallbacks(transientStateCallback)
+        }
+    }
+
+    private fun createTransientStateCallback(): FragmentManager.FragmentLifecycleCallbacks {
+        return object : FragmentManager.FragmentLifecycleCallbacks() {
+            override fun onFragmentViewCreated(
+                fm: FragmentManager,
+                f: Fragment,
+                v: View,
+                savedInstanceState: Bundle?
+            ) {
+                v.setHasTransientState(true)
+            }
+        }
+    }
+}
diff --git a/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java b/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
index 435762c..a07954e 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
+++ b/viewpager2/src/main/java/androidx/viewpager2/adapter/FragmentStateAdapter.java
@@ -395,12 +395,20 @@
 
     @Override
     public final boolean onFailedToRecycleView(@NonNull FragmentViewHolder holder) {
-        // This happens when a ViewHolder is in a transient state (e.g. during custom
-        // animation). We don't have sufficient information on how to clear up what lead to
-        // the transient state, so we are throwing away the ViewHolder to stay on the
-        // conservative side.
-        onViewRecycled(holder); // the same clean-up steps as when recycling a ViewHolder
-        return false; // don't recycle the view
+        /*
+         This happens when a ViewHolder is in a transient state (e.g. during an
+         animation).
+
+         Our ViewHolders are effectively just FrameLayout instances in which we put Fragment
+         Views, so it's safe to force recycle them. This is because:
+         - FrameLayout instances are not to be directly manipulated, so no animations are
+         expected to be running directly on them.
+         - Fragment Views are not reused between position (one Fragment = one page). Animation
+         running in one of the Fragment Views won't affect another Fragment View.
+         - If a user chooses to violate these assumptions, they are also in the position to
+         correct the state in their code.
+        */
+        return true;
     }
 
     private void removeFragment(long itemId) {
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 8c0c18d..622bf29 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0-rc01")
+    api("androidx.core:core:1.1.0")
 
     androidTestImplementation(OKHTTP_MOCKWEBSERVER)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/webkit/src/androidTest/java/androidx/webkit/WebViewAssetLoaderTest.java b/webkit/src/androidTest/java/androidx/webkit/WebViewAssetLoaderTest.java
index db29999..f5a667b 100644
--- a/webkit/src/androidTest/java/androidx/webkit/WebViewAssetLoaderTest.java
+++ b/webkit/src/androidTest/java/androidx/webkit/WebViewAssetLoaderTest.java
@@ -395,6 +395,48 @@
         assertResponse(response, FakeTextPathHandler.CONTENTS);
     }
 
+    @Test
+    @SmallTest
+    public void testMimeTypeInPathHandlers() throws Throwable {
+        final String testHtmlContents = "<body><div>test</div></body>";
+
+        AssetHelper mockAssetHelper = new MockAssetHelper() {
+            @Override
+            public InputStream openResource(Uri uri) {
+                try {
+                    return new ByteArrayInputStream(testHtmlContents.getBytes(ENCODING));
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        };
+
+        WebViewAssetLoader assetLoader = new WebViewAssetLoader.Builder()
+                .addPathHandler("/assets/", new AssetsPathHandler(mockAssetHelper))
+                .addPathHandler("/res/", new ResourcesPathHandler(mockAssetHelper))
+                .build();
+
+        WebResourceResponse response = assetLoader.shouldInterceptRequest(
+                Uri.parse("https://appassets.androidplatform.net/res/raw/test"));
+        Assert.assertEquals("File doesn't have an extension, MIME type should be text/plain",
+                AssetHelper.DEFAULT_MIME_TYPE, response.getMimeType());
+
+        response = assetLoader.shouldInterceptRequest(
+                Uri.parse("https://appassets.androidplatform.net/assets/other/test"));
+        Assert.assertEquals("File doesn't have an extension, MIME type should be text/plain",
+                AssetHelper.DEFAULT_MIME_TYPE, response.getMimeType());
+
+        response = assetLoader.shouldInterceptRequest(
+                Uri.parse("https://appassets.androidplatform.net/res/drawable/test.png"));
+        Assert.assertEquals(".png file should have mime type image/png regardless of its content",
+                "image/png", response.getMimeType());
+
+        response = assetLoader.shouldInterceptRequest(
+                Uri.parse("https://appassets.androidplatform.net/assets/images/test.png"));
+        Assert.assertEquals(".png file should have mime type image/png regardless of its content",
+                "image/png", response.getMimeType());
+    }
+
     private static void assertResponse(@Nullable WebResourceResponse response,
               @NonNull String expectedContent) throws IOException {
         Assert.assertNotNull("failed to match the URL and returned null response", response);
diff --git a/webkit/src/main/java/androidx/webkit/WebViewAssetLoader.java b/webkit/src/main/java/androidx/webkit/WebViewAssetLoader.java
index d74bde7..b34d682 100644
--- a/webkit/src/main/java/androidx/webkit/WebViewAssetLoader.java
+++ b/webkit/src/main/java/androidx/webkit/WebViewAssetLoader.java
@@ -32,7 +32,6 @@
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -149,6 +148,11 @@
          * falling back to network and trying to resolve a path that doesn't exist. A
          * {@link WebResourceResponse} with {@code null} {@link InputStream} will be received as an
          * HTTP response with status code {@code 404} and no body.
+         * <p class="note">
+         * The MIME type for the file will be determined from the file's extension using
+         * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
+         * asset files are named using standard file extensions. If the file does not have a
+         * recognised extension, {@code "text/plain"} will be used by default.
          *
          * @param path the suffix path to be handled.
          * @return {@link WebResourceResponse} for the requested file.
@@ -162,7 +166,7 @@
                     .build();
 
             InputStream is = mAssetHelper.openAsset(uri);
-            String mimeType = URLConnection.guessContentTypeFromName(path);
+            String mimeType = AssetHelper.guessMimeType(path);
             return new WebResourceResponse(mimeType, null, is);
         }
     }
@@ -194,6 +198,11 @@
          * falling back to network and trying to resolve a path that doesn't exist. A
          * {@link WebResourceResponse} with {@code null} {@link InputStream} will be received as an
          * HTTP response with status code {@code 404} and no body.
+         * <p class="note">
+         * The MIME type for the file will be determined from the file's extension using
+         * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
+         * resource files are named using standard file extensions. If the file does not have a
+         * recognised extension, {@code "text/plain"} will be used by default.
          *
          * @param path the suffix path to be handled.
          * @return {@link WebResourceResponse} for the requested file.
@@ -207,7 +216,7 @@
                     .build();
 
             InputStream is = mAssetHelper.openResource(uri);
-            String mimeType = URLConnection.guessContentTypeFromName(path);
+            String mimeType = AssetHelper.guessMimeType(path);
             return new WebResourceResponse(mimeType, null, is);
         }
 
@@ -298,6 +307,11 @@
          * trying to resolve a path that doesn't exist. A {@link WebResourceResponse} with
          * {@code null} {@link InputStream} will be received as an HTTP response with status code
          * {@code 404} and no body.
+         * <p class="note">
+         * The MIME type for the file will be determined from the file's extension using
+         * {@link java.net.URLConnection#guessContentTypeFromName}. Developers should ensure that
+         * files are named using standard file extensions. If the file does not have a
+         * recognised extension, {@code "text/plain"} will be used by default.
          *
          * @param path the suffix path to be handled.
          * @return {@link WebResourceResponse} for the requested file.
@@ -314,7 +328,7 @@
                 Log.e(TAG, "The requested file: " + path + " is outside the mounted directory: "
                          + mDirectory);
             }
-            String mimeType = URLConnection.guessContentTypeFromName(path);
+            String mimeType = AssetHelper.guessMimeType(path);
             return new WebResourceResponse(mimeType, null, is);
         }
     }
diff --git a/webkit/src/main/java/androidx/webkit/internal/AssetHelper.java b/webkit/src/main/java/androidx/webkit/internal/AssetHelper.java
index 8294ab2..e6d5d2e 100644
--- a/webkit/src/main/java/androidx/webkit/internal/AssetHelper.java
+++ b/webkit/src/main/java/androidx/webkit/internal/AssetHelper.java
@@ -31,6 +31,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.net.URLConnection;
 import java.util.List;
 import java.util.zip.GZIPInputStream;
 
@@ -41,6 +42,11 @@
 public class AssetHelper {
     private static final String TAG = "AssetHelper";
 
+    /**
+     * Default value to be used as MIME type if guessing MIME type failed.
+     */
+    public static final String DEFAULT_MIME_TYPE = "text/plain";
+
     @NonNull private Context mContext;
 
     public AssetHelper(@NonNull Context context) {
@@ -196,4 +202,16 @@
         }
     }
 
+    /**
+     * Use {@link URLConnection#guessContentTypeFromName} to guess MIME type or return the
+     * {@link DEFAULT_MIME_TYPE} if it can't guess.
+     *
+     * @param filePath path of the file to guess its MIME type.
+     * @return MIME type guessed from file extension or {@link DEFAULT_MIME_TYPE}.
+     */
+    @NonNull
+    public static String guessMimeType(@NonNull String filePath) {
+        String mimeType = URLConnection.guessContentTypeFromName(filePath);
+        return mimeType == null ? DEFAULT_MIME_TYPE : mimeType;
+    }
 }
diff --git a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobService.java b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobService.java
index aa28fb2..bbc87a0 100644
--- a/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobService.java
+++ b/work/workmanager/src/main/java/androidx/work/impl/background/systemjob/SystemJobService.java
@@ -16,6 +16,8 @@
 
 package androidx.work.impl.background.systemjob;
 
+import static androidx.work.impl.background.systemjob.SystemJobInfoConverter.EXTRA_WORK_SPEC_ID;
+
 import android.app.Application;
 import android.app.job.JobParameters;
 import android.app.job.JobService;
@@ -24,6 +26,7 @@
 import android.text.TextUtils;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
 import androidx.annotation.RestrictTo;
 import androidx.work.Logger;
@@ -86,22 +89,14 @@
     }
 
     @Override
-    public boolean onStartJob(JobParameters params) {
+    public boolean onStartJob(@NonNull JobParameters params) {
         if (mWorkManagerImpl == null) {
             Logger.get().debug(TAG, "WorkManager is not initialized; requesting retry.");
             jobFinished(params, true);
             return false;
         }
 
-        PersistableBundle extras = params.getExtras();
-        // This can be null, possibly on a device-specific/API-specific (23) situation.  b/134028277
-        //noinspection ConstantConditions
-        if (extras == null) {
-            Logger.get().error(TAG, "No extras in JobParameters.");
-            return false;
-        }
-
-        String workSpecId = extras.getString(SystemJobInfoConverter.EXTRA_WORK_SPEC_ID);
+        String workSpecId = getWorkSpecIdFromJobParameters(params);
         if (TextUtils.isEmpty(workSpecId)) {
             Logger.get().error(TAG, "WorkSpec id not found!");
             return false;
@@ -152,21 +147,13 @@
     }
 
     @Override
-    public boolean onStopJob(JobParameters params) {
+    public boolean onStopJob(@NonNull JobParameters params) {
         if (mWorkManagerImpl == null) {
             Logger.get().debug(TAG, "WorkManager is not initialized; requesting retry.");
             return true;
         }
 
-        PersistableBundle extras = params.getExtras();
-        // This can be null, possibly on a device-specific/API-specific (23) situation.  b/134028277
-        //noinspection ConstantConditions
-        if (extras == null) {
-            Logger.get().error(TAG, "No extras in JobParameters.");
-            return false;
-        }
-
-        String workSpecId = extras.getString(SystemJobInfoConverter.EXTRA_WORK_SPEC_ID);
+        String workSpecId = getWorkSpecIdFromJobParameters(params);
         if (TextUtils.isEmpty(workSpecId)) {
             Logger.get().error(TAG, "WorkSpec id not found!");
             return false;
@@ -192,4 +179,18 @@
             jobFinished(parameters, needsReschedule);
         }
     }
+
+    @Nullable
+    @SuppressWarnings("ConstantConditions")
+    private static String getWorkSpecIdFromJobParameters(@NonNull JobParameters parameters) {
+        try {
+            PersistableBundle extras = parameters.getExtras();
+            if (extras != null && extras.containsKey(EXTRA_WORK_SPEC_ID)) {
+                return extras.getString(EXTRA_WORK_SPEC_ID);
+            }
+        } catch (NullPointerException e) {
+            // b/138441699: BaseBundle.getString sometimes throws an NPE.  Ignore and return null.
+        }
+        return null;
+    }
 }