[go: nahoru, domu]

Merge "Document setTargetRotation for ImageCapture" into androidx-master-dev
diff --git a/OWNERS b/OWNERS
index 71b2ab2..67a6139 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,5 +1,4 @@
 adamp@google.com
-jsproch@google.com
 alanv@google.com
 asfalcone@google.com
 aurimas@google.com
@@ -8,7 +7,9 @@
 emberrose@google.com
 ilake@google.com
 jeffrygaston@google.com
+jsproch@google.com
 kirillg@google.com
+lpf@google.com
 mount@google.com
 nickanthony@google.com
 obenabde@google.com
diff --git a/buildSrc/build_dependencies.gradle b/buildSrc/build_dependencies.gradle
index fa04a55..7657249 100644
--- a/buildSrc/build_dependencies.gradle
+++ b/buildSrc/build_dependencies.gradle
@@ -25,8 +25,8 @@
     build_versions.lint = "27.0.0-alpha01"
 } else {
     build_versions.kotlin = "1.3.41"
-    build_versions.agp = '3.6.0-beta03'
-    build_versions.lint = '26.6.0-beta03'
+    build_versions.agp = '3.6.0-beta04'
+    build_versions.lint = '26.6.0-beta04'
 }
 
 build_versions.dokka = '0.9.17-g002'
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index c6be20f..1dd08f1 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -29,7 +29,7 @@
  */
 val RELEASE_RULE = docsRules("public", false) {
     prebuilts(LibraryGroups.ACTIVITY, "1.1.0-rc02")
-    prebuilts(LibraryGroups.ADS, "1.0.0-alpha02")
+    prebuilts(LibraryGroups.ADS, "1.0.0-alpha03")
     prebuilts(LibraryGroups.ANNOTATION, "annotation", "1.1.0")
     prebuilts(LibraryGroups.ANNOTATION, "annotation-experimental", "1.0.0")
     prebuilts(LibraryGroups.ANNOTATION, "annotation-experimental-lint", "1.0.0")
@@ -38,9 +38,9 @@
     prebuilts(LibraryGroups.ASYNCLAYOUTINFLATER, "1.0.0")
     prebuilts(LibraryGroups.AUTOFILL, "1.0.0-rc01")
     ignore(LibraryGroups.BENCHMARK.group, "benchmark-gradle-plugin")
-    prebuilts(LibraryGroups.BENCHMARK, "1.0.0-rc01")
+    prebuilts(LibraryGroups.BENCHMARK, "1.0.0")
     prebuilts(LibraryGroups.BIOMETRIC, "biometric", "1.0.0")
-    prebuilts(LibraryGroups.BROWSER, "1.2.0-alpha09")
+    prebuilts(LibraryGroups.BROWSER, "1.2.0-beta01")
     ignore(LibraryGroups.CAMERA.group, "camera-testing")
     ignore(LibraryGroups.CAMERA.group, "camera-extensions-stub")
     ignore(LibraryGroups.CAMERA.group, "camera-testlib-extensions")
@@ -63,7 +63,7 @@
     prebuilts(LibraryGroups.COORDINATORLAYOUT, "1.1.0-rc01")
     prebuilts(LibraryGroups.CORE, "core", "1.2.0-rc01")
     prebuilts(LibraryGroups.CORE, "core-ktx", "1.2.0-rc01")
-    prebuilts(LibraryGroups.CORE, "core-role", "1.0.0-alpha02")
+    prebuilts(LibraryGroups.CORE, "core-role", "1.0.0-beta01")
     prebuilts(LibraryGroups.CURSORADAPTER, "1.0.0")
     prebuilts(LibraryGroups.CUSTOMVIEW, "1.1.0-alpha01")
     prebuilts(LibraryGroups.DOCUMENTFILE, "1.0.0")
@@ -114,7 +114,7 @@
     prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview", "1.1.0")
     prebuilts(LibraryGroups.RECYCLERVIEW, "recyclerview-selection", "1.1.0-alpha06")
     prebuilts(LibraryGroups.REMOTECALLBACK, "1.0.0-alpha02")
-    prebuilts(LibraryGroups.ROOM, "2.2.0-beta01")
+    prebuilts(LibraryGroups.ROOM, "2.2.2")
     prebuilts(LibraryGroups.SAVEDSTATE, "1.0.0")
     // TODO: Remove this ignore once androidx.security:security-identity-credential:1.0.0-alpha01 is released
     ignore(LibraryGroups.SECURITY.group, "security-identity-credential")
@@ -138,13 +138,13 @@
     prebuilts(LibraryGroups.VECTORDRAWABLE, "vectordrawable-animated", "1.1.0")
     prebuilts(LibraryGroups.VERSIONEDPARCELABLE, "1.1.0")
     prebuilts(LibraryGroups.VIEWPAGER, "1.0.0")
-    prebuilts(LibraryGroups.VIEWPAGER2, "1.0.0-rc01")
+    prebuilts(LibraryGroups.VIEWPAGER2, "1.0.0")
     prebuilts(LibraryGroups.WEAR, "1.0.0")
             .addStubs("wear/wear_stubs/com.google.android.wearable-stubs.jar")
     prebuilts(LibraryGroups.WEBKIT, "1.1.0")
     ignore(LibraryGroups.WORK.group, "work-gcm")
     ignore(LibraryGroups.WORK.group, "work-runtime-lint")
-    prebuilts(LibraryGroups.WORK, "2.3.0-alpha03")
+    prebuilts(LibraryGroups.WORK, "2.3.0-beta01")
     default(Ignore)
 }
 
diff --git a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
index 6fb8f9e..5293510 100644
--- a/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt
@@ -110,7 +110,7 @@
 
 internal lateinit var agpVersion: String
 
-const val AGP_STABLE = "com.android.tools.build:gradle:3.4.2"
+const val AGP_STABLE = "com.android.tools.build:gradle:3.5.2"
 val AGP_LATEST get() = "com.android.tools.build:gradle:$agpVersion"
 
 internal lateinit var lintVersion: String
diff --git a/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt b/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
index c498eb4..aebc136 100644
--- a/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/studio/StudioVersions.kt
@@ -56,9 +56,9 @@
 }
 
 private object RootStudioVersions : StudioVersions() {
-    override val studioVersion = "3.6.0.15"
+    override val studioVersion = "3.6.0.16"
     override val ideaMajorVersion = "192"
-    override val studioBuildNumber = "5982640"
+    override val studioBuildNumber = "5994180"
     override val buildTxtOverride: String = ""
 }
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
index 69b2640..c54edb0 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
@@ -163,9 +163,8 @@
 
     private void analyzerAnalyzesImagesWithStrategy(@BackpressureStrategy int backpressureStrategy)
             throws InterruptedException {
-        ImageAnalysisConfig config = new ImageAnalysisConfig.Builder().setBackpressureStrategy(
+        ImageAnalysis useCase = new ImageAnalysisConfig.Builder().setBackpressureStrategy(
                 backpressureStrategy).build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
             mLifecycleOwner.startAndResume();
@@ -182,8 +181,7 @@
     @Test
     @UiThreadTest
     public void analyzerDoesNotAnalyzeImages_whenCameraIsNotOpen() throws InterruptedException {
-        ImageAnalysisConfig config = new ImageAnalysisConfig.Builder().build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = new ImageAnalysisConfig.Builder().build();
         // Bind but do not start lifecycle
         CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
         useCase.setAnalyzer(CameraXExecutors.newHandlerExecutor(mHandler), mAnalyzer);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
index 19f522c..4b22f84 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageCaptureTest.java
@@ -150,7 +150,7 @@
 
         return new ImageCaptureConfig.Builder()
                 .setTargetRotation(surfaceRotation)
-                .build();
+                .getUseCaseConfig();
     }
 
     @Before
@@ -167,9 +167,9 @@
             throw new IllegalArgumentException(
                     "Unable to attach to camera with LensFacing " + BACK_LENS_FACING, e);
         }
-        mDefaultConfig = new ImageCaptureConfig.Builder().build();
+        mDefaultConfig = new ImageCaptureConfig.Builder().getUseCaseConfig();
 
-        mFakeUseCaseConfig = new FakeUseCaseConfig.Builder().build();
+        mFakeUseCaseConfig = new FakeUseCaseConfig.Builder().getUseCaseConfig();
         mRepeatingUseCase = new FakeRepeatingUseCase(mFakeUseCaseConfig, BACK_SELECTOR);
         mLifecycleOwner = new FakeLifecycleOwner();
     }
@@ -188,10 +188,8 @@
 
     @Test
     public void capturedImageHasCorrectSize() {
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder().setTargetResolution(
-                        DEFAULT_RESOLUTION).setTargetRotation(Surface.ROTATION_0).build();
-        ImageCapture useCase = new ImageCapture(config);
+        ImageCapture useCase = new ImageCaptureConfig.Builder().setTargetResolution(
+                DEFAULT_RESOLUTION).setTargetRotation(Surface.ROTATION_0).build();
 
         mInstrumentation.runOnMainSync(
                 () -> {
@@ -249,11 +247,9 @@
     @FlakyTest //TODO(b/143734846): Callback is not always being called
     @Test
     public void canCaptureMultipleImagesWithMaxQuality() {
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder()
-                        .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                        .build();
-        ImageCapture useCase = new ImageCapture(config);
+        ImageCapture useCase = new ImageCaptureConfig.Builder()
+                .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+                .build();
         mInstrumentation.runOnMainSync(
                 () -> {
                     CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -290,9 +286,8 @@
 
     @Test
     public void canSaveFile_withRotation() throws IOException {
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder().setTargetRotation(Surface.ROTATION_0).build();
-        ImageCapture useCase = new ImageCapture(config);
+        ImageCapture useCase = new ImageCaptureConfig.Builder().setTargetRotation(
+                Surface.ROTATION_0).build();
         mInstrumentation.runOnMainSync(
                 () -> {
                     CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -443,7 +438,7 @@
         CameraCaptureSession.CaptureCallback captureCallback =
                 mock(CameraCaptureSession.CaptureCallback.class);
         new Camera2Config.Extender(configBuilder).setSessionCaptureCallback(captureCallback);
-        ImageCapture useCase = new ImageCapture(configBuilder.build());
+        ImageCapture useCase = configBuilder.build();
         mInstrumentation.runOnMainSync(
                 () -> {
                     CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -483,11 +478,9 @@
         Assume.assumeTrue(resolutions.length > 0);
         Size resolution = resolutions[0];
 
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder()
-                        .setBufferFormat(ImageFormat.RAW10)
-                        .build();
-        ImageCapture useCase = new ImageCapture(config);
+        ImageCapture useCase = new ImageCaptureConfig.Builder()
+                .setBufferFormat(ImageFormat.RAW10)
+                .build();
         mInstrumentation.runOnMainSync(
                 () -> {
                     CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, useCase);
@@ -505,18 +498,15 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void constructor_withBufferFormatAndCaptureProcessor_throwsException() {
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder()
-                        .setBufferFormat(ImageFormat.RAW_SENSOR)
-                        .setCaptureProcessor(mock(CaptureProcessor.class))
-                        .build();
-        new ImageCapture(config);
+        new ImageCaptureConfig.Builder()
+                .setBufferFormat(ImageFormat.RAW_SENSOR)
+                .setCaptureProcessor(mock(CaptureProcessor.class))
+                .build();
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void constructor_maxCaptureStageInvalid_throwsException() {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder().setMaxCaptureStages(0).build();
-        new ImageCapture(config);
+        new ImageCaptureConfig.Builder().setMaxCaptureStages(0).build();
     }
 
     @Test
@@ -531,9 +521,8 @@
             }
         };
 
-        ImageCaptureConfig.Builder configBuilder =
-                new ImageCaptureConfig.Builder().setCaptureBundle(captureBundle);
-        ImageCapture imageCapture = new ImageCapture(configBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().setCaptureBundle(
+                captureBundle).build();
 
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
@@ -562,12 +551,11 @@
             }
         };
 
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder()
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
                 .setMaxCaptureStages(1)
                 .setCaptureBundle(captureBundle)
                 .setCaptureProcessor(mock(CaptureProcessor.class))
                 .build();
-        ImageCapture imageCapture = new ImageCapture(config);
 
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
@@ -592,9 +580,7 @@
 
     @Test
     public void onCaptureCancelled_onErrorCAMERA_CLOSED() throws InterruptedException {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder()
-                .build();
-        ImageCapture imageCapture = new ImageCapture(config);
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
             mLifecycleOwner.startAndResume();
@@ -620,9 +606,7 @@
 
     @Test
     public void onRequestFailed_OnErrorCAPTURE_FAILED() throws InterruptedException {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder()
-                .build();
-        ImageCapture imageCapture = new ImageCapture(config);
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
             mLifecycleOwner.startAndResume();
@@ -651,9 +635,7 @@
 
     @Test
     public void onStateOffline_abortAllCaptureRequests() {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder()
-                .build();
-        ImageCapture imageCapture = new ImageCapture(config);
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
         mInstrumentation.runOnMainSync(() -> {
             CameraX.bindToLifecycle(mLifecycleOwner, BACK_SELECTOR, imageCapture);
             mLifecycleOwner.startAndResume();
@@ -682,9 +664,7 @@
 
     @Test
     public void takePictureReturnsErrorNO_CAMERA_whenNotBound() {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder()
-                .build();
-        ImageCapture imageCapture = new ImageCapture(config);
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
 
         OnImageCapturedCallback callback = createMockOnImageCapturedCallback(null);
         imageCapture.takePicture(mListenerExecutor, callback);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
index 0fa883f..7bd6fe2 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageReaderProxysTest.java
@@ -149,7 +149,8 @@
             semaphores.add(semaphore);
         }
 
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         UseCase useCase = new UseCase(config, mReaders);
         CameraUtil.openCameraWithUseCase(CAMERA_ID, mCameraInternal, useCase);
 
@@ -173,7 +174,8 @@
             semaphores.add(semaphore);
         }
 
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         UseCase useCase = new UseCase(config, mReaders);
         CameraUtil.openCameraWithUseCase(CAMERA_ID, mCameraInternal, useCase);
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
index 5221251..e7bd74c 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/PreviewTest.java
@@ -38,7 +38,6 @@
 import androidx.camera.core.CaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.core.SessionConfig;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -73,19 +72,19 @@
     public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
             Manifest.permission.CAMERA);
 
-    private static final Preview.PreviewSurfaceCallback MOCK_PREVIEW_SURFACE_CALLBACK =
-            mock(Preview.PreviewSurfaceCallback.class);
+    private static final Preview.PreviewSurfaceProvider MOCK_PREVIEW_SURFACE_PROVIDER =
+            mock(Preview.PreviewSurfaceProvider.class);
 
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
 
-    private PreviewConfig mDefaultConfig;
+    private Preview.Builder mDefaultBuilder;
 
     private CameraSelector mCameraSelector;
     private String mCameraId;
     private FakeLifecycleOwner mLifecycleOwner;
     private Semaphore mSurfaceFutureSemaphore;
     private Semaphore mSaveToReleaseSemaphore;
-    private Preview.PreviewSurfaceCallback mPreviewSurfaceCallbackWithFrameAvailableListener =
+    private Preview.PreviewSurfaceProvider mPreviewSurfaceProviderWithFrameAvailableListener =
             createSurfaceTextureProvider(new PreviewSurfaceProviders.SurfaceTextureCallback() {
                 @Override
                 public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -118,7 +117,8 @@
         }
 
         // init CameraX before creating Preview to get preview size with CameraX's context
-        mDefaultConfig = Preview.DEFAULT_CONFIG.getConfig(LensFacing.BACK);
+        mDefaultBuilder = Preview.Builder.fromConfig(
+                Preview.DEFAULT_CONFIG.getConfig(LensFacing.BACK));
         mSurfaceFutureSemaphore = new Semaphore(/*permits=*/ 0);
         mSaveToReleaseSemaphore = new Semaphore(/*permits=*/ 0);
         mCameraSelector = new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
@@ -137,26 +137,26 @@
 
     @Test
     @UiThreadTest
-    public void getAndSetPreviewSurfaceCallback() {
-        Preview preview = new Preview(mDefaultConfig);
-        preview.setPreviewSurfaceCallback(MOCK_PREVIEW_SURFACE_CALLBACK);
-        assertThat(preview.getPreviewSurfaceCallback()).isEqualTo(MOCK_PREVIEW_SURFACE_CALLBACK);
+    public void getAndSetPreviewSurfaceProvider() {
+        Preview preview = mDefaultBuilder.build();
+        preview.setPreviewSurfaceProvider(MOCK_PREVIEW_SURFACE_PROVIDER);
+        assertThat(preview.getPreviewSurfaceProvider()).isEqualTo(MOCK_PREVIEW_SURFACE_PROVIDER);
     }
 
     @Test
     @UiThreadTest
-    public void removePreviewSurfaceCallback() {
-        Preview preview = new Preview(mDefaultConfig);
-        preview.setPreviewSurfaceCallback(MOCK_PREVIEW_SURFACE_CALLBACK);
-        preview.setPreviewSurfaceCallback(null);
-        assertThat(preview.getPreviewSurfaceCallback()).isNull();
+    public void removePreviewSurfaceProvider() {
+        Preview preview = mDefaultBuilder.build();
+        preview.setPreviewSurfaceProvider(MOCK_PREVIEW_SURFACE_PROVIDER);
+        preview.setPreviewSurfaceProvider(null);
+        assertThat(preview.getPreviewSurfaceProvider()).isNull();
     }
 
     //TODO(b/143514107): This API is being removed from preview. This test should be moved.
     @Test
     @UiThreadTest
     public void torchModeCanBeSet() {
-        Preview useCase = new Preview(mDefaultConfig);
+        Preview useCase = mDefaultBuilder.build();
         CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, useCase);
         CameraControlInternal cameraControl = getFakeCameraControl();
         useCase.attachCameraControl(mCameraId, cameraControl);
@@ -169,13 +169,12 @@
     @Test
     public void previewDetached_onSafeToReleaseCalled() throws InterruptedException {
         // Arrange.
-        PreviewConfig config = new PreviewConfig.Builder().build();
-        Preview preview = new Preview(config);
+        Preview preview = new Preview.Builder().build();
 
         // Act.
         mInstrumentation.runOnMainSync(() -> {
-            preview.setPreviewSurfaceCallback(CameraXExecutors.mainThreadExecutor(),
-                    mPreviewSurfaceCallbackWithFrameAvailableListener);
+            preview.setPreviewSurfaceProvider(CameraXExecutors.mainThreadExecutor(),
+                    mPreviewSurfaceProviderWithFrameAvailableListener);
             CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
         });
 
@@ -192,11 +191,11 @@
     }
 
     @Test
-    public void setPreviewSurfaceCallbackBeforeBind_getsFrame() throws InterruptedException {
+    public void setPreviewSurfaceProviderBeforeBind_getsFrame() throws InterruptedException {
         mInstrumentation.runOnMainSync(() -> {
             // Arrange.
-            Preview preview = new Preview(mDefaultConfig);
-            preview.setPreviewSurfaceCallback(mPreviewSurfaceCallbackWithFrameAvailableListener);
+            Preview preview = mDefaultBuilder.build();
+            preview.setPreviewSurfaceProvider(mPreviewSurfaceProviderWithFrameAvailableListener);
 
             // Act.
             CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
@@ -207,16 +206,16 @@
         assertThat(mSurfaceFutureSemaphore.tryAcquire(10, TimeUnit.SECONDS)).isTrue();
     }
 
-    @Suppress // TODO(b/143703289): Remove suppression once callback can be set after bind
+    @Suppress // TODO(b/143703289): Remove suppression once provider can be set after bind
     @Test
-    public void setPreviewSurfaceCallbackAfterBind_getsFrame() throws InterruptedException {
+    public void setPreviewSurfaceProviderAfterBind_getsFrame() throws InterruptedException {
         mInstrumentation.runOnMainSync(() -> {
             // Arrange.
-            Preview preview = new Preview(mDefaultConfig);
+            Preview preview = mDefaultBuilder.build();
             CameraX.bindToLifecycle(mLifecycleOwner, mCameraSelector, preview);
 
             // Act.
-            preview.setPreviewSurfaceCallback(mPreviewSurfaceCallbackWithFrameAvailableListener);
+            preview.setPreviewSurfaceProvider(mPreviewSurfaceProviderWithFrameAvailableListener);
             mLifecycleOwner.startAndResume();
         });
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
index b6cb6a3..cb3849b 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/SurfaceOrientedMeteringPointFactoryTest.java
@@ -52,6 +52,7 @@
     private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
     private LifecycleOwner mLifecycle;
     SurfaceOrientedMeteringPointFactory mPointFactory;
+
     @Before
     public void setUp() {
         Context context = ApplicationProvider.getApplicationContext();
@@ -114,12 +115,10 @@
     public void createPointWithFoVUseCase_success() {
         assumeTrue(CameraUtil.hasCameraWithLensFacing(LensFacing.BACK));
 
-        ImageAnalysisConfig imageAnalysisConfig =
-                new ImageAnalysisConfig.Builder()
-                        .setTargetAspectRatio(AspectRatio.RATIO_4_3)
-                        .setTargetName("ImageAnalysis")
-                        .build();
-        ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_4_3)
+                .setTargetName("ImageAnalysis")
+                .build();
         CameraSelector cameraSelector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
         mInstrumentation.runOnMainSync(new Runnable() {
@@ -139,12 +138,10 @@
     public void createPointWithFoVUseCase_FailedNotBound() {
         assumeTrue(CameraUtil.hasCameraWithLensFacing(LensFacing.BACK));
 
-        ImageAnalysisConfig imageAnalysisConfig =
-                new ImageAnalysisConfig.Builder()
-                        .setTargetAspectRatio(AspectRatio.RATIO_4_3)
-                        .setTargetName("ImageAnalysis")
-                        .build();
-        ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_4_3)
+                .setTargetName("ImageAnalysis")
+                .build();
 
         // This will throw IllegalStateException.
         SurfaceOrientedMeteringPointFactory factory = new SurfaceOrientedMeteringPointFactory(
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
index 1645c7f..deb6d09 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/UseCaseCombinationTest.java
@@ -38,7 +38,6 @@
 import androidx.camera.core.ImageCaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.testing.CameraUtil;
@@ -121,7 +120,7 @@
         initPreview();
         initImageCapture();
         mInstrumentation.runOnMainSync(() -> {
-            mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+            mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                     new PreviewSurfaceProviders.SurfaceTextureCallback() {
                         @Override
                         public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -208,27 +207,20 @@
     }
 
     private void initImageAnalysis() {
-        ImageAnalysisConfig imageAnalysisConfig =
-                new ImageAnalysisConfig.Builder()
-                        .setTargetName("ImageAnalysis")
-                        .build();
         mImageAnalyzer = (image, rotationDegrees) -> {
             mAnalysisResult.postValue(image.getImageInfo().getTimestamp());
             image.close();
         };
-        mImageAnalysis = new ImageAnalysis(imageAnalysisConfig);
+        mImageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetName("ImageAnalysis")
+                .build();
     }
 
     private void initImageCapture() {
-        ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
-
-        mImageCapture = new ImageCapture(imageCaptureConfig);
+        mImageCapture = new ImageCaptureConfig.Builder().build();
     }
 
     private void initPreview() {
-        PreviewConfig.Builder configBuilder =
-                new PreviewConfig.Builder()
-                        .setTargetName("Preview");
-        mPreview = new Preview(configBuilder.build());
+        mPreview = new Preview.Builder().setTargetName("Preview").build();
     }
 }
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
index 7010d1f..d4b1d81 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2CameraImplTest.java
@@ -806,7 +806,7 @@
                 new FakeUseCaseConfig.Builder().setTargetName("UseCase");
         CameraSelector selector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
-        TestUseCase testUseCase = new TestUseCase(configBuilder.build(), selector,
+        TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig(), selector,
                 mMockOnImageAvailableListener);
         Map<String, Size> suggestedResolutionMap = new HashMap<>();
         suggestedResolutionMap.put(mCameraId, new Size(640, 480));
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
index 1f1d6fc..fd500bf 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraRepositoryTest.java
@@ -115,7 +115,7 @@
 
         FakeUseCaseConfig.Builder configBuilder = new FakeUseCaseConfig.Builder();
         new Camera2Config.Extender(configBuilder).setDeviceStateCallback(mDeviceStateCallback);
-        mConfig = configBuilder.build();
+        mConfig = configBuilder.getUseCaseConfig();
         mCameraId = getCameraIdForLensFacingUnchecked(LensFacing.BACK);
         mUseCase = new CallbackAttachingFakeUseCase(mConfig, mCameraId);
         mUseCaseGroup.addUseCase(mUseCase);
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
index ab113ef..3b0a52d 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/Camera2ImplCameraXTest.java
@@ -147,7 +147,7 @@
             public void run() {
                 ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
                 new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-                ImageAnalysis useCase = new ImageAnalysis(builder.build());
+                ImageAnalysis useCase = builder.build();
 
                 CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
                 useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mImageAnalyzer);
@@ -180,10 +180,9 @@
             public void run() {
                 ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
                 new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-                ImageAnalysis useCase = new ImageAnalysis(builder.build());
+                ImageAnalysis useCase = builder.build();
 
-                ImageAnalysisConfig config2 = new ImageAnalysisConfig.Builder().build();
-                ImageAnalysis useCase2 = new ImageAnalysis(config2);
+                ImageAnalysis useCase2 = new ImageAnalysisConfig.Builder().build();
 
                 CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase, useCase2);
 
@@ -216,7 +215,7 @@
                 new Camera2Config.Extender(configBuilder)
                         .setDeviceStateCallback(deviceStateCallback)
                         .setSessionCaptureCallback(sessionCaptureCallback);
-                ImageAnalysis useCase = new ImageAnalysis(configBuilder.build());
+                ImageAnalysis useCase = configBuilder.build();
                 CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
                 useCase.setAnalyzer(CameraXExecutors.mainThreadExecutor(), mImageAnalyzer);
                 mAnalysisResult.observe(mLifecycle, createCountIncrementingObserver(observedCount));
@@ -253,8 +252,7 @@
     public void bind_opensCamera() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -272,8 +270,7 @@
     public void bind_opensCamera_withOutAnalyzer() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -295,8 +292,7 @@
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback)
                 .setSessionStateCallback(mockSessionStateCallback);
 
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -321,8 +317,7 @@
         for (int i = 0; i < 2; i++) {
             CameraDevice.StateCallback callback = mock(CameraDevice.StateCallback.class);
             new Camera2Config.Extender(builder).setDeviceStateCallback(callback);
-            ImageAnalysisConfig config = builder.build();
-            ImageAnalysis useCase = new ImageAnalysis(config);
+            ImageAnalysis useCase = builder.build();
 
             mInstrumentation.runOnMainSync(new Runnable() {
                 @Override
@@ -352,8 +347,7 @@
         for (int i = 0; i < 2; i++) {
             CameraDevice.StateCallback callback = mock(CameraDevice.StateCallback.class);
             new Camera2Config.Extender(builder).setDeviceStateCallback(callback);
-            ImageAnalysisConfig config = builder.build();
-            ImageAnalysis useCase = new ImageAnalysis(config);
+            ImageAnalysis useCase = builder.build();
 
             mInstrumentation.runOnMainSync(new Runnable() {
                 @Override
@@ -380,8 +374,7 @@
     public void unbindAll_closesAllCameras() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -407,8 +400,7 @@
     public void unbindAllAssociatedUseCase_closesCamera() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -434,14 +426,11 @@
     public void unbindPartialAssociatedUseCase_doesNotCloseCamera() throws InterruptedException {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config0 = builder.build();
-        ImageAnalysis useCase0 = new ImageAnalysis(config0);
+        ImageAnalysis useCase0 = builder.build();
 
-        ImageCaptureConfig configuration =
-                new ImageCaptureConfig.Builder()
-                        .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                        .build();
-        ImageCapture useCase1 = new ImageCapture(configuration);
+        ImageCapture useCase1 = new ImageCaptureConfig.Builder()
+                .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+                .build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -469,14 +458,11 @@
     public void unbindAllAssociatedUseCaseInParts_ClosesCamera() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
         new Camera2Config.Extender(builder).setDeviceStateCallback(mDeviceStateCallback);
-        ImageAnalysisConfig config0 = builder.build();
-        ImageAnalysis useCase0 = new ImageAnalysis(config0);
+        ImageAnalysis useCase0 = builder.build();
 
-        ImageCaptureConfig configuration =
-                new ImageCaptureConfig.Builder()
-                        .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                        .build();
-        ImageCapture useCase1 = new ImageCapture(configuration);
+        ImageCapture useCase1 = new ImageCaptureConfig.Builder()
+                .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
+                .build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
@@ -503,8 +489,7 @@
     @UiThreadTest
     public void cameraInfo_getCameraInfoFromCamera() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         Camera camera = CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
 
@@ -515,8 +500,7 @@
     @UiThreadTest
     public void cameraControl_getCameraControlFromCamera() {
         ImageAnalysisConfig.Builder builder = new ImageAnalysisConfig.Builder();
-        ImageAnalysisConfig config = builder.build();
-        ImageAnalysis useCase = new ImageAnalysis(config);
+        ImageAnalysis useCase = builder.build();
 
         Camera camera = CameraX.bindToLifecycle(mLifecycle, DEFAULT_SELECTOR, useCase);
 
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
index a2a7616..07362fce 100644
--- a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
+++ b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/impl/UseCaseSurfaceOccupancyManagerTest.java
@@ -57,7 +57,7 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void failedWhenBindTooManyImageCapture() {
-        ImageCaptureConfig config = new ImageCaptureConfig.Builder().build();
+        ImageCaptureConfig config = new ImageCaptureConfig.Builder().getUseCaseConfig();
         ImageCapture useCase1 = new ImageCapture(config);
         ImageCapture useCase2 = new ImageCapture(config);
 
@@ -69,7 +69,7 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void failedWhenBindTooManyVideoCapture() {
-        VideoCaptureConfig config = new VideoCaptureConfig.Builder().build();
+        VideoCaptureConfig config = new VideoCaptureConfig.Builder().getUseCaseConfig();
         VideoCapture useCase1 = new VideoCapture(config);
         VideoCapture useCase2 = new VideoCapture(config);
 
@@ -81,11 +81,8 @@
 
     @Test
     public void passWhenNotBindTooManyImageVideoCapture() {
-        ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfig);
-
-        VideoCaptureConfig videoCaptureConfig = new VideoCaptureConfig.Builder().build();
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfig);
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder().build();
 
         UseCaseSurfaceOccupancyManager.checkUseCaseLimitNotExceeded(
                 Collections.<UseCase>singletonList(imageCapture),
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
index 9533b0b..04654d1 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageAnalysisConfigProvider.java
@@ -35,6 +35,7 @@
 
 /**
  * Provides defaults for {@link ImageAnalysisConfig} in the Camera2 implementation.
+ *
  * @hide
  */
 @RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
             Log.w(TAG, "Unable to determine default lens facing for ImageAnalysis.", e);
         }
 
-        return builder.build();
+        return builder.getUseCaseConfig();
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
index dc18b1f..99b4677 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/ImageCaptureConfigProvider.java
@@ -35,6 +35,7 @@
 
 /**
  * Provides defaults for {@link ImageCaptureConfig} in the Camera2 implementation.
+ *
  * @hide
  */
 @RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
             Log.w(TAG, "Unable to determine default lens facing for ImageCapture.", e);
         }
 
-        return builder.build();
+        return builder.getUseCaseConfig();
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
index 054fffb8..5eb1f5d 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/PreviewConfigProvider.java
@@ -35,6 +35,7 @@
 
 /**
  * Provides defaults for {@link PreviewConfig} in the Camera2 implementation.
+ *
  * @hide
  */
 @RestrictTo(Scope.LIBRARY)
@@ -53,8 +54,8 @@
 
     @Override
     public PreviewConfig getConfig(LensFacing lensFacing) {
-        PreviewConfig.Builder builder =
-                PreviewConfig.Builder.fromConfig(Preview.DEFAULT_CONFIG.getConfig(lensFacing));
+        Preview.Builder builder = Preview.Builder.fromConfig(
+                Preview.DEFAULT_CONFIG.getConfig(lensFacing));
 
         // SessionConfig containing all intrinsic properties needed for Preview
         SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
@@ -89,6 +90,6 @@
             Log.w(TAG, "Unable to determine default lens facing for Preview.", e);
         }
 
-        return builder.build();
+        return builder.getUseCaseConfig();
     }
 }
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
index 918b673..c67da97 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/SupportedSurfaceCombination.java
@@ -364,10 +364,10 @@
         List<Size> sizesNotMatchAspectRatio = new ArrayList<>();
 
         Rational aspectRatio = null;
-        Integer targetAspectRatio = config.getTargetAspectRatio(null);
-        if (targetAspectRatio != null) {
+        if (config.hasTargetAspectRatio()) {
             // Checks the sensor orientation.
             boolean isSensorLandscapeOrientation = isRotationNeeded(Surface.ROTATION_0);
+            @AspectRatio int targetAspectRatio = config.getTargetAspectRatio();
             switch (targetAspectRatio) {
                 case AspectRatio.RATIO_4_3:
                     aspectRatio =
diff --git a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
index 0c5e47f..8d3eafc 100644
--- a/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
+++ b/camera/camera-camera2/src/main/java/androidx/camera/camera2/impl/VideoCaptureConfigProvider.java
@@ -35,6 +35,7 @@
 
 /**
  * Provides defaults for {@link VideoCaptureConfig} in the Camera2 implementation.
+ *
  * @hide
  */
 @RestrictTo(Scope.LIBRARY)
@@ -91,6 +92,6 @@
             Log.w(TAG, "Unable to determine default lens facing for VideoCapture.", e);
         }
 
-        return builder.build();
+        return builder.getUseCaseConfig();
     }
 }
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
index 7a88fe74..29d4c2d 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2CaptureOptionUnpackerTest.java
@@ -62,7 +62,7 @@
                 .setSessionCaptureCallback(captureCallback);
 
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
-        mUnpacker.unpack(imageCaptureConfigBuilder.build(), captureBuilder);
+        mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), captureBuilder);
         CaptureConfig captureConfig = captureBuilder.build();
 
         CameraCaptureCallback cameraCaptureCallback =
@@ -84,7 +84,7 @@
                         CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
 
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
-        mUnpacker.unpack(imageCaptureConfigBuilder.build(), captureBuilder);
+        mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), captureBuilder);
         CaptureConfig captureConfig = captureBuilder.build();
 
         Camera2Config config = new Camera2Config(captureConfig.getImplementationOptions());
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
index 0079028..55c1978 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2DeviceSurfaceManagerTest.java
@@ -330,17 +330,15 @@
 
     @Test
     public void suggestedResolutionsForMixedUseCaseNotSupportedInLegacyDevice() {
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
-        Preview preview = new Preview(previewConfigBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -361,17 +359,15 @@
 
     @Test
     public void getSuggestedResolutionsForMixedUseCaseInLimitedDevice() {
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
-        Preview preview = new Preview(previewConfigBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -389,7 +385,7 @@
     @Test
     public void transformSurfaceConfigWithYUVAnalysisSize() {
         SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
-                        LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mAnalysisSize);
+                LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mAnalysisSize);
         SurfaceConfig expectedSurfaceConfig =
                 SurfaceConfig.create(ConfigType.YUV, ConfigSize.ANALYSIS);
         assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -398,7 +394,7 @@
     @Test
     public void transformSurfaceConfigWithYUVPreviewSize() {
         SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
-                        LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mPreviewSize);
+                LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mPreviewSize);
         SurfaceConfig expectedSurfaceConfig =
                 SurfaceConfig.create(ConfigType.YUV, ConfigSize.PREVIEW);
         assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -407,7 +403,7 @@
     @Test
     public void transformSurfaceConfigWithYUVRecordSize() {
         SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
-                        LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mRecordSize);
+                LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mRecordSize);
         SurfaceConfig expectedSurfaceConfig =
                 SurfaceConfig.create(ConfigType.YUV, SurfaceConfig.ConfigSize.RECORD);
         assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -416,7 +412,7 @@
     @Test
     public void transformSurfaceConfigWithYUVMaximumSize() {
         SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
-                        LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mMaximumSize);
+                LEGACY_CAMERA_ID, ImageFormat.YUV_420_888, mMaximumSize);
         SurfaceConfig expectedSurfaceConfig =
                 SurfaceConfig.create(SurfaceConfig.ConfigType.YUV, ConfigSize.MAXIMUM);
         assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -425,9 +421,9 @@
     @Test
     public void transformSurfaceConfigWithYUVNotSupportSize() {
         SurfaceConfig surfaceConfig = mSurfaceManager.transformSurfaceConfig(
-                        LEGACY_CAMERA_ID,
-                        ImageFormat.YUV_420_888,
-                        new Size(mMaximumSize.getWidth() + 1, mMaximumSize.getHeight() + 1));
+                LEGACY_CAMERA_ID,
+                ImageFormat.YUV_420_888,
+                new Size(mMaximumSize.getWidth() + 1, mMaximumSize.getHeight() + 1));
         SurfaceConfig expectedSurfaceConfig =
                 SurfaceConfig.create(ConfigType.YUV, ConfigSize.NOT_SUPPORT);
         assertEquals(expectedSurfaceConfig, surfaceConfig);
@@ -501,10 +497,9 @@
                         mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
 
         Rational targetAspectRatio = new Rational(9, 16);
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        PreviewConfig previewConfig = previewConfigBuilder.build();
+        PreviewConfig previewConfig = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .getUseCaseConfig();
 
         CameraDeviceConfig deviceConfig =
                 CameraSelectorUtil.toCameraDeviceConfig(
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
index c742129..d544ea2 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/Camera2SessionOptionUnpackerTest.java
@@ -73,7 +73,7 @@
                 .setCameraEventCallback(cameraEventCallbacks);
 
         SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
-        mUnpacker.unpack(imageCaptureConfigBuilder.build(), sessionBuilder);
+        mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), sessionBuilder);
         SessionConfig sessionConfig = sessionBuilder.build();
 
         CameraCaptureCallback interopCallback =
@@ -105,7 +105,7 @@
                         CaptureRequest.FLASH_MODE, CaptureRequest.FLASH_MODE_TORCH);
 
         SessionConfig.Builder sessionBuilder = new SessionConfig.Builder();
-        mUnpacker.unpack(imageCaptureConfigBuilder.build(), sessionBuilder);
+        mUnpacker.unpack(imageCaptureConfigBuilder.getUseCaseConfig(), sessionBuilder);
         SessionConfig sessionConfig = sessionBuilder.build();
 
         Camera2Config config = new Camera2Config(sessionConfig.getImplementationOptions());
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
index 7a903d7..3d41e17 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/DisplayOrientedMeteringPointFactoryTest.java
@@ -88,7 +88,7 @@
                 new ConfigProvider<FakeUseCaseConfig>() {
                     @Override
                     public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
-                        return new FakeUseCaseConfig.Builder().build();
+                        return new FakeUseCaseConfig.Builder().getUseCaseConfig();
                     }
                 });
 
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
index a4deffc..a49500a 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/ImageCaptureOptionUnpackerTest.java
@@ -92,7 +92,7 @@
     @Test
     public void unpackWithoutCaptureMode() {
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
-        ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().build();
+        ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder().getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -109,7 +109,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -126,7 +126,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_API26);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -143,7 +143,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_NOT_SUPPORT_API);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -160,7 +160,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_2_NOT_SUPPORT_API);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -177,7 +177,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_API26);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -194,7 +194,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_API26);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -211,7 +211,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MIN_LATENCY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_NOT_SUPPORT_API);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -228,7 +228,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_PIXEL_3_NOT_SUPPORT_API);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -245,7 +245,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_NOT_GOOGLE);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
@@ -262,7 +262,7 @@
         CaptureConfig.Builder captureBuilder = new CaptureConfig.Builder();
         ImageCaptureConfig imageCaptureConfig = new ImageCaptureConfig.Builder()
                 .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
-                .build();
+                .getUseCaseConfig();
 
         mUnpacker.setDeviceProperty(PROPERTIES_NOT_SUPPORT_MODEL);
         mUnpacker.unpack(imageCaptureConfig, captureBuilder);
diff --git a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
index 5accefc..1682758 100644
--- a/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
+++ b/camera/camera-camera2/src/test/java/androidx/camera/camera2/impl/SupportedSurfaceCombinationTest.java
@@ -477,10 +477,9 @@
                         mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
 
         Rational targetAspectRatio = new Rational(9, 16);
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        Preview preview = new Preview(previewConfigBuilder.build());
+        final Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         // Ensure we are bound to a camera to ensure aspect ratio correction is applied.
         FakeLifecycleOwner fakeLifecycle = new FakeLifecycleOwner();
@@ -526,13 +525,9 @@
                 new SupportedSurfaceCombination(
                         mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-        ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
-        Preview preview = new Preview(previewConfigBuilder.build());
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+        Preview preview = new Preview.Builder().build();
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder().build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(preview);
@@ -564,10 +559,10 @@
     public void checkDefaultLensFacingForMixedUseCase() {
         setupCamera(/* supportsRaw= */ false);
 
-        Preview preview = new Preview(new PreviewConfig.Builder().build());
-        ImageCapture imageCapture = new ImageCapture(new ImageCaptureConfig.Builder().build());
-        ImageAnalysis imageAnalysis = new ImageAnalysis(new ImageAnalysisConfig.Builder().build());
-        VideoCapture videoCapture = new VideoCapture(new VideoCaptureConfig.Builder().build());
+        Preview preview = new Preview.Builder().build();
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder().build();
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder().build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder().build();
 
         PreviewConfig previewConfig = (PreviewConfig) preview.getUseCaseConfig();
         ImageCaptureConfig imageCaptureConfig =
@@ -603,9 +598,9 @@
         */
         final int displayWidth = 1080;
         final int displayHeight = 2220;
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        previewConfigBuilder.setTargetResolution(new Size(displayHeight, displayWidth));
-        Preview preview = new Preview(previewConfigBuilder.build());
+        Preview preview = new Preview.Builder()
+                .setTargetResolution(new Size(displayHeight, displayWidth))
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(preview);
@@ -637,9 +632,9 @@
         // The resolution selection will filter out the sizes which are smaller than min(640x480,
         // TARGET_RESOLUTION)
         final Size targetResolution = new Size(240, 320);
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        previewConfigBuilder.setTargetResolution(targetResolution);
-        Preview preview = new Preview(previewConfigBuilder.build());
+        Preview preview = new Preview.Builder()
+                .setTargetResolution(targetResolution)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(preview);
@@ -660,17 +655,15 @@
                 new SupportedSurfaceCombination(
                         mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
-        Preview preview = new Preview(previewConfigBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -689,17 +682,15 @@
                 new SupportedSurfaceCombination(
                         mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        videoCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
-        Preview preview = new Preview(previewConfigBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -727,16 +718,15 @@
         2. supportedOutputSizes for ImageCapture and Preview in
         SupportedSurfaceCombination#getAllPossibleSizeArrangements are the same.
         */
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
-        imageCaptureConfigBuilder.setTargetResolution(mDisplaySize);
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        previewConfigBuilder.setTargetResolution(mDisplaySize);
-        Preview preview = new Preview(previewConfigBuilder.build());
-        imageAnalysisConfigBuilder.setTargetResolution(mDisplaySize);
-        ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetResolution(mDisplaySize)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setTargetResolution(mDisplaySize)
+                .build();
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetResolution(mDisplaySize)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -757,17 +747,15 @@
                 new SupportedSurfaceCombination(
                         mContext, FULL_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-        ImageAnalysisConfig.Builder imageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageAnalysisConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        Preview preview = new Preview(previewConfigBuilder.build());
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        ImageAnalysis imageAnalysis = new ImageAnalysis(imageAnalysisConfigBuilder.build());
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
+        ImageAnalysis imageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -796,11 +784,11 @@
         setupCamera(/* supportsRaw= */ false);
 
         boolean previewExceptionHappened = false;
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder()
+        Preview.Builder previewBuilder = new Preview.Builder()
                 .setTargetResolution(mDisplaySize)
                 .setTargetAspectRatio(AspectRatio.RATIO_16_9);
         try {
-            previewConfigBuilder.build();
+            previewBuilder.build();
         } catch (IllegalArgumentException e) {
             previewExceptionHappened = true;
         }
@@ -836,24 +824,22 @@
                 new SupportedSurfaceCombination(
                         mContext, LIMITED_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        VideoCaptureConfig.Builder videoCaptureConfigBuilder = new VideoCaptureConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
         List<Pair<Integer, Size[]>> formatResolutionsPairList = new ArrayList<>();
         formatResolutionsPairList.add(Pair.create(ImageFormat.JPEG, new Size[]{mAnalysisSize}));
         formatResolutionsPairList.add(
                 Pair.create(ImageFormat.YUV_420_888, new Size[]{mAnalysisSize}));
         formatResolutionsPairList.add(Pair.create(ImageFormat.PRIVATE, new Size[]{mAnalysisSize}));
 
-        // Sets customized supported resolutions to 640x480 only.
-        imageCaptureConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
-        videoCaptureConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
-        previewConfigBuilder.setSupportedResolutions(formatResolutionsPairList);
-
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
-        VideoCapture videoCapture = new VideoCapture(videoCaptureConfigBuilder.build());
-        Preview preview = new Preview(previewConfigBuilder.build());
+        // Sets use cases customized supported resolutions to 640x480 only.
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setSupportedResolutions(formatResolutionsPairList)
+                .build();
+        VideoCapture videoCapture = new VideoCaptureConfig.Builder()
+                .setSupportedResolutions(formatResolutionsPairList)
+                .build();
+        Preview preview = new Preview.Builder()
+                .setSupportedResolutions(formatResolutionsPairList)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(imageCapture);
@@ -1031,17 +1017,14 @@
                 new SupportedSurfaceCombination(
                         mContext, LEGACY_CAMERA_ID, mMockCamcorderProfileHelper);
 
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-        ImageCaptureConfig.Builder imageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-
-        previewConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-        imageCaptureConfigBuilder.setTargetAspectRatio(AspectRatio.RATIO_16_9);
-
-        previewConfigBuilder.setDefaultResolution(mMod16Size);
-        imageCaptureConfigBuilder.setDefaultResolution(mMod16Size);
-
-        Preview preview = new Preview(previewConfigBuilder.build());
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfigBuilder.build());
+        Preview preview = new Preview.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .setDefaultResolution(mMod16Size)
+                .build();
+        ImageCapture imageCapture = new ImageCaptureConfig.Builder()
+                .setTargetAspectRatio(AspectRatio.RATIO_16_9)
+                .setDefaultResolution(mMod16Size)
+                .build();
 
         List<UseCase> useCases = new ArrayList<>();
         useCases.add(preview);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
index c728aeb..0ec35f7 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/CameraXTest.java
@@ -85,7 +85,7 @@
                 new ConfigProvider<FakeUseCaseConfig>() {
                     @Override
                     public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
-                        return new FakeUseCaseConfig.Builder().build();
+                        return new FakeUseCaseConfig.Builder().getUseCaseConfig();
                     }
                 });
         mUseCaseConfigFactory = defaultConfigFactory;
@@ -224,12 +224,9 @@
     @UiThreadTest
     public void bindMultipleUseCases() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
-        FakeUseCase fakeUseCase = new FakeUseCase(config0);
-        FakeOtherUseCaseConfig config1 =
-                new FakeOtherUseCaseConfig.Builder().setTargetName("config1").build();
-        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+        FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().setTargetName(
+                "config1").build();
 
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase, fakeOtherUseCase);
 
@@ -252,14 +249,12 @@
     @UiThreadTest
     public void bind_createsDifferentUseCaseGroups_forDifferentLifecycles() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
-        CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, new FakeUseCase(config0));
+        CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR,
+                new FakeUseCaseConfig.Builder().setTargetName("config0").build());
 
-        FakeUseCaseConfig config1 =
-                new FakeUseCaseConfig.Builder().setTargetName("config1").build();
         FakeLifecycleOwner anotherLifecycle = new FakeLifecycleOwner();
-        CameraX.bindToLifecycle(anotherLifecycle, CAMERA_SELECTOR, new FakeUseCase(config1));
+        CameraX.bindToLifecycle(anotherLifecycle, CAMERA_SELECTOR,
+                new FakeUseCaseConfig.Builder().setTargetName("config1").build());
 
         // One observer is the use case group. The other observer removes the use case upon the
         // lifecycle's destruction.
@@ -309,14 +304,10 @@
 
         CameraSelector frontSelector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().build();
-        FakeUseCase fakeUseCase = new FakeUseCase(config0);
+        FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().build();
         CameraSelector backSelector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
-        FakeOtherUseCaseConfig config1 =
-                new FakeOtherUseCaseConfig.Builder().build();
-        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().build();
 
         boolean hasException = false;
         try {
@@ -331,7 +322,7 @@
     @UiThreadTest
     public void bindUseCases_successReturnCamera() {
         initCameraX();
-        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().getUseCaseConfig();
 
         assertThat(CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR,
                 new FakeUseCase(config0))).isInstanceOf(Camera.class);
@@ -343,7 +334,7 @@
         initCameraX();
         CameraSelector frontSelector = new CameraSelector.Builder().requireLensFacing(
                 LensFacing.FRONT).build();
-        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().getUseCaseConfig();
         FakeUseCase fakeUseCase = new FakeUseCase(config0);
 
         // The front camera is not defined, we should get the IllegalArgumentException when it
@@ -365,8 +356,8 @@
     @UiThreadTest
     public void attachCameraControl_afterBindToLifecycle() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+                "config0").getUseCaseConfig();
         AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(config0);
 
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
@@ -379,8 +370,8 @@
     @UiThreadTest
     public void onCameraControlReadyIsCalled_afterBindToLifecycle() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+                "config0").getUseCaseConfig();
         AttachCameraFakeCase fakeUseCase = spy(new AttachCameraFakeCase(config0));
 
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
@@ -392,8 +383,8 @@
     @UiThreadTest
     public void detachCameraControl_afterUnbind() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+                "config0").getUseCaseConfig();
         AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(config0);
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
 
@@ -415,7 +406,8 @@
 
         FakeUseCaseConfig.Builder fakeConfigBuilder = new FakeUseCaseConfig.Builder();
         fakeConfigBuilder.setUseCaseEventCallback(eventCallback);
-        AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(fakeConfigBuilder.build());
+        AttachCameraFakeCase fakeUseCase = new AttachCameraFakeCase(
+                fakeConfigBuilder.getUseCaseConfig());
 
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase);
         Mockito.verify(eventCallback).onBind(mCameraId);
@@ -444,12 +436,9 @@
     @UiThreadTest
     public void canGetActiveUseCases_afterBindToLifecycle() {
         initCameraX();
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("config0").build();
-        FakeUseCase fakeUseCase = new FakeUseCase(config0);
-        FakeOtherUseCaseConfig config1 =
-                new FakeOtherUseCaseConfig.Builder().setTargetName("config1").build();
-        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCase(config1);
+        FakeUseCase fakeUseCase = new FakeUseCaseConfig.Builder().setTargetName("config0").build();
+        FakeOtherUseCase fakeOtherUseCase = new FakeOtherUseCaseConfig.Builder().setTargetName(
+                "config1").build();
 
         CameraX.bindToLifecycle(mLifecycle, CAMERA_SELECTOR, fakeUseCase, fakeOtherUseCase);
         mLifecycle.startAndResume();
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
index 7aed7d0..e1f1d54 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCase.java
@@ -39,7 +39,7 @@
 
     /** Creates a new instance of a {@link FakeOtherUseCase} with a default configuration. */
     FakeOtherUseCase() {
-        this(new FakeOtherUseCaseConfig.Builder().build());
+        this(new FakeOtherUseCaseConfig.Builder().getUseCaseConfig());
     }
 
     @Override
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
index 007be6e..eb5f67b 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/FakeOtherUseCaseConfig.java
@@ -252,10 +252,16 @@
             return mOptionsBundle;
         }
 
+        @NonNull
+        @Override
+        public FakeOtherUseCaseConfig getUseCaseConfig() {
+            return new FakeOtherUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+        }
+
         @Override
         @NonNull
-        public FakeOtherUseCaseConfig build() {
-            return new FakeOtherUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+        public FakeOtherUseCase build() {
+            return new FakeOtherUseCase(getUseCaseConfig());
         }
 
         // Implementations of TargetConfig.Builder default methods
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
index d7e7435..51f196e 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/ImageSaverTest.java
@@ -111,8 +111,8 @@
                 }
 
                 @Override
-                public void onError(
-                        SaveError saveError, String message, @Nullable Throwable cause) {
+                public void onError(@SaveError int saveError, String message,
+                        @Nullable Throwable cause) {
                     mMockCallback.onError(saveError, message, cause);
                     mSemaphore.release();
                 }
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
index 9c6612b..768a9e4 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseAttachStateTest.java
@@ -51,9 +51,9 @@
 @RunWith(AndroidJUnit4.class)
 public class UseCaseAttachStateTest {
     private static final CameraSelector BACK_CAMERA_SELECTOR =
-                    new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
+            new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
     private static final CameraSelector FRONT_CAMERA_SELECTOR =
-                    new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
+            new CameraSelector.Builder().requireLensFacing(LensFacing.FRONT).build();
     private final CameraDevice mMockCameraDevice = Mockito.mock(CameraDevice.class);
     private final CameraCaptureSession mMockCameraCaptureSession =
             Mockito.mock(CameraCaptureSession.class);
@@ -84,7 +84,7 @@
         FakeUseCaseConfig config =
                 new FakeUseCaseConfig.Builder()
                         .setTargetName("UseCase")
-                        .build();
+                        .getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -114,11 +114,11 @@
     @Test
     public void setTwoUseCasesOnline() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config0 =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config0 = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase0 = new TestUseCase(config0, BACK_CAMERA_SELECTOR, mCameraId);
-        FakeUseCaseConfig config1 =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config1 = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase1 = new TestUseCase(config1, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase0);
@@ -154,8 +154,8 @@
     @Test
     public void setUseCaseActiveOnly() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseActive(fakeUseCase);
@@ -184,8 +184,8 @@
     @Test
     public void setUseCaseActiveAndOnline() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -216,8 +216,8 @@
     @Test
     public void setUseCaseOffline() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -247,8 +247,8 @@
     @Test
     public void setUseCaseInactive() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -279,8 +279,8 @@
     @Test
     public void updateUseCase() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, BACK_CAMERA_SELECTOR, mCameraId);
 
         useCaseAttachState.setUseCaseOnline(fakeUseCase);
@@ -306,8 +306,8 @@
     @Test(expected = IllegalArgumentException.class)
     public void setUseCaseOnlineWithWrongCamera() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, FRONT_CAMERA_SELECTOR, mCameraId);
 
 
@@ -318,8 +318,8 @@
     @Test(expected = IllegalArgumentException.class)
     public void setUseCaseActiveWithWrongCamera() {
         UseCaseAttachState useCaseAttachState = new UseCaseAttachState(mCameraId);
-        FakeUseCaseConfig config =
-                new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase fakeUseCase = new TestUseCase(config, FRONT_CAMERA_SELECTOR, mCameraId);
 
         // Should throw IllegalArgumentException
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
index 664f066..cbeda0a 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseGroupTest.java
@@ -45,11 +45,11 @@
     public void setUp() {
         FakeUseCaseConfig fakeUseCaseConfig = new FakeUseCaseConfig.Builder()
                 .setTargetName("fakeUseCaseConfig")
-                .build();
+                .getUseCaseConfig();
         FakeOtherUseCaseConfig fakeOtherUseCaseConfig =
                 new FakeOtherUseCaseConfig.Builder()
                         .setTargetName("fakeOtherUseCaseConfig")
-                        .build();
+                        .getUseCaseConfig();
         mUseCaseGroup = new UseCaseGroup();
         mFakeUseCase = new FakeUseCase(fakeUseCaseConfig);
         mFakeOtherUseCase = new FakeOtherUseCase(fakeOtherUseCaseConfig);
diff --git a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
index d373c97..3dbcbb9 100644
--- a/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
+++ b/camera/camera-core/src/androidTest/java/androidx/camera/core/UseCaseTest.java
@@ -51,7 +51,8 @@
 
     @Test
     public void getAttachedCamera() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         SessionConfig sessionToAttach = new SessionConfig.Builder().build();
         testUseCase.attachToCamera("Camera", sessionToAttach);
@@ -63,7 +64,8 @@
 
     @Test
     public void getAttachedSessionConfig() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         SessionConfig sessionToAttach = new SessionConfig.Builder().build();
         testUseCase.attachToCamera("Camera", sessionToAttach);
@@ -75,7 +77,8 @@
 
     @Test
     public void removeListener() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
         testUseCase.removeStateChangeCallback(mMockUseCaseCallback);
@@ -87,7 +90,8 @@
 
     @Test
     public void clearListeners() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
         testUseCase.clear();
@@ -98,7 +102,8 @@
 
     @Test
     public void notifyActiveState() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
 
@@ -108,7 +113,8 @@
 
     @Test
     public void notifyInactiveState() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
 
@@ -118,7 +124,8 @@
 
     @Test
     public void notifyUpdatedSettings() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
 
@@ -128,7 +135,8 @@
 
     @Test
     public void notifyResetUseCase() {
-        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName("UseCase").build();
+        FakeUseCaseConfig config = new FakeUseCaseConfig.Builder().setTargetName(
+                "UseCase").getUseCaseConfig();
         TestUseCase testUseCase = new TestUseCase(config);
         testUseCase.addStateChangeCallback(mMockUseCaseCallback);
 
@@ -142,7 +150,7 @@
         FakeUseCaseConfig.Builder configBuilder =
                 new FakeUseCaseConfig.Builder().setTargetName(originalName);
 
-        TestUseCase testUseCase = new TestUseCase(configBuilder.build());
+        TestUseCase testUseCase = new TestUseCase(configBuilder.getUseCaseConfig());
         String originalRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
 
         // NOTE: Updating the use case name is probably a very bad idea in most cases. However,
@@ -150,7 +158,7 @@
         // it here for the sake of this test.
         String newName = "UseCase-New";
         configBuilder.setTargetName(newName);
-        testUseCase.updateUseCaseConfig(configBuilder.build());
+        testUseCase.updateUseCaseConfig(configBuilder.getUseCaseConfig());
         String newRetrievedName = testUseCase.getUseCaseConfig().getTargetName();
 
         assertThat(originalRetrievedName).isEqualTo(originalName);
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java b/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
index 210ce14..6011859 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/CallbackDeferrableSurface.java
@@ -20,6 +20,7 @@
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.camera.core.impl.utils.futures.Futures;
 import androidx.concurrent.futures.CallbackToFutureAdapter;
 
@@ -28,30 +29,32 @@
 import java.util.concurrent.Executor;
 
 /**
- * A {@link DeferrableSurface} wraps around user provided {@link Preview.PreviewSurfaceCallback}
+ * A {@link DeferrableSurface} wraps around user provided {@link Preview.PreviewSurfaceProvider}
  * and {@link Executor}.
  */
 final class CallbackDeferrableSurface extends DeferrableSurface implements SurfaceHolder {
 
     @NonNull
     private ListenableFuture<Surface> mSurfaceFuture;
-    @NonNull
-    private Preview.PreviewSurfaceCallback mPreviewSurfaceCallback;
+    @Nullable
+    private CallbackToFutureAdapter.Completer<Void> mCancellationCompleter;
     @NonNull
     private Executor mCallbackExecutor;
 
     CallbackDeferrableSurface(@NonNull Size resolution, @NonNull Executor callbackExecutor,
-            @NonNull Preview.PreviewSurfaceCallback previewSurfaceCallback) {
+            @NonNull Preview.PreviewSurfaceProvider previewSurfaceProvider) {
         mCallbackExecutor = callbackExecutor;
-        mPreviewSurfaceCallback = previewSurfaceCallback;
         // Re-wrap user's ListenableFuture with user's executor.
         mSurfaceFuture = CallbackToFutureAdapter.getFuture(
                 completer -> {
-                    callbackExecutor.execute(() -> {
-                        Futures.propagate(previewSurfaceCallback.createSurfaceFuture(resolution),
-                                completer);
-
-                    });
+                    callbackExecutor.execute(() -> Futures.propagate(
+                            previewSurfaceProvider.provideSurface(resolution,
+                                    CallbackToFutureAdapter.getFuture(
+                                            cancellationCompleter -> {
+                                                mCancellationCompleter = cancellationCompleter;
+                                                return "SurfaceCancellationFuture";
+                                            })),
+                            completer));
                     return "GetSurfaceFutureWithExecutor";
                 });
     }
@@ -66,7 +69,10 @@
      */
     @Override
     public void release() {
-        setOnSurfaceDetachedListener(mCallbackExecutor,
-                () -> mPreviewSurfaceCallback.onSafeToRelease(mSurfaceFuture));
+        setOnSurfaceDetachedListener(mCallbackExecutor, () -> {
+            if (mCancellationCompleter != null) {
+                mCancellationCompleter.set(null);
+            }
+        });
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
index 0f60030d..0427339 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysis.java
@@ -138,6 +138,7 @@
                 // TODO(b/143915543): Ensure this never gets called by a camera that is not bound
                 //  to this use case so we don't need to do this check.
                 if (isCurrentlyBoundCamera(cameraId)) {
+                    // Only reset the pipeline when the bound camera is the same.
                     SessionConfig.Builder sessionConfigBuilder = createPipeline(cameraId, config,
                             resolution);
                     attachToCamera(cameraId, sessionConfigBuilder.build());
@@ -194,19 +195,26 @@
      * Sets the target rotation.
      *
      * <p>This informs the use case so it can adjust the rotation value sent to
-     * {@link Analyzer#analyze(ImageProxy, int)}.
-     *
-     * <p>In most cases this should be set to the current rotation returned by {@link
-     * Display#getRotation()}.  In that case, the rotation parameter sent to the analyzer will be
-     * the rotation, which if applied to the output image, will make the image match the display
-     * orientation.
+     * {@link Analyzer#analyze(ImageProxy, int)} which provides rotation information to the
+     * analysis method. The rotation parameter sent to the analyzer will be the rotation, which if
+     * applied to the output image, will make the image match target rotation specified here.
      *
      * <p>While rotation can also be set via
      * {@link ImageAnalysisConfig.Builder#setTargetRotation(int)}, using
      * {@link ImageAnalysis#setTargetRotation(int)} allows the target rotation to be set
-     * dynamically. This can be useful if an app locks itself to portrait, and uses the orientation
-     * sensor to set rotation, to process landscape images when the device is rotated by examining
-     * the rotation received by the Analyzer function.
+     * dynamically.
+     *
+     * <p>In general, it is best to use an {@link android.view.OrientationEventListener} to
+     * set the target rotation.  This way, the rotation output to the Analyzer will indicate
+     * which way is down for a given image.  This is important since display orientation may be
+     * locked by device default, user setting, or app configuration,
+     * and some devices may not transition to a reverse-portrait display orientation.  In
+     * these cases, use {@link androidx.camera.core.ImageAnalysis#setTargetRotation} to set
+     * target rotation dynamically according to the
+     * {@link android.view.OrientationEventListener}, without re-creating the use case.  Note
+     * the OrientationEventListener output of degrees in the range [0..359] should be converted to
+     * a surface rotation, i.e. one of {@link Surface#ROTATION_0}, {@link Surface#ROTATION_90},
+     * {@link Surface#ROTATION_180}, or {@link Surface#ROTATION_270}.
      *
      * <p>If not set here or by configuration, the target rotation will default to the value of
      * {@link Display#getRotation()} of the default display at the time the
@@ -221,7 +229,7 @@
         int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
         if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
             mUseCaseConfigBuilder.setTargetRotation(rotation);
-            updateUseCaseConfig(mUseCaseConfigBuilder.build());
+            updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
 
             // TODO(b/122846516): Update session configuration and possibly reconfigure session.
             // For now we'll just update the relative rotation value.
@@ -475,7 +483,7 @@
                             .setMaxResolution(DEFAULT_MAX_RESOLUTION)
                             .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
 
-            DEFAULT_CONFIG = builder.build();
+            DEFAULT_CONFIG = builder.getUseCaseConfig();
         }
 
         @Override
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
index 9157ece..de69069 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisConfig.java
@@ -20,7 +20,6 @@
 import android.util.Pair;
 import android.util.Rational;
 import android.util.Size;
-import android.view.Display;
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
@@ -320,17 +319,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -698,6 +689,18 @@
         }
 
         /**
+         * {@inheritDoc}
+         *
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        @Override
+        public ImageAnalysisConfig getUseCaseConfig() {
+            return new ImageAnalysisConfig(OptionsBundle.from(mMutableConfig));
+        }
+
+        /**
          * Builds an immutable {@link ImageAnalysisConfig} from the current state.
          *
          * @return A {@link ImageAnalysisConfig} populated with the current state.
@@ -706,7 +709,7 @@
          */
         @Override
         @NonNull
-        public ImageAnalysisConfig build() {
+        public ImageAnalysis build() {
             // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
             // the same config.
             if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -715,7 +718,7 @@
                         "Cannot use both setTargetResolution and setTargetAspectRatio on the same"
                                 + " config.");
             }
-            return new ImageAnalysisConfig(OptionsBundle.from(mMutableConfig));
+            return new ImageAnalysis(getUseCaseConfig());
         }
 
         // Implementations of TargetConfig.Builder default methods
@@ -737,7 +740,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
@@ -857,12 +860,24 @@
         /**
          * Sets the rotation of the intended target for images from this configuration.
          *
+         * <p>The rotation parameter sent to the analyzer will be the rotation, which if applied to
+         * the output image, will make the image match target rotation specified here.
+         *
          * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
          * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
          * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
          *
+         * <p>In general, it is best to additionally set the target rotation dynamically on the use
+         * case.  See
+         * {@link androidx.camera.core.ImageAnalysis#setTargetRotation(int)} for additional
+         * documentation.
+         *
          * <p>If not set, the target rotation will default to the value of
-         * {@link Display#getRotation()} of the default display at the time the use case is created.
+         * {@link android.view.Display#getRotation()} of the default display at the time the
+         * use case is created.
+         *
+         * @see androidx.camera.core.ImageAnalysis#setTargetRotation(int)
+         * @see android.view.OrientationEventListener
          *
          * @param rotation The rotation of the intended target.
          * @return The current Builder.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
index 0c1d084..e04242e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCapture.java
@@ -282,6 +282,7 @@
                 // TODO(b/143915543): Ensure this never gets called by a camera that is not bound
                 //  to this use case so we don't need to do this check.
                 if (isCurrentlyBoundCamera(cameraId)) {
+                    // Only reset the pipeline when the bound camera is the same.
                     mSessionConfigBuilder = createPipeline(cameraId, config, resolution);
                     attachToCamera(cameraId, mSessionConfigBuilder.build());
                     notifyReset();
@@ -399,7 +400,7 @@
         Rational oldRatio = oldConfig.getTargetAspectRatioCustom(null);
         if (!aspectRatio.equals(oldRatio)) {
             mUseCaseConfigBuilder.setTargetAspectRatioCustom(aspectRatio);
-            updateUseCaseConfig(mUseCaseConfigBuilder.build());
+            updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
             mConfig = (ImageCaptureConfig) getUseCaseConfig();
 
             // TODO(b/122846516): Reconfigure capture session if the ratio is changed drastically.
@@ -446,7 +447,7 @@
         int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
         if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
             mUseCaseConfigBuilder.setTargetRotation(rotation);
-            updateUseCaseConfig(mUseCaseConfigBuilder.build());
+            updateUseCaseConfig(mUseCaseConfigBuilder.build().getUseCaseConfig());
             mConfig = (ImageCaptureConfig) getUseCaseConfig();
 
             // TODO(b/122846516): Update session configuration and possibly reconfigure session.
@@ -542,11 +543,11 @@
                     }
 
                     @Override
-                    public void onError(ImageSaver.SaveError error, String message,
+                    public void onError(@ImageSaver.SaveError int error, String message,
                             @Nullable Throwable cause) {
                         @ImageCaptureError int imageCaptureError = ImageCaptureError.UNKNOWN_ERROR;
                         switch (error) {
-                            case FILE_IO_FAILED:
+                            case ImageSaver.SaveError.FILE_IO_FAILED:
                                 imageCaptureError = ImageCaptureError.FILE_IO_ERROR;
                                 break;
                             default:
@@ -1208,7 +1209,7 @@
                             .setFlashMode(DEFAULT_FLASH_MODE)
                             .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
 
-            DEFAULT_CONFIG = builder.build();
+            DEFAULT_CONFIG = builder.getUseCaseConfig();
         }
 
         @Override
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
index 8b9f468..fc6971c 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageCaptureConfig.java
@@ -94,18 +94,6 @@
     /**
      * Returns the {@link FlashMode}.
      *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
-    public Integer getFlashMode(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_FLASH_MODE, valueIfMissing);
-    }
-
-    /**
-     * Returns the {@link FlashMode}.
-     *
      * @return The stored value, if it exists in this configuration.
      * @throws IllegalArgumentException if the option does not exist in this configuration.
      */
@@ -422,17 +410,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -763,15 +743,27 @@
         }
 
         /**
+         * {@inheritDoc}
+         *
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        @Override
+        public ImageCaptureConfig getUseCaseConfig() {
+            return new ImageCaptureConfig(OptionsBundle.from(mMutableConfig));
+        }
+
+        /**
          * Builds an immutable {@link ImageCaptureConfig} from the current state.
          *
          * @return A {@link ImageCaptureConfig} populated with the current state.
          * @throws IllegalArgumentException if attempting to set both target aspect ratio and
-         * target resolution.
+         *                                  target resolution.
          */
         @Override
         @NonNull
-        public ImageCaptureConfig build() {
+        public ImageCapture build() {
             // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
             // the same config.
             if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -780,7 +772,7 @@
                         "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
                                 + "config.");
             }
-            return new ImageCaptureConfig(OptionsBundle.from(mMutableConfig));
+            return new ImageCapture(getUseCaseConfig());
         }
 
         /**
@@ -908,7 +900,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
index 3951792..68431fa 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageOutputConfig.java
@@ -144,14 +144,12 @@
     Rational getTargetAspectRatioCustom();
 
     /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
+     * Verifies whether the aspect ratio of the target intending to use images from this
+     * configuration is set.
      *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
+     * @return true is the value exists in this configuration, false otherwise.
      */
-    @Nullable
-    Integer getTargetAspectRatio(@Nullable Integer valueIfMissing);
+    boolean hasTargetAspectRatio();
 
     /**
      * Retrieves the aspect ratio of the target intending to use images from this configuration.
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
index 0648e8d..8500ce9 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageSaver.java
@@ -18,12 +18,15 @@
 
 import android.location.Location;
 
+import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
 import androidx.camera.core.ImageUtil.CodecFailedException;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.concurrent.Executor;
 
 final class ImageSaver implements Runnable {
@@ -68,7 +71,7 @@
     @Override
     public void run() {
         // Finally, we save the file to disk
-        SaveError saveError = null;
+        Integer saveError = null;
         String errorMessage = null;
         Exception exception = null;
         try (ImageProxy imageToClose = mImage;
@@ -128,7 +131,7 @@
         });
     }
 
-    private void postError(final SaveError saveError, final String message,
+    private void postError(final @SaveError int saveError, final String message,
             @Nullable final Throwable cause) {
         mExecutor.execute(new Runnable() {
             @Override
@@ -139,20 +142,23 @@
     }
 
     /** Type of error that occurred during save */
-    public enum SaveError {
+    @IntDef({SaveError.FILE_IO_FAILED, SaveError.ENCODE_FAILED, SaveError.CROP_FAILED,
+            SaveError.UNKNOWN})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SaveError {
         /** Failed to write to or close the file */
-        FILE_IO_FAILED,
+        int FILE_IO_FAILED = 0;
         /** Failure when attempting to encode image */
-        ENCODE_FAILED,
+        int ENCODE_FAILED = 1;
         /** Failure when attempting to crop image */
-        CROP_FAILED,
-        UNKNOWN
+        int CROP_FAILED = 2;
+        int UNKNOWN = 3;
     }
 
     public interface OnImageSavedCallback {
 
         void onImageSaved(File file);
 
-        void onError(SaveError saveError, String message, @Nullable Throwable cause);
+        void onError(@SaveError int saveError, String message, @Nullable Throwable cause);
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
index c36070a..e60878f 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/Preview.java
@@ -16,14 +16,37 @@
 
 package androidx.camera.core;
 
+import static androidx.camera.core.PreviewConfig.IMAGE_INFO_PROCESSOR;
+import static androidx.camera.core.PreviewConfig.OPTION_BACKGROUND_EXECUTOR;
+import static androidx.camera.core.PreviewConfig.OPTION_CAMERA_ID_FILTER;
+import static androidx.camera.core.PreviewConfig.OPTION_CAPTURE_CONFIG_UNPACKER;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_CAPTURE_CONFIG;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_DEFAULT_SESSION_CONFIG;
+import static androidx.camera.core.PreviewConfig.OPTION_LENS_FACING;
+import static androidx.camera.core.PreviewConfig.OPTION_MAX_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_PREVIEW_CAPTURE_PROCESSOR;
+import static androidx.camera.core.PreviewConfig.OPTION_SESSION_CONFIG_UNPACKER;
+import static androidx.camera.core.PreviewConfig.OPTION_SUPPORTED_RESOLUTIONS;
+import static androidx.camera.core.PreviewConfig.OPTION_SURFACE_OCCUPANCY_PRIORITY;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ASPECT_RATIO;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ASPECT_RATIO_CUSTOM;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_CLASS;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_NAME;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_RESOLUTION;
+import static androidx.camera.core.PreviewConfig.OPTION_TARGET_ROTATION;
+import static androidx.camera.core.PreviewConfig.OPTION_USE_CASE_EVENT_CALLBACK;
+
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
 import android.media.ImageReader;
 import android.media.MediaCodec;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.util.Pair;
 import android.util.Rational;
 import android.util.Size;
+import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceView;
 import android.view.TextureView;
@@ -36,19 +59,20 @@
 import androidx.annotation.UiThread;
 import androidx.camera.core.impl.utils.Threads;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
-import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.util.Preconditions;
 
 import com.google.common.util.concurrent.ListenableFuture;
 
+import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 import java.util.concurrent.Executor;
 
 /**
  * A use case that provides a camera preview stream for displaying on-screen.
  *
  * <p>The preview stream is connected to the {@link Surface} provided via
- * {@link PreviewSurfaceCallback}. The application decides how the {@link Surface} is shown,
+ * {@link PreviewSurfaceProvider}. The application decides how the {@link Surface} is shown,
  * and is responsible for managing the {@link Surface} lifecycle after providing it.
  *
  * <p> To display the preview with the correct orientation, app needs to take different actions
@@ -103,10 +127,10 @@
 
     @SuppressWarnings("WeakerAccess") /* synthetic accessor */
     @Nullable
-    PreviewSurfaceCallback mPreviewSurfaceCallback;
+    PreviewSurfaceProvider mPreviewSurfaceProvider;
     @SuppressWarnings("WeakerAccess") /* Synthetic Accessor */
     @Nullable
-    Executor mPreviewSurfaceCallbackExecutor;
+    Executor mPreviewSurfaceProviderExecutor;
     // Cached latest resolution for creating the pipeline as soon as it's ready.
     @Nullable
     private Size mLatestResolution;
@@ -120,8 +144,9 @@
      *
      * @param config for this use case instance
      */
+    @SuppressWarnings("WeakerAccess")
     @MainThread
-    public Preview(@NonNull PreviewConfig config) {
+    Preview(@NonNull PreviewConfig config) {
         super(config);
     }
 
@@ -129,13 +154,13 @@
     SessionConfig.Builder createPipeline(@NonNull String cameraId, @NonNull PreviewConfig config,
             @NonNull Size resolution) {
         Threads.checkMainThread();
-        Preconditions.checkState(isPreviewSurfaceCallbackSet());
+        Preconditions.checkState(isPreviewSurfaceProviderSet());
         SessionConfig.Builder sessionConfigBuilder = SessionConfig.Builder.createFrom(config);
 
         final CaptureProcessor captureProcessor = config.getCaptureProcessor(null);
         final CallbackDeferrableSurface callbackDeferrableSurface = new CallbackDeferrableSurface(
-                resolution, mPreviewSurfaceCallbackExecutor,
-                mPreviewSurfaceCallback);
+                resolution, mPreviewSurfaceProviderExecutor,
+                mPreviewSurfaceProvider);
         if (captureProcessor != null) {
             CaptureStage captureStage = new CaptureStage.DefaultCaptureStage();
             // TODO: To allow user to use an Executor for the processing.
@@ -191,6 +216,7 @@
                 // TODO(b/143915543): Ensure this never gets called by a camera that is not bound
                 //  to this use case so we don't need to do this check.
                 if (isCurrentlyBoundCamera(cameraId)) {
+                    // Only reset the pipeline when the bound camera is the same.
                     SessionConfig.Builder sessionConfigBuilder = createPipeline(cameraId, config,
                             resolution);
 
@@ -204,7 +230,7 @@
     }
 
     /**
-     * Gets {@link PreviewSurfaceCallback}
+     * Gets {@link PreviewSurfaceProvider}
      *
      * <p> Setting the callback will signal to the camera that the use case is ready to receive
      * data.
@@ -218,35 +244,37 @@
      */
     @UiThread
     @Nullable
-    public PreviewSurfaceCallback getPreviewSurfaceCallback() {
+    public PreviewSurfaceProvider getPreviewSurfaceProvider() {
         Threads.checkMainThread();
-        return mPreviewSurfaceCallback;
+        return mPreviewSurfaceProvider;
     }
 
     /**
-     * Sets a {@link PreviewSurfaceCallback} to provide Surface for Preview.
+     * Sets a {@link PreviewSurfaceProvider} to provide Surface for Preview.
      *
-     * <p> Setting the callback will signal to the camera that the use case is ready to receive
+     * <p> Setting the provider will signal to the camera that the use case is ready to receive
      * data.
      *
-     * <p> To displaying preview with a {@link TextureView}, consider using
+     * TODO(b/144386349) Remove after minimal version of PreviewView implemented since using with
+     * TextureView is not safe.
+     * <p> To display a preview with a {@link TextureView}, consider using
      * {@link PreviewSurfaceProviders#createSurfaceTextureProvider(
      *PreviewSurfaceProviders.SurfaceTextureCallback)}
-     * to create the callback.
+     * to create the provider.
      *
-     * @param previewSurfaceCallback PreviewSurfaceCallback that provides a Preview.
-     * @param callbackExecutor       on which the previewSurfaceCallback will be triggered.
+     * @param executor               on which the previewSurfaceProvider will be triggered.
+     * @param previewSurfaceProvider PreviewSurfaceProvider that provides a Preview.
      */
     @UiThread
-    public void setPreviewSurfaceCallback(@NonNull Executor callbackExecutor,
-            @Nullable PreviewSurfaceCallback previewSurfaceCallback) {
+    public void setPreviewSurfaceProvider(@NonNull Executor executor,
+            @Nullable PreviewSurfaceProvider previewSurfaceProvider) {
         Threads.checkMainThread();
-        if (previewSurfaceCallback == null) {
-            mPreviewSurfaceCallback = null;
+        if (previewSurfaceProvider == null) {
+            mPreviewSurfaceProvider = null;
             notifyInactive();
         } else {
-            mPreviewSurfaceCallback = previewSurfaceCallback;
-            mPreviewSurfaceCallbackExecutor = callbackExecutor;
+            mPreviewSurfaceProvider = previewSurfaceProvider;
+            mPreviewSurfaceProviderExecutor = executor;
             notifyActive();
             if (mLatestResolution != null) {
                 updateConfigAndOutput(getBoundCameraId(), (PreviewConfig) getUseCaseConfig(),
@@ -256,30 +284,30 @@
     }
 
     /**
-     * Sets a {@link PreviewSurfaceCallback} to provide Surface for Preview.
+     * Sets a {@link PreviewSurfaceProvider} to provide Surface for Preview.
      *
-     * <p> Setting the callback will signal to the camera that the use case is ready to receive
-     * data. The callback will be triggered on main thread.
+     * <p> Setting the provider will signal to the camera that the use case is ready to receive
+     * data. The provider will be triggered on main thread.
      *
-     * @param previewSurfaceCallback PreviewSurfaceCallback that provides a Preview.
+     * @param previewSurfaceProvider PreviewSurfaceProvider that provides a Preview.
      */
     @UiThread
-    public void setPreviewSurfaceCallback(@Nullable PreviewSurfaceCallback previewSurfaceCallback) {
-        setPreviewSurfaceCallback(CameraXExecutors.mainThreadExecutor(), previewSurfaceCallback);
+    public void setPreviewSurfaceProvider(@Nullable PreviewSurfaceProvider previewSurfaceProvider) {
+        setPreviewSurfaceProvider(CameraXExecutors.mainThreadExecutor(), previewSurfaceProvider);
     }
 
     /**
-     * Checks if {@link PreviewSurfaceCallback} is set by the user.
+     * Checks if {@link PreviewSurfaceProvider} is set by the user.
      */
     @SuppressWarnings("WeakerAccess")
-    boolean isPreviewSurfaceCallbackSet() {
-        return mPreviewSurfaceCallback != null && mPreviewSurfaceCallbackExecutor != null;
+    boolean isPreviewSurfaceProviderSet() {
+        return mPreviewSurfaceProvider != null && mPreviewSurfaceProviderExecutor != null;
     }
 
 
     private void updateConfigAndOutput(@NonNull String cameraId, @NonNull PreviewConfig config,
             @NonNull Size resolution) {
-        Preconditions.checkState(isPreviewSurfaceCallbackSet());
+        Preconditions.checkState(isPreviewSurfaceProviderSet());
         attachToCamera(cameraId, createPipeline(cameraId, config, resolution).build());
     }
 
@@ -324,7 +352,7 @@
     protected UseCaseConfig.Builder<?, ?, ?> getDefaultBuilder(LensFacing lensFacing) {
         PreviewConfig defaults = CameraX.getDefaultUseCaseConfig(PreviewConfig.class, lensFacing);
         if (defaults != null) {
-            return PreviewConfig.Builder.fromConfig(defaults);
+            return Builder.fromConfig(defaults);
         }
 
         return null;
@@ -353,10 +381,9 @@
                     CameraX.getSurfaceManager().getCorrectedAspectRatio(deviceConfig,
                             imageConfig.getTargetRotation(Surface.ROTATION_0));
             if (resultRatio != null) {
-                PreviewConfig.Builder configBuilder = PreviewConfig.Builder.fromConfig(
-                        previewConfig);
+                Builder configBuilder = Builder.fromConfig(previewConfig);
                 configBuilder.setTargetAspectRatioCustom(resultRatio);
-                previewConfig = configBuilder.build();
+                previewConfig = configBuilder.getUseCaseConfig();
             }
         }
 
@@ -396,7 +423,7 @@
         }
         mLatestResolution = resolution;
 
-        if (isPreviewSurfaceCallbackSet()) {
+        if (isPreviewSurfaceProviderSet()) {
             updateConfigAndOutput(cameraId, (PreviewConfig) getUseCaseConfig(), resolution);
         }
         return suggestedResolutionMap;
@@ -404,75 +431,93 @@
 
 
     /**
-     * A callback for the application to provide a {@link Surface} to CameraX.
+     * A interface implemented by the application to provide a {@link Surface} for {@link Preview}.
      *
-     * <p> This interface is implemented by the application to provide a {@link Surface}, and then
-     * called by CameraX when a preview output Surface is needed or is no longer in use by CameraX.
+     * <p> This interface is implemented by the application to provide a {@link Surface}. This
+     * will be called by CameraX when it needs a Surface for Preview. It also signals when the
+     * Surface is no longer in use by CameraX.
      *
-     * @see Preview#setPreviewSurfaceCallback(PreviewSurfaceCallback)
+     * @see Preview#setPreviewSurfaceProvider(Executor, PreviewSurfaceProvider)
      */
-    public interface PreviewSurfaceCallback {
+    public interface PreviewSurfaceProvider {
 
         /**
-         * For the application to create an output Surface with the given resolution.
+         * Provides preview output Surface with the given resolution.
          *
          * <p> This is called when {@link Preview} needs a valid {@link Surface}. e.g. when the
-         * {@link Preview} is bound to lifecycle. If the {@link Surface} is backed by a
-         * {@link SurfaceTexture}, both the {@link Surface} and the {@link ListenableFuture} need
-         * to be recreated each time this is invoked. The application is also responsible to hold
-         * a reference to the {@link SurfaceTexture} since the weak reference from
-         * {@link Surface} does not prevent it to be garbage collected.
+         * Preview is bound to lifecycle. The Surface should either be backed by a
+         * {@link SurfaceTexture} or a {@link android.view.SurfaceHolder}.
          *
-         * <p> It's most common to use it with a {@link SurfaceView} or a {@link TextureView}.
-         * For {@link TextureView}, {@link PreviewSurfaceProviders} for creating {@link Surface}
-         * backed by a {@link SurfaceTexture}. For {@link SurfaceView}, the creation is in the
-         * hands of the {@link SurfaceView}. Use {@link CallbackToFutureAdapter} to wait for the
-         * creation of the {@link Surface} in {@link android.view.SurfaceHolder.Callback
-         * #surfaceChanged(android.view.SurfaceHolder, int, int, int)}. Example:
+         * <p>If the {@link Surface} is backed by a {@link SurfaceTexture}, both the
+         * {@link Surface} and the {@link ListenableFuture} need to be recreated each time this
+         * is invoked. The implementer is also responsible to hold a reference to the
+         * {@link SurfaceTexture} since the weak reference from {@link Surface} does not prevent
+         * it from being garbage collected.
+         *
+         * <p>If the {@link Surface} is backed by a {@link SurfaceView}, the
+         * {@link android.graphics.PixelFormat} should always be the default
+         * {@link android.graphics.PixelFormat#OPAQUE}.
+         *
+         * <p>The application will need to crop and rotate the Surface to fit the UI.
+         *
+         * <p>The resolution that is requested by CameraX will be the sensor resolution, based on
+         * the capabilities of the camera Preview is attached to. The approximate resolution used
+         * for the sensor can be controlled via
+         * {@link Preview.Builder#setTargetResolution(Size)}}. However, the final
+         * resolution that is used might need to be cropped in order to fit the view.
+         *
+         * <p> Undefined behavior may occur if the Surface does not have the requested resolution
+         * or is released before surfaceReleaseFuture completes. So care must be taken when to
+         * using a {@link SurfaceView} or a {@link TextureView} to handle rotation to display
+         * orientation, since they automatically resize and release the Surface.
+         *
+         * Example:
          *
          * <pre><code>
-         * class SurfaceViewHandler implements SurfaceHolder.Callback, PreviewSurfaceCallback {
+         * class MyPreviewSurfaceProvider implements PreviewSurfaceProvider {
          *
-         *     Size mResolution;
-         *     CallbackToFutureAdapter.Completer<Surface> mCompleter;
+         *     SurfaceTexture mSurfaceTexture;
          *
          *     &#64;Override
-         *     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-         *         if (mResolution != null && mCompleter != null && mResolution.getHeight()
-         *                 == height && mResolution.getWidth() == width) {
-         *             mCompleter.set(holder.getSurface());
-         *         }
-         *     }
+         *     public ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+         *         &#64;NonNull ListenableFuture<Void> surfaceReleaseFuture) {
+         *         // Create the ListenableFuture for the Surface
+         *         mSurfaceTexture = new SurfaceTexture(0);
+         *         mSurfaceTexture.detachFromGLContext();
+         *         ListenableFuture<Surface> surfaceFuture = CallbackToFutureAdapter.getFuture(
+         *             completer -> completer.set(new Surface(mSurfaceTexture));
          *
-         *     &#64;Override
-         *     public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
-         *         mResolution = resolution;
-         *         return CallbackToFutureAdapter.getFuture(completer -> {
-         *             mCompleter = completer
-         *         });
+         *         Futures.addCallback(surfaceReleaseFuture, new FutureCallback<Void>() {
+         *             &#64;Override
+         *             public void onSuccess(Void result) {
+         *                 // mSurfaceTexture is no longer used by the camera so it is safe to
+         *                 // release
+         *                 mSurfaceTexture.release();
+         *             }
+         *
+         *             &#64;Override
+         *             public void onFailure(Throwable t) {
+         *                 // Should never fail
+         *             }
+         *         }, CameraXExecutors.directExecutor());
+         *
+         *         return surfaceFuture;
          *     }
-         * }
          * </code></pre>
          *
-         * @param resolution the resolution of the {@link Surface} to create. The value is
-         *                   based on the coordinate system of the image sensor.
-         * @return A ListenableFuture that contains the application created Surface.
+         * @param resolution the resolution required by CameraX, which is in image sensor
+         *                   coordinate system.
+         * @param surfaceReleaseFuture it's safe to release the returned Surface return by the
+         *                            method, after this {@link ListenableFuture} finishes.
+         * @return A ListenableFuture that contains the implementer created Surface.
+         *
+         * {@see Preview} for rotation details
+         * {@see PreviewConfig.Builder#setTargetResolution(Size)}} for resolution controls
+         * {@see PreviewConfig.Builder#setTargetAspectRatio(int)} for resolution controls
          */
         @NonNull
-        ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution);
-
-        /**
-         * Called when the {@link Surface} is safe to be released.
-         *
-         * <p> This method is called when the {@link Surface} previously returned from
-         * {@link #createSurfaceFuture(Size)} is no longer being used by the camera system, and
-         * it's safe to be released during or after this is called. The application is
-         * responsible to release the {@link Surface} when it's also no longer being used by the
-         * app.
-         *
-         * @param surfaceFuture the {@link Surface} to be released.
-         */
-        void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture);
+        ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+                @NonNull ListenableFuture<Void> surfaceReleaseFuture);
     }
 
     /**
@@ -492,11 +537,11 @@
         private static final PreviewConfig DEFAULT_CONFIG;
 
         static {
-            PreviewConfig.Builder builder =
-                    new PreviewConfig.Builder()
+            Builder builder =
+                    new Builder()
                             .setMaxResolution(DEFAULT_MAX_RESOLUTION)
                             .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
-            DEFAULT_CONFIG = builder.build();
+            DEFAULT_CONFIG = builder.getUseCaseConfig();
         }
 
         @Override
@@ -504,4 +549,427 @@
             return DEFAULT_CONFIG;
         }
     }
+
+    /** Builder for a {@link Preview}. */
+    public static final class Builder
+            implements UseCaseConfig.Builder<Preview, PreviewConfig, Builder>,
+            ImageOutputConfig.Builder<Builder>,
+            CameraDeviceConfig.Builder<Builder>,
+            ThreadConfig.Builder<Builder> {
+
+        private final MutableOptionsBundle mMutableConfig;
+
+        /** Creates a new Builder object. */
+        public Builder() {
+            this(MutableOptionsBundle.create());
+        }
+
+        private Builder(MutableOptionsBundle mutableConfig) {
+            mMutableConfig = mutableConfig;
+
+            Class<?> oldConfigClass =
+                    mutableConfig.retrieveOption(TargetConfig.OPTION_TARGET_CLASS, null);
+            if (oldConfigClass != null && !oldConfigClass.equals(Preview.class)) {
+                throw new IllegalArgumentException(
+                        "Invalid target class configuration for "
+                                + Builder.this
+                                + ": "
+                                + oldConfigClass);
+            }
+
+            setTargetClass(Preview.class);
+        }
+
+        /**
+         * Generates a Builder from another Config object
+         *
+         * @param configuration An immutable configuration to pre-populate this builder.
+         * @return The new Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public static Builder fromConfig(@NonNull PreviewConfig configuration) {
+            return new Builder(MutableOptionsBundle.from(configuration));
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public MutableConfig getMutableConfig() {
+            return mMutableConfig;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        @Override
+        public PreviewConfig getUseCaseConfig() {
+            return new PreviewConfig(OptionsBundle.from(mMutableConfig));
+        }
+
+        /**
+         * Builds an immutable {@link Preview} from the current state.
+         *
+         * @return A {@link Preview} populated with the current state.
+         * @throws IllegalArgumentException if attempting to set both target aspect ratio and
+         *                                  target resolution.
+         */
+        @NonNull
+        @Override
+        public Preview build() {
+            // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
+            // the same config.
+            if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
+                    && getMutableConfig().retrieveOption(OPTION_TARGET_RESOLUTION, null) != null) {
+                throw new IllegalArgumentException(
+                        "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
+                                + "config.");
+            }
+            return new Preview(getUseCaseConfig());
+        }
+
+        // Implementations of TargetConfig.Builder default methods
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setTargetClass(@NonNull Class<Preview> targetClass) {
+            getMutableConfig().insertOption(OPTION_TARGET_CLASS, targetClass);
+
+            // If no name is set yet, then generate a unique name
+            if (null == getMutableConfig().retrieveOption(OPTION_TARGET_NAME, null)) {
+                String targetName = targetClass.getCanonicalName() + "-" + UUID.randomUUID();
+                setTargetName(targetName);
+            }
+
+            return this;
+        }
+
+        /**
+         * Sets the name of the target object being configured, used only for debug logging.
+         *
+         * <p>The name should be a value that can uniquely identify an instance of the object being
+         * configured.
+         *
+         * <p>If not set, the target name will default to an unique name automatically generated
+         * with the class canonical name and random UUID.
+         *
+         * @param targetName A unique string identifier for the instance of the class being
+         *                   configured.
+         * @return the current Builder.
+         */
+        @Override
+        @NonNull
+        public Builder setTargetName(@NonNull String targetName) {
+            getMutableConfig().insertOption(OPTION_TARGET_NAME, targetName);
+            return this;
+        }
+
+        // Implementations of CameraDeviceConfig.Builder default methods
+
+        /**
+         * Sets the primary camera to be configured based on the direction the lens is facing.
+         *
+         * <p>If multiple cameras exist with equivalent lens facing direction, the first ("primary")
+         * camera for that direction will be chosen.
+         *
+         * @param lensFacing The direction of the camera's lens.
+         * @return the current Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setLensFacing(@NonNull LensFacing lensFacing) {
+            getMutableConfig().insertOption(OPTION_LENS_FACING, lensFacing);
+            return this;
+        }
+
+        /**
+         * Sets a {@link CameraIdFilter} that filter out the unavailable camera id.
+         *
+         * <p>The camera id filter will be used to filter those cameras with lens facing
+         * specified in the config.
+         *
+         * @param cameraIdFilter The {@link CameraIdFilter}.
+         * @return the current Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setCameraIdFilter(@NonNull CameraIdFilter cameraIdFilter) {
+            getMutableConfig().insertOption(OPTION_CAMERA_ID_FILTER, cameraIdFilter);
+            return this;
+        }
+
+        // Implementations of ImageOutputConfig.Builder default methods
+
+        /**
+         * Sets the aspect ratio of the intended target for images from this configuration.
+         *
+         * <p>This is the ratio of the target's width to the image's height, where the numerator of
+         * the provided {@link Rational} corresponds to the width, and the denominator corresponds
+         * to the height.
+         *
+         * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
+         * ratio which may differ from the request, possibly due to device constraints.
+         * Application code should check the resulting output's resolution.
+         *
+         * <p>This method can be used to request an aspect ratio that is not from the standard set
+         * of aspect ratios defined in the {@link AspectRatio}.
+         *
+         * <p>This method will remove any value set by setTargetAspectRatio().
+         *
+         * <p>For Preview, the value will be used to calculate the suggested resolution size in
+         * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
+         *
+         * @param aspectRatio A {@link Rational} representing the ratio of the target's width and
+         *                    height.
+         * @return The current Builder.
+         * @hide
+         */
+        @NonNull
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        public Builder setTargetAspectRatioCustom(@NonNull Rational aspectRatio) {
+            getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM, aspectRatio);
+            getMutableConfig().removeOption(OPTION_TARGET_ASPECT_RATIO);
+            return this;
+        }
+
+        /**
+         * Sets the aspect ratio of the intended target for images from this configuration.
+         *
+         * <p>It is not allowed to set both target aspect ratio and target resolution on the same
+         * use case.  Attempting so will throw an IllegalArgumentException when building the
+         * Config.
+         *
+         * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
+         * ratio which may differ from the request, possibly due to device constraints.
+         * Application code should check the resulting output's resolution.
+         *
+         * <p>For Preview, the value will be used to calculate the suggested resolution size in
+         * {@link Preview.PreviewSurfaceProvider#provideSurface(Size, ListenableFuture)}.
+         *
+         * <p>If not set, resolutions with aspect ratio 4:3 will be considered in higher
+         * priority.
+         *
+         * @param aspectRatio A {@link AspectRatio} representing the ratio of the
+         *                    target's width and height.
+         * @return The current Builder.
+         */
+        @NonNull
+        @Override
+        public Builder setTargetAspectRatio(@AspectRatio int aspectRatio) {
+            getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO, aspectRatio);
+            return this;
+        }
+
+        /**
+         * Sets the rotation of the intended target for images from this configuration.
+         *
+         * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
+         * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
+         * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
+         *
+         * <p>If not set, the target rotation will default to the value of
+         * {@link Display#getRotation()} of the default display at the time the use case is created.
+         *
+         * @param rotation The rotation of the intended target.
+         * @return The current Builder.
+         * @hide Preview always set the rotation to device's nature orientation.
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        @Override
+        public Builder setTargetRotation(@ImageOutputConfig.RotationValue int rotation) {
+            getMutableConfig().insertOption(OPTION_TARGET_ROTATION, rotation);
+            return this;
+        }
+
+        /**
+         * Sets the resolution of the intended target from this configuration.
+         *
+         * <p>The target resolution attempts to establish a minimum bound for the preview
+         * resolution. The actual preview resolution will be the closest available resolution in
+         * size that is not smaller than the target resolution, as determined by the Camera
+         * implementation. However, if no resolution exists that is equal to or larger than the
+         * target resolution, the nearest available resolution smaller than the target resolution
+         * will be chosen.  Resolutions with the same aspect ratio of the provided {@link Size} will
+         * be considered in higher priority before resolutions of different aspect ratios.
+         *
+         * <p>It is not allowed to set both target aspect ratio and target resolution on the same
+         * use case.  Attempting so will throw an IllegalArgumentException when building the
+         * Config.
+         *
+         * <p>The resolution {@link Size} should be expressed at the use cases's target rotation.
+         * For example, a device with portrait natural orientation in natural target rotation
+         * requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees
+         * and targeting landscape orientation may specify 640x480.
+         *
+         * <p>The maximum available resolution that could be selected for a {@link Preview} is
+         * limited to be under 1080p. The limitation of 1080p for {@link Preview} has considered
+         * both performance and quality factors that users can obtain reasonable quality and smooth
+         * output stream under 1080p.
+         *
+         * <p>If not set, the default selected resolution will be the best size match to the
+         * device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
+         *
+         * @param resolution The target resolution to choose from supported output sizes list.
+         * @return The current Builder.
+         */
+        @NonNull
+        @Override
+        public Builder setTargetResolution(@NonNull Size resolution) {
+            getMutableConfig()
+                    .insertOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION, resolution);
+            if (resolution != null) {
+                getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM,
+                        new Rational(resolution.getWidth(), resolution.getHeight()));
+            }
+            return this;
+        }
+
+        /**
+         * Sets the default resolution of the intended target from this configuration.
+         *
+         * @param resolution The default resolution to choose from supported output sizes list.
+         * @return The current Builder.
+         * @hide
+         */
+        @NonNull
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        public Builder setDefaultResolution(@NonNull Size resolution) {
+            getMutableConfig().insertOption(OPTION_DEFAULT_RESOLUTION, resolution);
+            return this;
+        }
+
+        /** @hide */
+        @NonNull
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        public Builder setMaxResolution(@NonNull Size resolution) {
+            getMutableConfig().insertOption(OPTION_MAX_RESOLUTION, resolution);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setSupportedResolutions(@NonNull List<Pair<Integer, Size[]>> resolutions) {
+            getMutableConfig().insertOption(OPTION_SUPPORTED_RESOLUTIONS, resolutions);
+            return this;
+        }
+
+        // Implementations of ThreadConfig.Builder default methods
+
+        /**
+         * Sets the default executor that will be used for background tasks.
+         *
+         * <p>If not set, the background executor will default to an automatically generated
+         * {@link Executor}.
+         *
+         * @param executor The executor which will be used for background tasks.
+         * @return the current Builder.
+         * @hide Background executor not used in {@link Preview}.
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setBackgroundExecutor(@NonNull Executor executor) {
+            getMutableConfig().insertOption(OPTION_BACKGROUND_EXECUTOR, executor);
+            return this;
+        }
+
+        // Implementations of UseCaseConfig.Builder default methods
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setDefaultSessionConfig(@NonNull SessionConfig sessionConfig) {
+            getMutableConfig().insertOption(OPTION_DEFAULT_SESSION_CONFIG, sessionConfig);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setDefaultCaptureConfig(@NonNull CaptureConfig captureConfig) {
+            getMutableConfig().insertOption(OPTION_DEFAULT_CAPTURE_CONFIG, captureConfig);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setSessionOptionUnpacker(
+                @NonNull SessionConfig.OptionUnpacker optionUnpacker) {
+            getMutableConfig().insertOption(OPTION_SESSION_CONFIG_UNPACKER, optionUnpacker);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setCaptureOptionUnpacker(
+                @NonNull CaptureConfig.OptionUnpacker optionUnpacker) {
+            getMutableConfig().insertOption(OPTION_CAPTURE_CONFIG_UNPACKER, optionUnpacker);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setSurfaceOccupancyPriority(int priority) {
+            getMutableConfig().insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY, priority);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @Override
+        @NonNull
+        public Builder setUseCaseEventCallback(
+                @NonNull UseCase.EventCallback useCaseEventCallback) {
+            getMutableConfig().insertOption(OPTION_USE_CASE_EVENT_CALLBACK, useCaseEventCallback);
+            return this;
+        }
+
+        /** @hide */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public Builder setImageInfoProcessor(@NonNull ImageInfoProcessor processor) {
+            getMutableConfig().insertOption(IMAGE_INFO_PROCESSOR, processor);
+            return this;
+        }
+
+        /**
+         * Sets the {@link CaptureProcessor}.
+         *
+         * @param captureProcessor The requested capture processor for extension.
+         * @return The current Builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        public Builder setCaptureProcessor(@NonNull CaptureProcessor captureProcessor) {
+            getMutableConfig().insertOption(OPTION_PREVIEW_CAPTURE_PROCESSOR, captureProcessor);
+            return this;
+        }
+    }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
index 6c303fe..9f146da 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/PreviewConfig.java
@@ -19,7 +19,6 @@
 import android.util.Pair;
 import android.util.Rational;
 import android.util.Size;
-import android.view.Display;
 import android.view.Surface;
 
 import androidx.annotation.NonNull;
@@ -29,10 +28,14 @@
 
 import java.util.List;
 import java.util.Set;
-import java.util.UUID;
 import java.util.concurrent.Executor;
 
-/** Configuration for a {@link Preview} use case. */
+/**
+ * Configuration for a {@link Preview} use case.
+ *
+ * @hide
+ */
+@RestrictTo(Scope.LIBRARY_GROUP)
 public final class PreviewConfig
         implements UseCaseConfig<Preview>,
         ImageOutputConfig,
@@ -258,17 +261,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -578,417 +573,4 @@
 
     // End of the default implementation of Config
     // *********************************************************************************************
-
-    /** Builder for a {@link PreviewConfig}. */
-    public static final class Builder
-            implements UseCaseConfig.Builder<Preview, PreviewConfig, Builder>,
-            ImageOutputConfig.Builder<Builder>,
-            CameraDeviceConfig.Builder<Builder>,
-            ThreadConfig.Builder<Builder> {
-
-        private final MutableOptionsBundle mMutableConfig;
-
-        /** Creates a new Builder object. */
-        public Builder() {
-            this(MutableOptionsBundle.create());
-        }
-
-        private Builder(MutableOptionsBundle mutableConfig) {
-            mMutableConfig = mutableConfig;
-
-            Class<?> oldConfigClass =
-                    mutableConfig.retrieveOption(TargetConfig.OPTION_TARGET_CLASS, null);
-            if (oldConfigClass != null && !oldConfigClass.equals(Preview.class)) {
-                throw new IllegalArgumentException(
-                        "Invalid target class configuration for "
-                                + Builder.this
-                                + ": "
-                                + oldConfigClass);
-            }
-
-            setTargetClass(Preview.class);
-        }
-
-        /**
-         * Generates a Builder from another Config object
-         *
-         * @param configuration An immutable configuration to pre-populate this builder.
-         * @return The new Builder.
-         */
-        @NonNull
-        public static Builder fromConfig(@NonNull PreviewConfig configuration) {
-            return new Builder(MutableOptionsBundle.from(configuration));
-        }
-
-        /**
-         * {@inheritDoc}
-         *
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public MutableConfig getMutableConfig() {
-            return mMutableConfig;
-        }
-
-        /**
-         * Builds an immutable {@link PreviewConfig} from the current state.
-         *
-         * @return A {@link PreviewConfig} populated with the current state.
-         * @throws IllegalArgumentException if attempting to set both target aspect ratio and
-         * target resolution.
-         */
-        @NonNull
-        @Override
-        public PreviewConfig build() {
-            // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
-            // the same config.
-            if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
-                    && getMutableConfig().retrieveOption(OPTION_TARGET_RESOLUTION, null) != null) {
-                throw new IllegalArgumentException(
-                        "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
-                                + "config.");
-            }
-            return new PreviewConfig(OptionsBundle.from(mMutableConfig));
-        }
-
-        // Implementations of TargetConfig.Builder default methods
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setTargetClass(@NonNull Class<Preview> targetClass) {
-            getMutableConfig().insertOption(OPTION_TARGET_CLASS, targetClass);
-
-            // If no name is set yet, then generate a unique name
-            if (null == getMutableConfig().retrieveOption(OPTION_TARGET_NAME, null)) {
-                String targetName = targetClass.getCanonicalName() + "-" + UUID.randomUUID();
-                setTargetName(targetName);
-            }
-
-            return this;
-        }
-
-        /**
-         * Sets the name of the target object being configured.
-         *
-         * <p>The name should be a value that can uniquely identify an instance of the object being
-         * configured.
-         *
-         * <p>If not set, the target name will default to an unique name automatically generated
-         * with the class canonical name and random UUID.
-         *
-         * @param targetName A unique string identifier for the instance of the class being
-         *                   configured.
-         * @return the current Builder.
-         */
-        @Override
-        @NonNull
-        public Builder setTargetName(@NonNull String targetName) {
-            getMutableConfig().insertOption(OPTION_TARGET_NAME, targetName);
-            return this;
-        }
-
-        // Implementations of CameraDeviceConfig.Builder default methods
-
-        /**
-         * Sets the primary camera to be configured based on the direction the lens is facing.
-         *
-         * <p>If multiple cameras exist with equivalent lens facing direction, the first ("primary")
-         * camera for that direction will be chosen.
-         *
-         * @param lensFacing The direction of the camera's lens.
-         * @return the current Builder.
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setLensFacing(@NonNull LensFacing lensFacing) {
-            getMutableConfig().insertOption(OPTION_LENS_FACING, lensFacing);
-            return this;
-        }
-
-        /**
-         * Sets a {@link CameraIdFilter} that filter out the unavailable camera id.
-         *
-         * <p>The camera id filter will be used to filter those cameras with lens facing
-         * specified in the config.
-         *
-         * @param cameraIdFilter The {@link CameraIdFilter}.
-         * @return the current Builder.
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setCameraIdFilter(@NonNull CameraIdFilter cameraIdFilter) {
-            getMutableConfig().insertOption(OPTION_CAMERA_ID_FILTER, cameraIdFilter);
-            return this;
-        }
-
-        // Implementations of ImageOutputConfig.Builder default methods
-
-        /**
-         * Sets the aspect ratio of the intended target for images from this configuration.
-         *
-         * <p>This is the ratio of the target's width to the image's height, where the numerator of
-         * the provided {@link Rational} corresponds to the width, and the denominator corresponds
-         * to the height.
-         *
-         * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
-         * ratio which may differ from the request, possibly due to device constraints.
-         * Application code should check the resulting output's resolution.
-         *
-         * <p>This method can be used to request an aspect ratio that is not from the standard set
-         * of aspect ratios defined in the {@link AspectRatio}.
-         *
-         * <p>This method will remove any value set by setTargetAspectRatio().
-         *
-         * <p>For Preview, the value will be used to calculate the suggested resolution size in
-         * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
-         *
-         * @param aspectRatio A {@link Rational} representing the ratio of the target's width and
-         *                    height.
-         * @return The current Builder.
-         * @hide
-         */
-        @NonNull
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        public Builder setTargetAspectRatioCustom(@NonNull Rational aspectRatio) {
-            getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM, aspectRatio);
-            getMutableConfig().removeOption(OPTION_TARGET_ASPECT_RATIO);
-            return this;
-        }
-
-        /**
-         * Sets the aspect ratio of the intended target for images from this configuration.
-         *
-         * <p>It is not allowed to set both target aspect ratio and target resolution on the same
-         * use case.  Attempting so will throw an IllegalArgumentException when building the
-         * Config.
-         *
-         * <p>The target aspect ratio is used as a hint when determining the resulting output aspect
-         * ratio which may differ from the request, possibly due to device constraints.
-         * Application code should check the resulting output's resolution.
-         *
-         * <p>For Preview, the value will be used to calculate the suggested resolution size in
-         * {@link Preview.PreviewSurfaceCallback#createSurfaceFuture(Size)}.
-         *
-         * <p>If not set, resolutions with aspect ratio 4:3 will be considered in higher
-         * priority.
-         *
-         * @param aspectRatio A {@link AspectRatio} representing the ratio of the
-         *                    target's width and height.
-         * @return The current Builder.
-         */
-        @NonNull
-        @Override
-        public Builder setTargetAspectRatio(@AspectRatio int aspectRatio) {
-            getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO, aspectRatio);
-            return this;
-        }
-
-        /**
-         * Sets the rotation of the intended target for images from this configuration.
-         *
-         * <p>This is one of four valid values: {@link Surface#ROTATION_0}, {@link
-         * Surface#ROTATION_90}, {@link Surface#ROTATION_180}, {@link Surface#ROTATION_270}.
-         * Rotation values are relative to the "natural" rotation, {@link Surface#ROTATION_0}.
-         *
-         * <p>If not set, the target rotation will default to the value of
-         * {@link Display#getRotation()} of the default display at the time the use case is created.
-         *
-         * @param rotation The rotation of the intended target.
-         * @return The current Builder.
-         * @hide Preview always set the rotation to device's nature orientation.
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @NonNull
-        @Override
-        public Builder setTargetRotation(@RotationValue int rotation) {
-            getMutableConfig().insertOption(OPTION_TARGET_ROTATION, rotation);
-            return this;
-        }
-
-        /**
-         * Sets the resolution of the intended target from this configuration.
-         *
-         * <p>The target resolution attempts to establish a minimum bound for the preview
-         * resolution. The actual preview resolution will be the closest available resolution in
-         * size that is not smaller than the target resolution, as determined by the Camera
-         * implementation. However, if no resolution exists that is equal to or larger than the
-         * target resolution, the nearest available resolution smaller than the target resolution
-         * will be chosen.  Resolutions with the same aspect ratio of the provided {@link Size} will
-         * be considered in higher priority before resolutions of different aspect ratios.
-         *
-         * <p>It is not allowed to set both target aspect ratio and target resolution on the same
-         * use case.  Attempting so will throw an IllegalArgumentException when building the
-         * Config.
-         *
-         * <p>The resolution {@link Size} should be expressed at the use cases's target rotation.
-         * For example, a device with portrait natural orientation in natural target rotation
-         * requesting a portrait image may specify 480x640, and the same device, rotated 90 degrees
-         * and targeting landscape orientation may specify 640x480.
-         *
-         * <p>The maximum available resolution that could be selected for a {@link Preview} is
-         * limited to be under 1080p. The limitation of 1080p for {@link Preview} has considered
-         * both performance and quality factors that users can obtain reasonable quality and smooth
-         * output stream under 1080p.
-         *
-         * <p>If not set, the default selected resolution will be the best size match to the
-         * device's screen resolution, or to 1080p (1920x1080), whichever is smaller.
-         *
-         * @param resolution The target resolution to choose from supported output sizes list.
-         * @return The current Builder.
-         */
-        @NonNull
-        @Override
-        public Builder setTargetResolution(@NonNull Size resolution) {
-            getMutableConfig()
-                    .insertOption(ImageOutputConfig.OPTION_TARGET_RESOLUTION, resolution);
-            if (resolution != null) {
-                getMutableConfig().insertOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM,
-                        new Rational(resolution.getWidth(), resolution.getHeight()));
-            }
-            return this;
-        }
-
-        /**
-         * Sets the default resolution of the intended target from this configuration.
-         *
-         * @param resolution The default resolution to choose from supported output sizes list.
-         * @return The current Builder.
-         * @hide
-         */
-        @NonNull
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        public Builder setDefaultResolution(@NonNull Size resolution) {
-            getMutableConfig().insertOption(OPTION_DEFAULT_RESOLUTION, resolution);
-            return this;
-        }
-
-        /** @hide */
-        @NonNull
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        public Builder setMaxResolution(@NonNull Size resolution) {
-            getMutableConfig().insertOption(OPTION_MAX_RESOLUTION, resolution);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setSupportedResolutions(@NonNull List<Pair<Integer, Size[]>> resolutions) {
-            getMutableConfig().insertOption(OPTION_SUPPORTED_RESOLUTIONS, resolutions);
-            return this;
-        }
-
-        // Implementations of ThreadConfig.Builder default methods
-
-        /**
-         * Sets the default executor that will be used for background tasks.
-         *
-         * <p>If not set, the background executor will default to an automatically generated
-         * {@link Executor}.
-         *
-         * @param executor The executor which will be used for background tasks.
-         * @return the current Builder.
-         * @hide Background executor not used in {@link Preview}.
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setBackgroundExecutor(@NonNull Executor executor) {
-            getMutableConfig().insertOption(OPTION_BACKGROUND_EXECUTOR, executor);
-            return this;
-        }
-
-        // Implementations of UseCaseConfig.Builder default methods
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setDefaultSessionConfig(@NonNull SessionConfig sessionConfig) {
-            getMutableConfig().insertOption(OPTION_DEFAULT_SESSION_CONFIG, sessionConfig);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setDefaultCaptureConfig(@NonNull CaptureConfig captureConfig) {
-            getMutableConfig().insertOption(OPTION_DEFAULT_CAPTURE_CONFIG, captureConfig);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setSessionOptionUnpacker(
-                @NonNull SessionConfig.OptionUnpacker optionUnpacker) {
-            getMutableConfig().insertOption(OPTION_SESSION_CONFIG_UNPACKER, optionUnpacker);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setCaptureOptionUnpacker(
-                @NonNull CaptureConfig.OptionUnpacker optionUnpacker) {
-            getMutableConfig().insertOption(OPTION_CAPTURE_CONFIG_UNPACKER, optionUnpacker);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setSurfaceOccupancyPriority(int priority) {
-            getMutableConfig().insertOption(OPTION_SURFACE_OCCUPANCY_PRIORITY, priority);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @Override
-        @NonNull
-        public Builder setUseCaseEventCallback(
-                @NonNull UseCase.EventCallback useCaseEventCallback) {
-            getMutableConfig().insertOption(OPTION_USE_CASE_EVENT_CALLBACK, useCaseEventCallback);
-            return this;
-        }
-
-        /** @hide */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @NonNull
-        public Builder setImageInfoProcessor(@NonNull ImageInfoProcessor processor) {
-            getMutableConfig().insertOption(IMAGE_INFO_PROCESSOR, processor);
-            return this;
-        }
-
-        /**
-         * Sets the {@link CaptureProcessor}.
-         *
-         * @param captureProcessor The requested capture processor for extension.
-         * @return The current Builder.
-         * @hide
-         */
-        @RestrictTo(Scope.LIBRARY_GROUP)
-        @NonNull
-        public Builder setCaptureProcessor(@NonNull CaptureProcessor captureProcessor) {
-            getMutableConfig().insertOption(OPTION_PREVIEW_CAPTURE_PROCESSOR, captureProcessor);
-            return this;
-        }
-    }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java b/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
index edd9033..371399e 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/PreviewSurfaceProviders.java
@@ -17,22 +17,16 @@
 package androidx.camera.core;
 
 import android.graphics.SurfaceTexture;
-import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
 import android.view.TextureView;
 
 import androidx.annotation.NonNull;
+import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.Futures;
 
-import com.google.common.util.concurrent.ListenableFuture;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-
 /**
- * This class creates implementations of PreviewSurfaceCallback that provide Surfaces that have been
+ * This class creates implementations of PreviewSurfaceProvider that provide Surfaces that have been
  * pre-configured for specific work flows.
  */
 public final class PreviewSurfaceProviders {
@@ -43,23 +37,21 @@
     }
 
     /**
-     * Creates a {@link Preview.PreviewSurfaceCallback} that is backed by a {@link SurfaceTexture}.
+     * Creates a {@link Preview.PreviewSurfaceProvider} that is backed by a {@link SurfaceTexture}.
      *
-     * <p>This is a convenience method for creating a {@link Preview.PreviewSurfaceCallback}
+     * <p>This is a convenience method for creating a {@link Preview.PreviewSurfaceProvider}
      * whose {@link Surface} is backed by a {@link SurfaceTexture}. The returned
-     * {@link Preview.PreviewSurfaceCallback} is responsible for creating the {@link SurfaceTexture}
-     * and propagating {@link Preview.PreviewSurfaceCallback#onSafeToRelease(ListenableFuture)}
-     * back to the implementer. The {@link SurfaceTexture} is usually used with a
-     * {@link TextureView}.
+     * {@link Preview.PreviewSurfaceProvider} is responsible for creating the
+     * {@link SurfaceTexture}. The {@link SurfaceTexture} may not be safe to use with
+     * {@link TextureView}
      * Example:
      *
      * <pre><code>
-     * preview.setPreviewSurfaceCallback(createPreviewSurfaceCallback(
+     * preview.setPreviewSurfaceProvider(createPreviewSurfaceProvider(
      *         new PreviewSurfaceProviders.SurfaceTextureCallback() {
      *             &#64;Override
      *             public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture) {
-     *                 // Maybe remove and re-add the TextureView to its parent.
-     *                 textureView.setSurfaceTexture(surfaceTexture);
+     *                 // Use the SurfaceTexture
      *             }
      *
      *             &#64;Override
@@ -69,49 +61,26 @@
      *         }));
      * </code></pre>
      *
-     * <p> Note that the TextureView needs to be removed and re-added from the parent view for the
-     * SurfaceTexture to be attached, because TextureView's existing SurfaceTexture is only
-     * correctly detached once the parent TextureView is removed from the view hierarchy.
-     *
      * @param surfaceTextureCallback callback called when the SurfaceTexture is ready to be
      *                               set/released.
-     * @return a {@link Preview.PreviewSurfaceCallback} to be used with
-     * {@link Preview#setPreviewSurfaceCallback(Preview.PreviewSurfaceCallback)}.
+     * @return a {@link Preview.PreviewSurfaceProvider} to be used with
+     * {@link Preview#setPreviewSurfaceProvider(Preview.PreviewSurfaceProvider)}.
      */
     @NonNull
-    public static Preview.PreviewSurfaceCallback createSurfaceTextureProvider(
+    public static Preview.PreviewSurfaceProvider createSurfaceTextureProvider(
             @NonNull SurfaceTextureCallback surfaceTextureCallback) {
-        return new Preview.PreviewSurfaceCallback() {
-
-            Map<Surface, SurfaceTexture> mSurfaceTextureMap = new HashMap<>();
-
-            @NonNull
-            @Override
-            public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
-                SurfaceTexture surfaceTexture = new SurfaceTexture(0);
-                surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
-                        resolution.getHeight());
-                surfaceTexture.detachFromGLContext();
-                surfaceTextureCallback.onSurfaceTextureReady(surfaceTexture, resolution);
-                Surface surface = new Surface(surfaceTexture);
-                mSurfaceTextureMap.put(surface, surfaceTexture);
-                return Futures.immediateFuture(surface);
-            }
-
-            @Override
-            public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
-                try {
-                    Surface surface = surfaceFuture.get();
-                    SurfaceTexture surfaceTexture = mSurfaceTextureMap.get(surface);
-                    if (surfaceTexture != null) {
-                        surfaceTextureCallback.onSafeToRelease(surfaceTexture);
-                        mSurfaceTextureMap.remove(surface);
-                    }
-                    surface.release();
-                } catch (ExecutionException | InterruptedException e) {
-                    Log.w(TAG, "Failed to release the Surface.", e);
-                }
-            }
+        return (resolution, safeToCancelFuture) -> {
+            SurfaceTexture surfaceTexture = new SurfaceTexture(0);
+            surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
+                    resolution.getHeight());
+            surfaceTexture.detachFromGLContext();
+            surfaceTextureCallback.onSurfaceTextureReady(surfaceTexture, resolution);
+            Surface surface = new Surface(surfaceTexture);
+            safeToCancelFuture.addListener(() -> {
+                surface.release();
+                surfaceTextureCallback.onSafeToRelease(surfaceTexture);
+            }, CameraXExecutors.directExecutor());
+            return Futures.immediateFuture(surface);
         };
     }
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
index 8bdb381..6df4dcb 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCase.java
@@ -93,7 +93,6 @@
      * Creates a named instance of the use case.
      *
      * @param useCaseConfig the configuration object used for this use case
-     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -162,7 +161,7 @@
      *
      * @param userConfig           The user-supplied configuration.
      * @param defaultConfigBuilder A builder containing use-case default values, or {@code null}
-     *                            if no default values exist.
+     *                             if no default values exist.
      * @return The configuration that will be used by this use case.
      * @hide
      */
@@ -186,10 +185,9 @@
                     objectOpt, userConfig.retrieveOption(objectOpt));
         }
 
-        @SuppressWarnings(
-                "unchecked") // Since builder is a UseCaseConfig.Builder, it should produce a
-                // UseCaseConfig
-                UseCaseConfig<?> defaultConfig = defaultConfigBuilder.build();
+        // Since builder is a UseCaseConfig.Builder, it should produce a UseCaseConfig
+        @SuppressWarnings("unchecked")
+        UseCaseConfig<?> defaultConfig = defaultConfigBuilder.getUseCaseConfig();
         return defaultConfig;
     }
 
@@ -370,6 +368,7 @@
     /**
      * Returns the camera ID for the currently bound camera, or throws an exception if no camera is
      * bound.
+     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -382,6 +381,7 @@
 
     /**
      * Checks whether the provided camera ID is the currently bound camera ID.
+     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -392,8 +392,7 @@
             boundCameraId = getCameraIdUnchecked(deviceConfig);
         }
 
-        // Bound camera changed. Don't attempt reset.
-        return !Objects.equals(cameraId, boundCameraId);
+        return Objects.equals(cameraId, boundCameraId);
     }
 
     /**
@@ -437,6 +436,7 @@
     /**
      * Returns the currently bound {@link CameraDeviceConfig} or {@code null} if none is bound.
      * TODO(b/142840814): Only rely on attached Camera rather than config.
+     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -490,7 +490,6 @@
      *                               bound.
      * @return The map with the resolutions that finally used to create the SessionConfig to
      * attach to the camera device.
-     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
@@ -529,6 +528,7 @@
 
     /**
      * Called when use case is online in camera. This method is called on main thread.
+     *
      * @hide
      */
     @RestrictTo(Scope.LIBRARY_GROUP)
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
index 24a0b98..39c7427 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/UseCaseConfig.java
@@ -234,10 +234,11 @@
     int getSurfaceOccupancyPriority();
 
     /**
-     * Builder for a {@link UseCaseConfig}.
+     * Builder for a {@link UseCase}.
      *
-     * @param <T> The type of the object being configured.
-     * @param <C> The top level configuration which will be generated by {@link #build()}.
+     * @param <T> The type of the object which will be built by {@link #build()}.
+     * @param <C> The top level configuration which will be generated by
+     *            {@link #getUseCaseConfig()}.
      * @param <B> The top level builder type for which this builder is composed with.
      * @hide
      */
@@ -313,12 +314,22 @@
         B setSurfaceOccupancyPriority(int priority);
 
         /**
-         * Builds the configuration for the target use case.
+         * Retrieves the configuration used by this builder.
+         *
+         * @return the configuration used by this builder.
+         * @hide
+         */
+        @RestrictTo(Scope.LIBRARY_GROUP)
+        @NonNull
+        C getUseCaseConfig();
+
+        /**
+         * Builds the target use case using the configuration.
          *
          * @hide
          */
         @RestrictTo(Scope.LIBRARY_GROUP)
         @NonNull
-        C build();
+        T build();
     }
 }
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
index 79e6c70..ebfcb54 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCapture.java
@@ -441,7 +441,7 @@
         int oldRotation = oldConfig.getTargetRotation(ImageOutputConfig.INVALID_ROTATION);
         if (oldRotation == ImageOutputConfig.INVALID_ROTATION || oldRotation != rotation) {
             mUseCaseConfigBuilder.setTargetRotation(rotation);
-            updateUseCaseConfig(mUseCaseConfigBuilder.build());
+            updateUseCaseConfig(mUseCaseConfigBuilder.getUseCaseConfig());
 
             // TODO(b/122846516): Update session configuration and possibly reconfigure session.
         }
@@ -481,6 +481,7 @@
                 // TODO(b/143915543): Ensure this never gets called by a camera that is not bound
                 //  to this use case so we don't need to do this check.
                 if (isCurrentlyBoundCamera(cameraId)) {
+                    // Only reset the pipeline when the bound camera is the same.
                     setupEncoder(cameraId, resolution);
                 }
             }
@@ -934,7 +935,7 @@
                             .setMaxResolution(DEFAULT_MAX_RESOLUTION)
                             .setSurfaceOccupancyPriority(DEFAULT_SURFACE_OCCUPANCY_PRIORITY);
 
-            DEFAULT_CONFIG = builder.build();
+            DEFAULT_CONFIG = builder.getUseCaseConfig();
         }
 
         @Override
@@ -952,8 +953,10 @@
 
     private final class VideoSavedListenerWrapper implements OnVideoSavedCallback {
 
-        @NonNull Executor mExecutor;
-        @NonNull OnVideoSavedCallback mOnVideoSavedCallback;
+        @NonNull
+        Executor mExecutor;
+        @NonNull
+        OnVideoSavedCallback mOnVideoSavedCallback;
 
         VideoSavedListenerWrapper(@NonNull Executor executor,
                 @NonNull OnVideoSavedCallback onVideoSavedCallback) {
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
index b4fc308..1164d75 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/VideoCaptureConfig.java
@@ -462,17 +462,9 @@
         return retrieveOption(OPTION_TARGET_ASPECT_RATIO_CUSTOM);
     }
 
-    /**
-     * Retrieves the aspect ratio of the target intending to use images from this configuration.
-     *
-     * @param valueIfMissing The value to return if this configuration option has not been set.
-     * @return The stored value or <code>valueIfMissing</code> if the value does not exist in this
-     * configuration.
-     */
-    @Nullable
     @Override
-    public Integer getTargetAspectRatio(@Nullable Integer valueIfMissing) {
-        return retrieveOption(OPTION_TARGET_ASPECT_RATIO, valueIfMissing);
+    public boolean hasTargetAspectRatio() {
+        return containsOption(OPTION_TARGET_ASPECT_RATIO);
     }
 
     /**
@@ -781,6 +773,12 @@
             return mMutableConfig;
         }
 
+        @NonNull
+        @Override
+        public VideoCaptureConfig getUseCaseConfig() {
+            return new VideoCaptureConfig(OptionsBundle.from(mMutableConfig));
+        }
+
         /**
          * Builds an immutable {@link VideoCaptureConfig} from the current state.
          *
@@ -788,7 +786,7 @@
          */
         @Override
         @NonNull
-        public VideoCaptureConfig build() {
+        public VideoCapture build() {
             // Error at runtime for using both setTargetResolution and setTargetAspectRatio on
             // the same config.
             if (getMutableConfig().retrieveOption(OPTION_TARGET_ASPECT_RATIO, null) != null
@@ -797,7 +795,7 @@
                         "Cannot use both setTargetResolution and setTargetAspectRatio on the same "
                                 + "config.");
             }
-            return new VideoCaptureConfig(OptionsBundle.from(mMutableConfig));
+            return new VideoCapture(getUseCaseConfig());
         }
 
         /**
@@ -925,7 +923,7 @@
         }
 
         /**
-         * Sets the name of the target object being configured.
+         * Sets the name of the target object being configured, used only for debug logging.
          *
          * <p>The name should be a value that can uniquely identify an instance of the object being
          * configured.
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java b/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
index 0faee6a..2fdadc8 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/CameraSelectorTest.java
@@ -62,7 +62,7 @@
                 new ConfigProvider<FakeUseCaseConfig>() {
                     @Override
                     public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
-                        return new FakeUseCaseConfig.Builder().build();
+                        return new FakeUseCaseConfig.Builder().getUseCaseConfig();
                     }
                 });
         FakeCameraFactory cameraFactory = new FakeCameraFactory();
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
index 98a7228..93a370b 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ExtendableUseCaseConfigFactoryTest.java
@@ -57,7 +57,7 @@
 
         @Override
         public FakeUseCaseConfig getConfig(LensFacing lensFacing) {
-            return new FakeUseCaseConfig.Builder().build();
+            return new FakeUseCaseConfig.Builder().getUseCaseConfig();
         }
     }
 }
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
index 7af61a1..8e63da3 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ImageAnalysisTest.java
@@ -214,11 +214,11 @@
 
     private void setUpImageAnalysisWithStrategy(
             @ImageAnalysis.BackpressureStrategy int backpressureStrategy) {
-        mImageAnalysis = new ImageAnalysis(new ImageAnalysisConfig.Builder()
+        mImageAnalysis = new ImageAnalysisConfig.Builder()
                 .setBackgroundExecutor(mBackgroundExecutor)
                 .setImageQueueDepth(QUEUE_DEPTH)
                 .setBackpressureStrategy(backpressureStrategy)
-                .build());
+                .build();
 
         mImageAnalysis.setAnalyzer(CameraXExecutors.newHandlerExecutor(mCallbackHandler),
                 (image, rotationDegrees) -> {
diff --git a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
index a37e865..f57ee37f 100644
--- a/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
+++ b/camera/camera-core/src/test/java/androidx/camera/core/ShadowCameraX.java
@@ -39,7 +39,7 @@
                                 @NonNull SessionConfig.Builder builder) {
                             // no op.
                         }
-                    }).build();
+                    }).getUseCaseConfig();
 
     private static final CameraInfo DEFAULT_CAMERA_INFO = new CameraInfoInternal() {
         MutableLiveData<Boolean> mFlashAvailability = new MutableLiveData<>(Boolean.TRUE);
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
index f62c775..30a4d3a 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ExtensionTest.java
@@ -141,7 +141,7 @@
         mInstrumentation.runOnMainSync(
                 () -> {
                     // To set the update listener and Preview will change to active state.
-                    preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+                    preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                             new PreviewSurfaceProviders.SurfaceTextureCallback() {
                                 @Override
                                 public void onSurfaceTextureReady(
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
index 4160d07..7d8d041 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/ImageCaptureExtenderTest.java
@@ -119,7 +119,7 @@
                         imageCaptureAdapter).setCaptureProcessor(
                         mock(CaptureProcessor.class));
 
-        ImageCapture useCase = new ImageCapture(configBuilder.build());
+        ImageCapture useCase = configBuilder.build();
 
         LensFacing lensFacing = CameraX.getDefaultLensFacing();
         CameraSelector cameraSelector = new CameraSelector.Builder()
@@ -177,7 +177,7 @@
         new Camera2Config.Extender(configBuilder).setCameraEventCallback(
                 new CameraEventCallbacks(imageCaptureAdapter));
 
-        ImageCapture useCase = new ImageCapture(configBuilder.build());
+        ImageCapture useCase = configBuilder.build();
 
         LensFacing lensFacing = CameraX.getDefaultLensFacing();
         CameraSelector cameraSelector = new CameraSelector.Builder()
@@ -242,14 +242,14 @@
                 mockImageCaptureExtenderImpl);
 
         // Checks the config does not include supported resolutions before applying effect mode.
-        assertThat(configBuilder.build().getSupportedResolutions(null)).isNull();
+        assertThat(configBuilder.getUseCaseConfig().getSupportedResolutions(null)).isNull();
 
         // Checks the config includes supported resolutions after applying effect mode.
         CameraSelector selector =
                 new CameraSelector.Builder().requireLensFacing(lensFacing).build();
         fakeExtender.enableExtension(selector);
         List<Pair<Integer, Size[]>> resultFormatResolutionsPairList =
-                configBuilder.build().getSupportedResolutions(null);
+                configBuilder.getUseCaseConfig().getSupportedResolutions(null);
         assertThat(resultFormatResolutionsPairList).isNotNull();
 
         // Checks the result and target pair lists are the same
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
index 32073df..7da28b3 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/PreviewExtenderTest.java
@@ -50,7 +50,6 @@
 import androidx.camera.core.CameraX;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.CaptureStageImpl;
@@ -139,7 +138,7 @@
         when(mockPreviewExtenderImpl.isExtensionAvailable(any(String.class),
                 any(CameraCharacteristics.class))).thenReturn(true);
 
-        PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+        Preview.Builder configBuilder = new Preview.Builder();
 
         FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
                 mockPreviewExtenderImpl);
@@ -147,12 +146,12 @@
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
         fakePreviewExtender.enableExtension(cameraSelector);
 
-        Preview useCase = new Preview(configBuilder.build());
+        Preview useCase = configBuilder.build();
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 // To set the update listener and Preview will change to active state.
-                useCase.setPreviewSurfaceCallback(
+                useCase.setPreviewSurfaceProvider(
                         createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
 
                 CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, useCase);
@@ -216,7 +215,7 @@
 
         when(mockPreviewExtenderImpl.getCaptureStage()).thenReturn(fakeCaptureStageImpl);
 
-        PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+        Preview.Builder configBuilder = new Preview.Builder();
 
         FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
                 mockPreviewExtenderImpl);
@@ -224,13 +223,13 @@
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
         fakePreviewExtender.enableExtension(cameraSelector);
 
-        Preview preview = new Preview(configBuilder.build());
+        Preview preview = configBuilder.build();
 
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 // To set the update listener and Preview will change to active state.
-                preview.setPreviewSurfaceCallback(
+                preview.setPreviewSurfaceProvider(
                         createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
 
                 CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, preview);
@@ -270,18 +269,18 @@
         when(mockPreviewExtenderImpl.isExtensionAvailable(any(String.class),
                 any(CameraCharacteristics.class))).thenReturn(true);
 
-        PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+        Preview.Builder configBuilder = new Preview.Builder();
         FakePreviewExtender fakePreviewExtender = new FakePreviewExtender(configBuilder,
                 mockPreviewExtenderImpl);
         CameraSelector cameraSelector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
         fakePreviewExtender.enableExtension(cameraSelector);
-        Preview preview = new Preview(configBuilder.build());
+        Preview preview = configBuilder.build();
         mInstrumentation.runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 // To set the update listener and Preview will change to active state.
-                preview.setPreviewSurfaceCallback(
+                preview.setPreviewSurfaceProvider(
                         createSurfaceTextureProvider(NO_OP_SURFACE_TEXTURE_CALLBACK));
 
                 CameraX.bindToLifecycle(mFakeLifecycle, cameraSelector, preview);
@@ -301,7 +300,7 @@
         assumeTrue(ExtensionVersion.getRuntimeVersion().compareTo(Version.VERSION_1_1) >= 0);
 
         LensFacing lensFacing = CameraX.getDefaultLensFacing();
-        PreviewConfig.Builder configBuilder = new PreviewConfig.Builder();
+        Preview.Builder configBuilder = new Preview.Builder();
 
         PreviewExtenderImpl mockPreviewExtenderImpl = mock(PreviewExtenderImpl.class);
         when(mockPreviewExtenderImpl.isExtensionAvailable(any(), any())).thenReturn(true);
@@ -317,14 +316,14 @@
                 mockPreviewExtenderImpl);
 
         // Checks the config does not include supported resolutions before applying effect mode.
-        assertThat(configBuilder.build().getSupportedResolutions(null)).isNull();
+        assertThat(configBuilder.getUseCaseConfig().getSupportedResolutions(null)).isNull();
 
         CameraSelector cameraSelector =
                 new CameraSelector.Builder().requireLensFacing(lensFacing).build();
         // Checks the config includes supported resolutions after applying effect mode.
         fakeExtender.enableExtension(cameraSelector);
         List<Pair<Integer, Size[]>> resultFormatResolutionsPairList =
-                configBuilder.build().getSupportedResolutions(null);
+                configBuilder.getUseCaseConfig().getSupportedResolutions(null);
         assertThat(resultFormatResolutionsPairList).isNotNull();
 
         // Checks the result and target pair lists are the same
@@ -368,7 +367,7 @@
     }
 
     private class FakePreviewExtender extends PreviewExtender {
-        FakePreviewExtender(PreviewConfig.Builder builder, PreviewExtenderImpl impl) {
+        FakePreviewExtender(Preview.Builder builder, PreviewExtenderImpl impl) {
             init(builder, impl, EffectMode.NORMAL);
         }
     }
diff --git a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
index 66f4610..fe3303d 100644
--- a/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
+++ b/camera/camera-extensions/src/androidTest/java/androidx/camera/extensions/util/ExtensionsTestUtil.java
@@ -153,18 +153,18 @@
     }
 
     /**
-     * Creates a {@link PreviewConfig.Builder} object for specific {@link EffectMode} and
+     * Creates a {@link Preview.Builder} object for specific {@link EffectMode} and
      * {@link LensFacing}.
      *
      * @param effectMode The effect mode for the created object.
      * @param lensFacing The lens facing for the created object.
-     * @return A {@link PreviewConfig.Builder} object.
+     * @return A {@link Preview.Builder} object.
      */
     @NonNull
-    public static PreviewConfig.Builder createPreviewConfigBuilderWithEffect(
+    public static Preview.Builder createPreviewBuilderWithEffect(
             @NonNull EffectMode effectMode,
             @NonNull LensFacing lensFacing) {
-        PreviewConfig.Builder builder = new PreviewConfig.Builder();
+        Preview.Builder builder = new Preview.Builder();
         CameraSelector selector =
                 new CameraSelector.Builder().requireLensFacing(lensFacing).build();
         PreviewExtender extender = null;
@@ -211,9 +211,7 @@
             @NonNull LensFacing lensFacing) {
         ImageCaptureConfig.Builder imageCaptureConfigBuilder =
                 createImageCaptureConfigBuilderWithEffect(effectMode, lensFacing);
-        ImageCaptureConfig imageCaptureConfig = imageCaptureConfigBuilder.build();
-
-        return imageCaptureConfig;
+        return imageCaptureConfigBuilder.getUseCaseConfig();
     }
 
     /**
@@ -227,11 +225,9 @@
     @NonNull
     public static PreviewConfig createPreviewConfigWithEffect(@NonNull EffectMode effectMode,
             @NonNull LensFacing lensFacing) {
-        PreviewConfig.Builder previewConfigBuilder =
-                createPreviewConfigBuilderWithEffect(effectMode, lensFacing);
-        PreviewConfig previewConfig = previewConfigBuilder.build();
-
-        return previewConfig;
+        Preview.Builder previewBuilder =
+                createPreviewBuilderWithEffect(effectMode, lensFacing);
+        return previewBuilder.getUseCaseConfig();
     }
 
     /**
@@ -247,9 +243,7 @@
             @NonNull LensFacing lensFacing) {
         ImageCaptureConfig imageCaptureConfig = createImageCaptureConfigWithEffect(effectMode,
                 lensFacing);
-        ImageCapture imageCapture = new ImageCapture(imageCaptureConfig);
-
-        return imageCapture;
+        return new ImageCapture(imageCaptureConfig);
     }
 
     /**
@@ -262,10 +256,7 @@
     @NonNull
     public static Preview createPreviewWithEffect(@NonNull EffectMode effectMode,
             @NonNull LensFacing lensFacing) {
-        PreviewConfig previewConfig = createPreviewConfigWithEffect(effectMode, lensFacing);
-        Preview preview = new Preview(previewConfig);
-
-        return preview;
+        return createPreviewBuilderWithEffect(effectMode, lensFacing).build();
     }
 
     /**
@@ -368,7 +359,7 @@
      * {@link ImageCaptureConfig.Builder}.
      *
      * @param effectMode The effect mode for the created object.
-     * @param builder The {@link ImageCaptureConfig.Builder} for the created object.
+     * @param builder    The {@link ImageCaptureConfig.Builder} for the created object.
      * @return An {@link ImageCaptureExtender} object.
      */
     @NonNull
@@ -400,15 +391,15 @@
 
     /**
      * Creates a {@link PreviewExtender} object for specific {@link EffectMode} and
-     * {@link PreviewConfig.Builder}.
+     * {@link Preview.Builder}.
      *
      * @param effectMode The effect mode for the created object.
-     * @param builder The {@link PreviewConfig.Builder} for the created object.
+     * @param builder    The {@link Preview.Builder} for the created object.
      * @return A {@link PreviewExtender} object.
      */
     @NonNull
     public static PreviewExtender createPreviewExtender(@NonNull EffectMode effectMode,
-            @NonNull PreviewConfig.Builder builder) {
+            @NonNull Preview.Builder builder) {
         PreviewExtender extender = null;
 
         switch (effectMode) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
index 7dd9894..6ec296b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/AutoPreviewExtender.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
 
@@ -34,9 +34,9 @@
      * Create a new instance of the auto extender.
      *
      * @param builder Builder that will be used to create the configurations for the
-     * {@link androidx.camera.core.Preview}.
+     *                {@link androidx.camera.core.Preview}.
      */
-    public static AutoPreviewExtender create(PreviewConfig.Builder builder) {
+    public static AutoPreviewExtender create(Preview.Builder builder) {
         if (ExtensionVersion.isExtensionVersionSupported()) {
             try {
                 return new VendorAutoPreviewExtender(builder);
@@ -67,11 +67,12 @@
     static class VendorAutoPreviewExtender extends AutoPreviewExtender {
         private final AutoPreviewExtenderImpl mImpl;
 
-        VendorAutoPreviewExtender(PreviewConfig.Builder builder) {
+        VendorAutoPreviewExtender(Preview.Builder builder) {
             mImpl = new AutoPreviewExtenderImpl();
             init(builder, mImpl, EffectMode.AUTO);
         }
     }
 
-    private AutoPreviewExtender() {}
+    private AutoPreviewExtender() {
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
index ab5323a..dcaff72 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BeautyPreviewExtender.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.BeautyPreviewExtenderImpl;
 
@@ -34,9 +34,9 @@
      * Create a new instance of the beauty extender.
      *
      * @param builder Builder that will be used to create the configurations for the
-     * {@link androidx.camera.core.Preview}.
+     *                {@link androidx.camera.core.Preview}.
      */
-    public static BeautyPreviewExtender create(PreviewConfig.Builder builder) {
+    public static BeautyPreviewExtender create(Preview.Builder builder) {
         if (ExtensionVersion.isExtensionVersionSupported()) {
             try {
                 return new VendorBeautyPreviewExtender(builder);
@@ -67,11 +67,12 @@
     static class VendorBeautyPreviewExtender extends BeautyPreviewExtender {
         private final BeautyPreviewExtenderImpl mImpl;
 
-        VendorBeautyPreviewExtender(PreviewConfig.Builder builder) {
+        VendorBeautyPreviewExtender(Preview.Builder builder) {
             mImpl = new BeautyPreviewExtenderImpl();
             init(builder, mImpl, EffectMode.BEAUTY);
         }
     }
 
-    private BeautyPreviewExtender() {}
+    private BeautyPreviewExtender() {
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
index 26f6892..ccf88a0 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/BokehPreviewExtender.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.BokehPreviewExtenderImpl;
 
@@ -34,9 +34,9 @@
      * Create a new instance of the bokeh extender.
      *
      * @param builder Builder that will be used to create the configurations for the
-     * {@link androidx.camera.core.Preview}.
+     *                {@link androidx.camera.core.Preview}.
      */
-    public static BokehPreviewExtender create(PreviewConfig.Builder builder) {
+    public static BokehPreviewExtender create(Preview.Builder builder) {
         if (ExtensionVersion.isExtensionVersionSupported()) {
             try {
                 return new VendorBokehPreviewExtender(builder);
@@ -67,11 +67,12 @@
     private static class VendorBokehPreviewExtender extends BokehPreviewExtender {
         private final BokehPreviewExtenderImpl mImpl;
 
-        VendorBokehPreviewExtender(PreviewConfig.Builder builder) {
+        VendorBokehPreviewExtender(Preview.Builder builder) {
             mImpl = new BokehPreviewExtenderImpl();
             init(builder, mImpl, EffectMode.BOKEH);
         }
     }
 
-    private BokehPreviewExtender() {}
+    private BokehPreviewExtender() {
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
index 1179b41..e8be743 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ExtensionsManager.java
@@ -28,7 +28,6 @@
 import androidx.camera.core.ImageCaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.core.impl.utils.futures.Futures;
 import androidx.camera.extensions.impl.InitializerImpl;
@@ -246,7 +245,7 @@
 
     private static boolean checkPreviewExtensionCapability(EffectMode effectMode,
             LensFacing lensFacing) {
-        PreviewConfig.Builder builder = new PreviewConfig.Builder();
+        Preview.Builder builder = new Preview.Builder();
         CameraSelector cameraSelector =
                 new CameraSelector.Builder().requireLensFacing(lensFacing).build();
         PreviewExtender extender;
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
index 7bd20a4..cf5be4d 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/HdrPreviewExtender.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.HdrPreviewExtenderImpl;
 
@@ -34,9 +34,9 @@
      * Create a new instance of the HDR extender.
      *
      * @param builder Builder that will be used to create the configurations for the
-     * {@link androidx.camera.core.Preview}.
+     *                {@link androidx.camera.core.Preview}.
      */
-    public static HdrPreviewExtender create(PreviewConfig.Builder builder) {
+    public static HdrPreviewExtender create(Preview.Builder builder) {
         if (ExtensionVersion.isExtensionVersionSupported()) {
             try {
                 return new VendorHdrPreviewExtender(builder);
@@ -67,11 +67,12 @@
     static class VendorHdrPreviewExtender extends HdrPreviewExtender {
         private final HdrPreviewExtenderImpl mImpl;
 
-        VendorHdrPreviewExtender(PreviewConfig.Builder builder) {
+        VendorHdrPreviewExtender(Preview.Builder builder) {
             mImpl = new HdrPreviewExtenderImpl();
             init(builder, mImpl, EffectMode.HDR);
         }
     }
 
-    private HdrPreviewExtender() {}
+    private HdrPreviewExtender() {
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
index dbf36f6..4c9bc4c3 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/ImageCaptureExtender.java
@@ -107,7 +107,7 @@
     public void enableExtension(@NonNull CameraSelector cameraSelector) {
         // Add extension camera id filter to config.
         ExtensionCameraIdFilter extensionCameraIdFilter = new ExtensionCameraIdFilter(mImpl);
-        CameraIdFilter currentCameraIdFilter = mBuilder.build().getCameraIdFilter(null);
+        CameraIdFilter currentCameraIdFilter = mBuilder.getUseCaseConfig().getCameraIdFilter(null);
         CameraSelector.Builder selectorBuilder =
                 CameraSelector.Builder.fromSelector(cameraSelector);
         if (currentCameraIdFilter == null) {
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
index 166710f..4e5210b 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/NightPreviewExtender.java
@@ -20,7 +20,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.camera.core.CameraSelector;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.extensions.ExtensionsManager.EffectMode;
 import androidx.camera.extensions.impl.NightPreviewExtenderImpl;
 
@@ -34,9 +34,9 @@
      * Create a new instance of the night extender.
      *
      * @param builder Builder that will be used to create the configurations for the
-     * {@link androidx.camera.core.Preview}.
+     *                {@link androidx.camera.core.Preview}.
      */
-    public static NightPreviewExtender create(PreviewConfig.Builder builder) {
+    public static NightPreviewExtender create(Preview.Builder builder) {
         if (ExtensionVersion.isExtensionVersionSupported()) {
             try {
                 return new VendorNightPreviewExtender(builder);
@@ -67,11 +67,12 @@
     static class VendorNightPreviewExtender extends NightPreviewExtender {
         private final NightPreviewExtenderImpl mImpl;
 
-        VendorNightPreviewExtender(PreviewConfig.Builder builder) {
+        VendorNightPreviewExtender(Preview.Builder builder) {
             mImpl = new NightPreviewExtenderImpl();
             init(builder, mImpl, EffectMode.NIGHT);
         }
     }
 
-    private NightPreviewExtender() {}
+    private NightPreviewExtender() {
+    }
 }
diff --git a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
index 7851202..c1e834a 100644
--- a/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
+++ b/camera/camera-extensions/src/main/java/androidx/camera/extensions/PreviewExtender.java
@@ -35,7 +35,7 @@
 import androidx.camera.core.CaptureConfig;
 import androidx.camera.core.Config;
 import androidx.camera.core.LensFacing;
-import androidx.camera.core.PreviewConfig;
+import androidx.camera.core.Preview;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.impl.utils.CameraSelectorUtil;
 import androidx.camera.extensions.ExtensionsErrorListener.ExtensionsErrorCode;
@@ -56,11 +56,11 @@
     static final Config.Option<EffectMode> OPTION_PREVIEW_EXTENDER_MODE = Config.Option.create(
             "camerax.extensions.previewExtender.mode", EffectMode.class);
 
-    private PreviewConfig.Builder mBuilder;
+    private Preview.Builder mBuilder;
     PreviewExtenderImpl mImpl;
     private EffectMode mEffectMode;
 
-    void init(PreviewConfig.Builder builder, PreviewExtenderImpl implementation,
+    void init(Preview.Builder builder, PreviewExtenderImpl implementation,
             EffectMode effectMode) {
         mBuilder = builder;
         mImpl = implementation;
@@ -68,12 +68,10 @@
     }
 
     /**
-     * Indicates whether extension function can support with
-     * {@link PreviewConfig.Builder}
+     * Indicates whether extension function can support with {@link Preview.Builder}.
      *
      * @param cameraSelector The selector that determines a camera that will be checked for the
      *                       availability of extensions.
-     *
      * @return True if the specific extension function is supported for the camera device.
      */
     public boolean isExtensionAvailable(@NonNull CameraSelector cameraSelector) {
@@ -104,7 +102,7 @@
     public void enableExtension(@NonNull CameraSelector cameraSelector) {
         // Add extension camera id filter to config.
         ExtensionCameraIdFilter extensionCameraIdFilter = new ExtensionCameraIdFilter(mImpl);
-        CameraIdFilter currentCameraIdFilter = mBuilder.build().getCameraIdFilter(null);
+        CameraIdFilter currentCameraIdFilter = mBuilder.getUseCaseConfig().getCameraIdFilter(null);
         CameraSelector.Builder selectorBuilder =
                 CameraSelector.Builder.fromSelector(cameraSelector);
         if (currentCameraIdFilter == null) {
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
index a1314daa..e6d9107 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/activity/CameraXTestActivity.java
@@ -89,14 +89,11 @@
             }
         }
 
-        PreviewConfig config =
-                new PreviewConfig.Builder()
-                        .setTargetName("Preview")
-                        .build();
-
-        mPreview = new Preview(config);
+        mPreview = new Preview.Builder()
+                .setTargetName("Preview")
+                .build();
         TextureView textureView = findViewById(R.id.textureView);
-        mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+        mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                 new PreviewSurfaceProviders.SurfaceTextureCallback() {
                     @Override
                     public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -128,6 +125,7 @@
                     CameraX.getCameraWithCameraDeviceConfig(
                             CameraSelectorUtil.toCameraDeviceConfig(cameraSelector));
         } catch (CameraInfoUnavailableException e) {
+            final PreviewConfig config = (PreviewConfig) mPreview.getUseCaseConfig();
             throw new IllegalArgumentException(
                     "Unable to get camera id for the camera device config "
                             + config.getLensFacing(), e);
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
index 62cb9cf..2e49159 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCase.java
@@ -43,7 +43,7 @@
      * Creates a new instance of a {@link FakeUseCase} with a default configuration.
      */
     public FakeUseCase() {
-        this(new FakeUseCaseConfig.Builder().build());
+        this(new FakeUseCaseConfig.Builder().getUseCaseConfig());
     }
 
     @Override
diff --git a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
index e27a164..e55dd98 100644
--- a/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
+++ b/camera/camera-testing/src/main/java/androidx/camera/testing/fakes/FakeUseCaseConfig.java
@@ -235,10 +235,16 @@
             return mOptionsBundle;
         }
 
+        @NonNull
+        @Override
+        public FakeUseCaseConfig getUseCaseConfig() {
+            return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+        }
+
         @Override
         @NonNull
-        public FakeUseCaseConfig build() {
-            return new FakeUseCaseConfig(OptionsBundle.from(mOptionsBundle));
+        public FakeUseCase build() {
+            return new FakeUseCase(getUseCaseConfig());
         }
 
         // Implementations of TargetConfig.Builder default methods
diff --git a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
index 6f8247a..5ac77f3 100644
--- a/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
+++ b/camera/camera-view/src/androidTest/java/androidx/camera/view/TextureViewMeteringPointFactoryTest.java
@@ -42,7 +42,6 @@
 import androidx.camera.core.MeteringPoint;
 import androidx.camera.core.MeteringPointFactory;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.testing.CameraUtil;
 import androidx.camera.testing.CoreAppTestUtil;
@@ -200,11 +199,9 @@
     }
 
     private void startAndWaitForCameraReady(LensFacing lensFacing) throws InterruptedException {
-        PreviewConfig.Builder previewConfigBuilder = new PreviewConfig.Builder();
-
-        Preview preview = new Preview(previewConfigBuilder.build());
+        Preview preview = new Preview.Builder().build();
         mInstrumentation.runOnMainSync(() -> {
-            preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+            preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                     new PreviewSurfaceProviders.SurfaceTextureCallback() {
                         @Override
                         public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java b/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
index c31fafe..b097500 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/CameraXModule.java
@@ -43,7 +43,6 @@
 import androidx.camera.core.ImageCaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.VideoCapture;
 import androidx.camera.core.VideoCapture.OnVideoSavedCallback;
 import androidx.camera.core.VideoCaptureConfig;
@@ -61,11 +60,8 @@
 
 import java.io.File;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.LinkedHashSet;
-import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicBoolean;
 
@@ -81,7 +77,7 @@
     private static final Rational ASPECT_RATIO_9_16 = new Rational(9, 16);
     private static final Rational ASPECT_RATIO_3_4 = new Rational(3, 4);
 
-    private final PreviewConfig.Builder mPreviewConfigBuilder;
+    private final Preview.Builder mPreviewBuilder;
     private final VideoCaptureConfig.Builder mVideoCaptureConfigBuilder;
     private final ImageCaptureConfig.Builder mImageCaptureConfigBuilder;
     private final CameraView mCameraView;
@@ -111,7 +107,7 @@
                 public void onDestroy(LifecycleOwner owner) {
                     if (owner == mCurrentLifecycle) {
                         clearCurrentLifecycle();
-                        mPreview.setPreviewSurfaceCallback(null);
+                        mPreview.setPreviewSurfaceProvider(null);
                     }
                 }
             };
@@ -123,7 +119,7 @@
     CameraXModule(CameraView view) {
         this.mCameraView = view;
 
-        mPreviewConfigBuilder = new PreviewConfig.Builder().setTargetName("Preview");
+        mPreviewBuilder = new Preview.Builder().setTargetName("Preview");
 
         mImageCaptureConfigBuilder =
                 new ImageCaptureConfig.Builder().setTargetName("ImageCapture");
@@ -202,52 +198,33 @@
         }
 
         mImageCaptureConfigBuilder.setTargetRotation(getDisplaySurfaceRotation());
-        mImageCapture = new ImageCapture(mImageCaptureConfigBuilder.build());
+        mImageCapture = mImageCaptureConfigBuilder.build();
 
         mVideoCaptureConfigBuilder.setTargetRotation(getDisplaySurfaceRotation());
-        mVideoCapture = new VideoCapture(mVideoCaptureConfigBuilder.build());
+        mVideoCapture = mVideoCaptureConfigBuilder.build();
 
         // Adjusts the preview resolution according to the view size and the target aspect ratio.
         int height = (int) (getMeasuredWidth() / targetAspectRatio.floatValue());
-        mPreviewConfigBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
+        mPreviewBuilder.setTargetResolution(new Size(getMeasuredWidth(), height));
 
-        mPreview = new Preview(mPreviewConfigBuilder.build());
-        mPreview.setPreviewSurfaceCallback(new Preview.PreviewSurfaceCallback() {
-            // Thread safe because it only accessed on the default executor, which is UI thread.
-            Map<Surface, SurfaceTexture> mSurfaceTextureMap = new HashMap<>();
-
-            @NonNull
-            @Override
-            public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
-                // The PreviewSurfaceCallback#createSurfaceFuture() might come asynchronously.
+        mPreview = mPreviewBuilder.build();
+        mPreview.setPreviewSurfaceProvider((resolution, safeToCancelFuture) -> {
+                // The PreviewSurfaceProvider#createSurfaceFuture() might come asynchronously.
                 // It cannot guarantee the callback time, so we store the resolution result in
                 // the listenableFuture.
                 mResolutionUpdateCompleter.set(resolution);
-                // Create SurfaceTexture and Surface.
-                SurfaceTexture surfaceTexture = new SurfaceTexture(0);
-                surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
-                        resolution.getHeight());
-                surfaceTexture.detachFromGLContext();
-                CameraXModule.this.setSurfaceTexture(surfaceTexture);
-                Surface surface = new Surface(surfaceTexture);
-                mSurfaceTextureMap.put(surface, surfaceTexture);
-                return Futures.immediateFuture(surface);
-            }
-
-            @Override
-            public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
-                try {
-                    Surface surface = surfaceFuture.get();
-                    surface.release();
-                    SurfaceTexture surfaceTexture = mSurfaceTextureMap.get(surface);
-                    if (surfaceTexture != null) {
-                        surfaceTexture.release();
-                        mSurfaceTextureMap.remove(surface);
-                    }
-                } catch (ExecutionException | InterruptedException e) {
-                    Log.e(TAG, "Failed to release Surface", e);
-                }
-            }
+            // Create SurfaceTexture and Surface.
+            SurfaceTexture surfaceTexture = new SurfaceTexture(0);
+            surfaceTexture.setDefaultBufferSize(resolution.getWidth(),
+                    resolution.getHeight());
+            surfaceTexture.detachFromGLContext();
+            CameraXModule.this.setSurfaceTexture(surfaceTexture);
+            Surface surface = new Surface(surfaceTexture);
+            safeToCancelFuture.addListener(() -> {
+                surface.release();
+                surfaceTexture.release();
+            }, CameraXExecutors.directExecutor());
+            return Futures.immediateFuture(surface);
         });
 
         CameraSelector cameraSelector =
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
index 4e2beba..aaee145 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/PreviewView.java
@@ -116,12 +116,12 @@
     }
 
     /**
-     * Gets the {@link Preview.PreviewSurfaceCallback} to be used with
-     * {@link Preview#setPreviewSurfaceCallback(Executor, Preview.PreviewSurfaceCallback)}.
+     * Gets the {@link Preview.PreviewSurfaceProvider} to be used with
+     * {@link Preview#setPreviewSurfaceProvider(Executor, Preview.PreviewSurfaceProvider)}.
      */
     @NonNull
-    public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
-        return mImplementation.getPreviewSurfaceCallback();
+    public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
+        return mImplementation.getPreviewSurfaceProvider();
     }
 
     /**
@@ -137,10 +137,10 @@
         void init(@NonNull FrameLayout parent);
 
         /**
-         * Gets the {@link Preview.PreviewSurfaceCallback} to be used with {@link Preview}.
+         * Gets the {@link Preview.PreviewSurfaceProvider} to be used with {@link Preview}.
          */
         @NonNull
-        Preview.PreviewSurfaceCallback getPreviewSurfaceCallback();
+        Preview.PreviewSurfaceProvider getPreviewSurfaceProvider();
     }
 
     /**
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
index d948fa2..dc33f64 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/SurfaceViewImplementation.java
@@ -46,11 +46,14 @@
     final CompleterWithSizeCallback mCompleterWithSizeCallback =
             new CompleterWithSizeCallback();
 
-    private Preview.PreviewSurfaceCallback mPreviewSurfaceCallback =
-            new Preview.PreviewSurfaceCallback() {
+    private Preview.PreviewSurfaceProvider mPreviewSurfaceProvider =
+            new Preview.PreviewSurfaceProvider() {
                 @NonNull
                 @Override
-                public ListenableFuture<Surface> createSurfaceFuture(@NonNull Size resolution) {
+                public ListenableFuture<Surface> provideSurface(@NonNull Size resolution,
+                        @NonNull ListenableFuture<Void> surfaceReleaseFuture) {
+                    // No-op on surfaceReleaseFuture because the Surface will be destroyed by
+                    // SurfaceView.
                     return CallbackToFutureAdapter.getFuture(
                             completer -> {
                                 // Post to UI thread for thread safety.
@@ -60,11 +63,6 @@
                                 return "SurfaceViewSurfaceCreation";
                             });
                 }
-
-                @Override
-                public void onSafeToRelease(@NonNull ListenableFuture<Surface> surfaceFuture) {
-                    // No-op. The Surface will be released by SurfaceView when it's done.
-                }
             };
 
     /**
@@ -86,8 +84,8 @@
      */
     @NonNull
     @Override
-    public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
-        return mPreviewSurfaceCallback;
+    public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
+        return mPreviewSurfaceProvider;
     }
 
     /**
diff --git a/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java b/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
index 429b5bd..9118358 100644
--- a/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
+++ b/camera/camera-view/src/main/java/androidx/camera/view/TextureViewImplementation.java
@@ -54,7 +54,7 @@
 
     @NonNull
     @Override
-    public Preview.PreviewSurfaceCallback getPreviewSurfaceCallback() {
+    public Preview.PreviewSurfaceProvider getPreviewSurfaceProvider() {
         return createSurfaceTextureProvider(new PreviewSurfaceProviders.SurfaceTextureCallback() {
             @Override
             public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
diff --git a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
index 0a738d0..083178b 100644
--- a/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
+++ b/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/CameraXActivity.java
@@ -16,8 +16,6 @@
 
 package androidx.camera.integration.core;
 
-import static androidx.camera.core.PreviewSurfaceProviders.createSurfaceTextureProvider;
-
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -32,14 +30,13 @@
 import android.util.Size;
 import android.view.Surface;
 import android.view.TextureView;
-import android.view.TextureView.SurfaceTextureListener;
 import android.view.View;
-import android.view.ViewGroup;
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.TextView;
 import android.widget.Toast;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
@@ -53,13 +50,12 @@
 import androidx.camera.core.ImageCaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
-import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.VideoCapture;
 import androidx.camera.core.VideoCaptureConfig;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
 import androidx.camera.lifecycle.LifecycleCameraProvider;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
 import androidx.core.app.ActivityCompat;
 import androidx.core.content.ContextCompat;
 import androidx.lifecycle.LiveData;
@@ -68,6 +64,8 @@
 import androidx.test.espresso.IdlingResource;
 import androidx.test.espresso.idling.CountingIdlingResource;
 
+import com.google.common.util.concurrent.ListenableFuture;
+
 import java.io.File;
 import java.math.BigDecimal;
 import java.text.Format;
@@ -75,6 +73,7 @@
 import java.util.Calendar;
 import java.util.concurrent.Callable;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
@@ -119,30 +118,6 @@
     // Synthetic Accessor
     @SuppressWarnings("WeakerAccess")
     TextureView mTextureView;
-    private final SurfaceTextureListener mSurfaceTextureListener = new SurfaceTextureListener() {
-        @Override
-        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
-
-        }
-
-        @Override
-        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
-
-        }
-
-        @Override
-        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
-            return false;
-        }
-
-        @Override
-        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
-            // Wait until surface texture receives enough updates.
-            if (!mViewIdlingResource.isIdleNow()) {
-                mViewIdlingResource.decrement();
-            }
-        }
-    };
 
     // Espresso testing variables
     @VisibleForTesting
@@ -190,8 +165,7 @@
                         } else {
                             // Add the use case
                             buttonView.setBackgroundColor(Color.LTGRAY);
-
-                            CameraXActivity.this.enablePreview();
+                            enablePreview();
                         }
                     }
                 });
@@ -200,34 +174,20 @@
     }
 
     void enablePreview() {
-        PreviewConfig config =
-                new PreviewConfig.Builder()
-                        .setTargetName("Preview")
-                        .build();
-
-        mPreview = new Preview(config);
+        mPreview = new Preview.Builder()
+                .setTargetName("Preview")
+                .build();
         Log.d(TAG, "enablePreview");
-        mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
-                new PreviewSurfaceProviders.SurfaceTextureCallback() {
-                    @Override
-                    public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
-                            @NonNull Size resolution) {
-                        Log.d(TAG, "onSurfaceTextureReady");
-                        // If TextureView was already created, need to re-add it to change the
-                        // SurfaceTexture.
-                        ViewGroup viewGroup = (ViewGroup) mTextureView.getParent();
-                        viewGroup.removeView(mTextureView);
-                        viewGroup.addView(mTextureView);
-                        mTextureView.setSurfaceTexture(surfaceTexture);
-                        transformPreview(resolution);
-                    }
 
-                    @Override
-                    public void onSafeToRelease(@NonNull SurfaceTexture surfaceTexture) {
-                        Log.d(TAG, "onSafeToRelease");
-                        surfaceTexture.release();
-                    }
-                }));
+        mPreview.setPreviewSurfaceProvider(
+                (resolution, surfaceReleaseFuture) -> CallbackToFutureAdapter.getFuture(
+                        completer -> {
+                            ((PreviewSurfaceTextureListener) mTextureView
+                                    .getSurfaceTextureListener())
+                                    .setSurfaceFutureCompleter(completer,
+                                            resolution, surfaceReleaseFuture);
+                            return "PreviewSurfaceCreation";
+                        }));
 
         for (int i = 0; i < FRAMES_UNTIL_VIEW_IS_READY; i++) {
             mViewIdlingResource.increment();
@@ -383,12 +343,9 @@
     }
 
     void enableImageAnalysis() {
-        ImageAnalysisConfig config =
-                new ImageAnalysisConfig.Builder()
-                        .setTargetName("ImageAnalysis")
-                        .build();
-
-        mImageAnalysis = new ImageAnalysis(config);
+        mImageAnalysis = new ImageAnalysisConfig.Builder()
+                .setTargetName("ImageAnalysis")
+                .build();
         TextView textView = this.findViewById(R.id.textView);
         mAnalysisIdlingResource.increment();
 
@@ -459,13 +416,10 @@
     }
 
     void enableImageCapture() {
-        ImageCaptureConfig config =
-                new ImageCaptureConfig.Builder()
-                        .setCaptureMode(mCaptureMode)
-                        .setTargetName("ImageCapture")
-                        .build();
-
-        mImageCapture = new ImageCapture(config);
+        mImageCapture = new ImageCaptureConfig.Builder()
+                .setCaptureMode(mCaptureMode)
+                .setTargetName("ImageCapture")
+                .build();
 
         Camera camera = bindToLifecycleSafely(mImageCapture, R.id.PhotoToggle);
         if (camera == null) {
@@ -641,12 +595,9 @@
     }
 
     void enableVideoCapture() {
-        VideoCaptureConfig config =
-                new VideoCaptureConfig.Builder()
-                        .setTargetName("VideoCapture")
-                        .build();
-
-        mVideoCapture = new VideoCapture(config);
+        mVideoCapture = new VideoCaptureConfig.Builder()
+                .setTargetName("VideoCapture")
+                .build();
 
         if (bindToLifecycleSafely(mVideoCapture, R.id.VideoToggle) == null) {
             Button button = this.findViewById(R.id.Video);
@@ -702,7 +653,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_camera_xmain);
         mTextureView = findViewById(R.id.textureView);
-        mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+        mTextureView.setSurfaceTextureListener(new PreviewSurfaceTextureListener());
 
         StrictMode.VmPolicy policy =
                 new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build();
@@ -919,4 +870,112 @@
     VideoCapture getVideoCapture() {
         return mVideoCapture;
     }
+
+    /**
+     * Manages the life cycle of the {@link TextureView} {@link SurfaceTexture} for {@link Preview}
+     * use cases.
+     *
+     * This class is responsible for resolving two race conditions: the creation
+     * and the destroy of the {@link Surface}/{@link SurfaceTexture} pair.
+     */
+    final class PreviewSurfaceTextureListener implements
+            TextureView.SurfaceTextureListener {
+
+        @GuardedBy("this")
+        CallbackToFutureAdapter.Completer<Surface> mSurfaceCompleter;
+        @GuardedBy("this")
+        Size mResolution;
+        @GuardedBy("this")
+        SurfaceTexture mSurfaceTexture;
+        @GuardedBy("this")
+        ListenableFuture<Void> mSurfaceSafeToReleaseFuture;
+
+        // Whether the handle is still being used by the consumer(TextureView).
+        AtomicBoolean mIsSurfaceTextureUsedByTextureView = new AtomicBoolean(true);
+        // Whether the handle is still being used by the producer(CameraX).
+        AtomicBoolean mIsSurfaceTextureUsedByPreview = new AtomicBoolean(false);
+
+        /**
+         * Resolves the race condition in {@link SurfaceTexture} creation.
+         */
+        private synchronized void tryToSetSurface() {
+            if (mResolution != null && mSurfaceTexture != null && mSurfaceCompleter != null) {
+                Log.d(TAG, "SurfaceTexture set " + hashCode());
+                // Only set Surface when both the consumer and the producer are ready.
+                mSurfaceTexture.setDefaultBufferSize(mResolution.getWidth(),
+                        mResolution.getHeight());
+                final Surface surface = new Surface(mSurfaceTexture);
+                mSurfaceCompleter.set(surface);
+                mIsSurfaceTextureUsedByPreview.set(true);
+
+                mSurfaceSafeToReleaseFuture.addListener(() -> {
+                    Log.d(TAG, "Preview is ready to release Surface." + hashCode());
+                    surface.release();
+                    mIsSurfaceTextureUsedByPreview.set(false);
+                    tryToReleaseSurfaceTexture();
+                }, ContextCompat.getMainExecutor(CameraXActivity.this));
+            }
+        }
+
+        /**
+         * Resolves the race condition in {@link SurfaceTexture} releasing.
+         */
+        private synchronized void tryToReleaseSurfaceTexture() {
+            if (!mIsSurfaceTextureUsedByTextureView.get()
+                    && !mIsSurfaceTextureUsedByPreview.get()
+                    && mSurfaceTexture != null) {
+                Log.d(TAG, "SurfaceTexture released " + hashCode());
+                // Only release when both the consumer and the producer are done.
+                mSurfaceTexture.release();
+                mSurfaceTexture = null;
+            }
+        }
+
+        synchronized void setSurfaceFutureCompleter(
+                CallbackToFutureAdapter.Completer<Surface> surfaceCompleter,
+                Size resolution,
+                ListenableFuture<Void> surfaceSafeToReleaseFuture) {
+            Log.d(TAG, "SurfaceCompleter set. " + hashCode());
+            mSurfaceCompleter = surfaceCompleter;
+            mResolution = resolution;
+            mSurfaceSafeToReleaseFuture = surfaceSafeToReleaseFuture;
+            transformPreview(resolution);
+            tryToSetSurface();
+        }
+
+        @Override
+        public synchronized void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width,
+                int height) {
+            Log.d(TAG, "TextureView is ready to set SurfaceTexture. " + hashCode());
+            mSurfaceTexture = surfaceTexture;
+            mIsSurfaceTextureUsedByTextureView.set(true);
+            tryToSetSurface();
+        }
+
+        @Override
+        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width,
+                int height) {
+            Log.d(TAG, "onSurfaceTextureSizeChanged " + width + "x" + height);
+            // No-op.
+        }
+
+        @Override
+        public synchronized boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
+            Log.d(TAG, "TextureView is ready to release SurfaceTexture. " + hashCode());
+            mIsSurfaceTextureUsedByTextureView.set(false);
+            ContextCompat.getMainExecutor(CameraXActivity.this).execute(
+                    this::tryToReleaseSurfaceTexture);
+            // Never auto release. Premature releasing causes CaptureSession to misbehave on LEGACY
+            // devices. Wait for CameraX's signal to release it.
+            return false;
+        }
+
+        @Override
+        public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+            // Wait until surface texture receives enough updates. This is for testing.
+            if (!mViewIdlingResource.isIdleNow()) {
+                mViewIdlingResource.decrement();
+            }
+        }
+    }
 }
diff --git a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
index d501648..dbc9f23 100644
--- a/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
+++ b/camera/integration-tests/extensionstestapp/src/androidTest/java/androidx/camera/integration/extensions/PreviewProcessorTimestampTest.java
@@ -109,7 +109,7 @@
     SurfaceTexture.OnFrameAvailableListener mOnFrameAvailableListener;
 
     private ImageCaptureConfig.Builder mImageCaptureConfigBuilder;
-    private PreviewConfig.Builder mPreviewConfigBuilder;
+    private Preview.Builder mPreviewBuilder;
     private ImageAnalysisConfig.Builder mImageAnalysisConfigBuilder;
 
     @Parameterized.Parameters
@@ -147,7 +147,7 @@
         mLifecycleOwner = new FakeLifecycleOwner();
 
         mImageCaptureConfigBuilder = new ImageCaptureConfig.Builder();
-        mPreviewConfigBuilder = new PreviewConfig.Builder();
+        mPreviewBuilder = new Preview.Builder();
         mImageAnalysisConfigBuilder = new ImageAnalysisConfig.Builder();
         mCameraStatusCallback = new CameraDevice.StateCallback() {
             @Override
@@ -237,19 +237,18 @@
         enableExtension(mEffectMode, mLensFacing);
 
         // To test bind/unbind and take picture.
-        ImageCapture imageCapture = new ImageCapture(mImageCaptureConfigBuilder.build());
+        ImageCapture imageCapture = mImageCaptureConfigBuilder.build();
 
-        PreviewConfig previewConfig = mPreviewConfigBuilder
-                .build();
+        PreviewConfig previewConfig = mPreviewBuilder.getUseCaseConfig();
         CaptureProcessor previewCaptureProcessor = previewConfig.getCaptureProcessor(null);
         assumeNotNull(previewCaptureProcessor);
-        mPreviewConfigBuilder.setCaptureProcessor(
+        mPreviewBuilder.setCaptureProcessor(
                 new TimestampCaptureProcessor(previewCaptureProcessor, mTimestampListener));
 
-        Preview preview = new Preview(mPreviewConfigBuilder.build());
+        Preview preview = mPreviewBuilder.build();
 
         // To set the update listener and Preview will change to active state.
-        preview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+        preview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                 new PreviewSurfaceProviders.SurfaceTextureCallback() {
                     @Override
                     public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -296,25 +295,25 @@
         switch (effectMode) {
             case HDR:
                 imageCaptureExtender = HdrImageCaptureExtender.create(mImageCaptureConfigBuilder);
-                previewExtender = HdrPreviewExtender.create(mPreviewConfigBuilder);
+                previewExtender = HdrPreviewExtender.create(mPreviewBuilder);
                 break;
             case BOKEH:
                 imageCaptureExtender = BokehImageCaptureExtender.create(
                         mImageCaptureConfigBuilder);
-                previewExtender = BokehPreviewExtender.create(mPreviewConfigBuilder);
+                previewExtender = BokehPreviewExtender.create(mPreviewBuilder);
                 break;
             case BEAUTY:
                 imageCaptureExtender = BeautyImageCaptureExtender.create(
                         mImageCaptureConfigBuilder);
-                previewExtender = BeautyPreviewExtender.create(mPreviewConfigBuilder);
+                previewExtender = BeautyPreviewExtender.create(mPreviewBuilder);
                 break;
             case NIGHT:
                 imageCaptureExtender = NightImageCaptureExtender.create(mImageCaptureConfigBuilder);
-                previewExtender = NightPreviewExtender.create(mPreviewConfigBuilder);
+                previewExtender = NightPreviewExtender.create(mPreviewBuilder);
                 break;
             case AUTO:
                 imageCaptureExtender = AutoImageCaptureExtender.create(mImageCaptureConfigBuilder);
-                previewExtender = AutoPreviewExtender.create(mPreviewConfigBuilder);
+                previewExtender = AutoPreviewExtender.create(mPreviewBuilder);
                 break;
         }
 
diff --git a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
index d70d733..22e2470 100644
--- a/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
+++ b/camera/integration-tests/extensionstestapp/src/main/java/androidx/camera/integration/extensions/CameraExtensionsActivity.java
@@ -44,7 +44,6 @@
 import androidx.camera.core.ImageCaptureConfig;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.core.PreviewSurfaceProviders;
 import androidx.camera.core.UseCase;
 import androidx.camera.core.impl.utils.executor.CameraXExecutors;
@@ -124,9 +123,8 @@
             LifecycleCameraProvider.unbind(mPreview);
         }
 
-        PreviewConfig.Builder builder =
-                new PreviewConfig.Builder()
-                        .setTargetName("Preview");
+        Preview.Builder builder = new Preview.Builder()
+                .setTargetName("Preview");
 
         Log.d(TAG, "Enabling the extended preview");
         if (mCurrentImageCaptureType == ImageCaptureType.IMAGE_CAPTURE_TYPE_BOKEH) {
@@ -166,8 +164,8 @@
             }
         }
 
-        mPreview = new Preview(builder.build());
-        mPreview.setPreviewSurfaceCallback(createSurfaceTextureProvider(
+        mPreview = builder.build();
+        mPreview.setPreviewSurfaceProvider(createSurfaceTextureProvider(
                 new PreviewSurfaceProviders.SurfaceTextureCallback() {
                     @Override
                     public void onSurfaceTextureReady(@NonNull SurfaceTexture surfaceTexture,
@@ -301,7 +299,7 @@
                 return;
         }
 
-        mImageCapture = new ImageCapture(builder.build());
+        mImageCapture = builder.build();
 
         Button captureButton = findViewById(R.id.Picture);
 
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
index e2bc6af..2e6c59d 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraParams.kt
@@ -24,18 +24,18 @@
 import android.os.Handler
 import android.os.HandlerThread
 import android.util.Size
+import androidx.camera.core.ImageCapture
+import androidx.camera.core.ImageCaptureConfig
+import androidx.camera.core.Preview
 import androidx.camera.integration.antelope.MainActivity.Companion.FIXED_FOCUS_DISTANCE
 import androidx.camera.integration.antelope.MainActivity.Companion.INVALID_FOCAL_LENGTH
 import androidx.camera.integration.antelope.MainActivity.Companion.NO_APERTURE
-import androidx.camera.core.ImageCapture
-import androidx.camera.core.ImageCaptureConfig
-import androidx.camera.core.PreviewConfig
 import androidx.camera.integration.antelope.cameracontrollers.Camera2CaptureSessionCallback
 import androidx.camera.integration.antelope.cameracontrollers.Camera2DeviceStateCallback
 import androidx.camera.integration.antelope.cameracontrollers.CameraState
+import androidx.camera.integration.antelope.cameracontrollers.CameraXCaptureSessionCallback
 import androidx.camera.integration.antelope.cameracontrollers.CameraXDeviceStateCallback
 import androidx.camera.integration.antelope.cameracontrollers.CameraXPreviewSessionStateCallback
-import androidx.camera.integration.antelope.cameracontrollers.CameraXCaptureSessionCallback
 
 /**
  * CameraParams contains a list of device characteristics for a given camera device.
@@ -104,15 +104,12 @@
     internal var cameraXDeviceStateCallback: CameraXDeviceStateCallback? = null
     internal var cameraXPreviewSessionStateCallback: CameraXPreviewSessionStateCallback? = null
     internal var cameraXCaptureSessionCallback: CameraXCaptureSessionCallback? = null
-    internal var cameraXPreviewConfig: PreviewConfig =
-        PreviewConfig.Builder().build()
-    internal var cameraXCaptureConfig: ImageCaptureConfig =
-        ImageCaptureConfig.Builder().build()
+    internal var cameraXPreviewBuilder: Preview.Builder = Preview.Builder()
+    internal var cameraXCaptureBuilder: ImageCaptureConfig.Builder = ImageCaptureConfig.Builder()
 
     // Custom lifecycle for CameraX API
     internal var cameraXLifecycle: CustomLifecycle = CustomLifecycle()
-    internal var cameraXImageCaptureUseCase: ImageCapture =
-        ImageCapture(ImageCaptureConfig.Builder().build())
+    internal var cameraXImageCaptureUseCase: ImageCapture = ImageCaptureConfig.Builder().build()
 
     // Testing variables
     internal var timer: CameraTimer = CameraTimer()
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
index 159071f..ab919f2 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/CameraUtils.kt
@@ -30,7 +30,7 @@
 import android.view.Surface
 import androidx.appcompat.app.AppCompatActivity
 import androidx.camera.core.ImageCaptureConfig
-import androidx.camera.core.PreviewConfig
+import androidx.camera.core.Preview
 import androidx.camera.integration.antelope.MainActivity.Companion.FIXED_FOCUS_DISTANCE
 import androidx.camera.integration.antelope.MainActivity.Companion.cameraParams
 import androidx.camera.integration.antelope.MainActivity.Companion.logd
@@ -165,9 +165,9 @@
                 previewSurfaceView = activity.surface_preview
                 cameraXPreviewTexture = activity.texture_preview
 
-                cameraXPreviewConfig = PreviewConfig.Builder().build()
+                cameraXPreviewBuilder = Preview.Builder()
 
-                cameraXCaptureConfig = ImageCaptureConfig.Builder().build()
+                cameraXCaptureBuilder = ImageCaptureConfig.Builder()
 
                 imageAvailableListener =
                     ImageAvailableListener(activity, this, TestConfig())
@@ -220,10 +220,13 @@
             params.cam2MinSize
 
         params.imageReader?.close()
-        params.imageReader = ImageReader.newInstance(size.width, size.height,
-            ImageFormat.JPEG, 5)
+        params.imageReader = ImageReader.newInstance(
+            size.width, size.height,
+            ImageFormat.JPEG, 5
+        )
         params.imageReader?.setOnImageAvailableListener(
-            params.imageAvailableListener, params.backgroundHandler)
+            params.imageAvailableListener, params.backgroundHandler
+        )
     }
 }
 
diff --git a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
index c8b4df9..705ce10 100644
--- a/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
+++ b/camera/integration-tests/timingtestapp/src/main/java/androidx/camera/integration/antelope/cameracontrollers/CameraXController.kt
@@ -24,14 +24,12 @@
 import android.view.ViewGroup
 import androidx.annotation.experimental.UseExperimental
 import androidx.camera.camera2.Camera2Config
-
 import androidx.camera.camera2.ExperimentalCamera2Interop
 import androidx.camera.core.CameraSelector
 import androidx.camera.core.ImageCapture
 import androidx.camera.core.ImageCaptureConfig
 import androidx.camera.core.LensFacing
 import androidx.camera.core.Preview
-import androidx.camera.core.PreviewConfig
 import androidx.camera.core.PreviewSurfaceProviders
 import androidx.camera.core.PreviewSurfaceProviders.createSurfaceTextureProvider
 import androidx.camera.core.impl.utils.executor.CameraXExecutors
@@ -69,7 +67,8 @@
         // Currently we swap out the ids behind the scenes
         // This requires to save the actual camera id for after the test
         if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
-            (testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
+            (testConfig.currentRunningTest == TestType.MULTI_SWITCH)
+        ) {
             testConfig.switchTestRealCameraId = params.id // Save the actual camera ID
             params.id = testConfig.switchTestCurrentCamera
         }
@@ -79,12 +78,14 @@
             CameraXPreviewSessionStateCallback(activity, params, testConfig)
 
         if (params.cameraXDeviceStateCallback != null &&
-            params.cameraXPreviewSessionStateCallback != null) {
-            params.cameraXPreviewConfig =
+            params.cameraXPreviewSessionStateCallback != null
+        ) {
+            params.cameraXPreviewBuilder =
                 cameraXPreviewUseCaseBuilder(
                     testConfig.focusMode,
                     params.cameraXDeviceStateCallback!!,
-                    params.cameraXPreviewSessionStateCallback!!)
+                    params.cameraXPreviewSessionStateCallback!!
+                )
         }
 
         if (!params.cameraXLifecycle.isFinished()) {
@@ -95,11 +96,11 @@
         params.cameraXLifecycle = CustomLifecycle()
 
         val lifecycleOwner: LifecycleOwner = params.cameraXLifecycle
-        val previewUseCase = Preview(params.cameraXPreviewConfig)
+        val previewUseCase = params.cameraXPreviewBuilder.build()
 
         // Set preview to observe the surface texture
         activity.runOnUiThread {
-            previewUseCase.previewSurfaceCallback = createSurfaceTextureProvider(
+            previewUseCase.previewSurfaceProvider = createSurfaceTextureProvider(
                 object : PreviewSurfaceProviders.SurfaceTextureCallback {
 
                     override fun onSafeToRelease(surfaceTexture: SurfaceTexture) {
@@ -144,15 +145,17 @@
                     CameraXCaptureSessionCallback(activity, params, testConfig)
 
                 if (params.cameraXDeviceStateCallback != null &&
-                    params.cameraXCaptureSessionCallback != null) {
-                    params.cameraXCaptureConfig =
+                    params.cameraXCaptureSessionCallback != null
+                ) {
+                    params.cameraXCaptureBuilder =
                         cameraXImageCaptureUseCaseBuilder(
                             testConfig.focusMode,
                             params.cameraXDeviceStateCallback!!,
-                            params.cameraXCaptureSessionCallback!!)
+                            params.cameraXCaptureSessionCallback!!
+                        )
                 }
 
-                params.cameraXImageCaptureUseCase = ImageCapture(params.cameraXCaptureConfig)
+                params.cameraXImageCaptureUseCase = params.cameraXCaptureBuilder.build()
 
                 params.timer.openStart = System.currentTimeMillis()
 
@@ -189,7 +192,8 @@
         }
     }
     if ((testConfig.currentRunningTest == TestType.SWITCH_CAMERA) ||
-        (testConfig.currentRunningTest == TestType.MULTI_SWITCH)) {
+        (testConfig.currentRunningTest == TestType.MULTI_SWITCH)
+    ) {
         params.id = testConfig.switchTestRealCameraId // Restore the actual camera ID
     }
 
@@ -212,8 +216,10 @@
     logd("CameraX TakePicture: capture start.")
 
     // Pause in multi-captures to make sure HDR routines don't get overloaded
-    logd("CameraX TakePicture. Pausing for " +
-            PrefHelper.getPreviewBuffer(activity) + "ms to let preview run.")
+    logd(
+        "CameraX TakePicture. Pausing for " +
+                PrefHelper.getPreviewBuffer(activity) + "ms to let preview run."
+    )
 
     params.timer.previewFillStart = System.currentTimeMillis()
     Thread.sleep(PrefHelper.getPreviewBuffer(activity))
@@ -287,9 +293,9 @@
     focusMode: FocusMode,
     deviceStateCallback: CameraDevice.StateCallback,
     sessionCaptureStateCallback: CameraCaptureSession.StateCallback
-): PreviewConfig {
+): Preview.Builder {
 
-    val configBuilder = PreviewConfig.Builder()
+    val configBuilder = Preview.Builder()
     Camera2Config.Extender(configBuilder)
         .setDeviceStateCallback(deviceStateCallback)
         .setSessionStateCallback(sessionCaptureStateCallback)
@@ -297,7 +303,7 @@
 
     // Prints a log to suppress "fix Parameter 'focusMode' is never used" build error"
     Log.d("Antelope", "focusMode($focusMode) Not enabled.")
-    return configBuilder.build()
+    return configBuilder
 }
 
 /**
@@ -309,7 +315,7 @@
     deviceStateCallback:
     CameraDevice.StateCallback,
     sessionCaptureCallback: CameraCaptureSession.CaptureCallback
-): ImageCaptureConfig {
+): ImageCaptureConfig.Builder {
 
     val configBuilder = ImageCaptureConfig.Builder()
         .setCaptureMode(ImageCapture.CaptureMode.MAX_QUALITY)
@@ -320,5 +326,5 @@
 
     // Prints a log to suppress "fix Parameter 'focusMode' is never used" build error"
     Log.d("Antelope", "focusMode($focusMode) Not enabled.")
-    return configBuilder.build()
+    return configBuilder
 }
\ No newline at end of file
diff --git a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
index a86e658b..db6d7c5 100644
--- a/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
+++ b/camera/integration-tests/viewtestapp/src/main/java/androidx/camera/integration/view/PreviewViewFragment.java
@@ -27,7 +27,6 @@
 import androidx.camera.core.CameraSelector;
 import androidx.camera.core.LensFacing;
 import androidx.camera.core.Preview;
-import androidx.camera.core.PreviewConfig;
 import androidx.camera.lifecycle.LifecycleCameraProvider;
 import androidx.camera.view.PreviewView;
 import androidx.fragment.app.Fragment;
@@ -68,10 +67,11 @@
     }
 
     private void bindPreview() {
-        Preview preview = new Preview(new PreviewConfig.Builder()
+        Preview preview = new Preview.Builder()
                 .setTargetName("Preview")
-                .build());
-        preview.setPreviewSurfaceCallback(mPreviewView.getPreviewSurfaceCallback());
+                .build();
+
+        preview.setPreviewSurfaceProvider(mPreviewView.getPreviewSurfaceProvider());
 
         CameraSelector cameraSelector =
                 new CameraSelector.Builder().requireLensFacing(LensFacing.BACK).build();
diff --git a/compose/compose-ide-plugin/build.gradle b/compose/compose-ide-plugin/build.gradle
index 4eb00cb..f909b50 100644
--- a/compose/compose-ide-plugin/build.gradle
+++ b/compose/compose-ide-plugin/build.gradle
@@ -23,12 +23,19 @@
 
 import static androidx.build.dependencies.DependenciesKt.*
 
+buildscript {
+    dependencies {
+        classpath("gradle.plugin.org.jetbrains.intellij.plugins:gradle-intellij-plugin:0.4.8")
+    }
+}
+
 plugins {
     id("AndroidXPlugin")
     id("kotlin")
-    id("org.jetbrains.intellij") version("0.4.8")
 }
 
+apply(plugin: "org.jetbrains.intellij")
+
 def studioWrapper = StudioWrapper.create(rootProject)
 
 // Unfortunately the Intellij plugin requires libs from the Studio installation as soon as it is
diff --git a/core/core/api/1.3.0-alpha01.txt b/core/core/api/1.3.0-alpha01.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/1.3.0-alpha01.txt
+++ b/core/core/api/1.3.0-alpha01.txt
@@ -462,29 +462,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/current.txt b/core/core/api/current.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/current.txt
+++ b/core/core/api/current.txt
@@ -462,29 +462,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
+++ b/core/core/api/public_plus_experimental_1.3.0-alpha01.txt
@@ -462,29 +462,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/public_plus_experimental_current.txt b/core/core/api/public_plus_experimental_current.txt
index 9b49fc4..9341fb8 100644
--- a/core/core/api/public_plus_experimental_current.txt
+++ b/core/core/api/public_plus_experimental_current.txt
@@ -462,29 +462,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/restricted_1.3.0-alpha01.txt b/core/core/api/restricted_1.3.0-alpha01.txt
index 70760bb..f86b271 100644
--- a/core/core/api/restricted_1.3.0-alpha01.txt
+++ b/core/core/api/restricted_1.3.0-alpha01.txt
@@ -519,29 +519,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/api/restricted_current.txt b/core/core/api/restricted_current.txt
index 70760bb..f86b271 100644
--- a/core/core/api/restricted_current.txt
+++ b/core/core/api/restricted_current.txt
@@ -519,29 +519,29 @@
     method public androidx.core.app.NotificationCompat.Builder! extend(androidx.core.app.NotificationCompat.Builder!);
     method @ColorInt public int getColor();
     method public android.graphics.Bitmap! getLargeIcon();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! getUnreadConversation();
     method public androidx.core.app.NotificationCompat.CarExtender! setColor(@ColorInt int);
     method public androidx.core.app.NotificationCompat.CarExtender! setLargeIcon(android.graphics.Bitmap!);
-    method public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender! setUnreadConversation(androidx.core.app.NotificationCompat.CarExtender.UnreadConversation!);
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation {
-    method public long getLatestTimestamp();
-    method public String![]! getMessages();
-    method public String! getParticipant();
-    method public String![]! getParticipants();
-    method public android.app.PendingIntent! getReadPendingIntent();
-    method public androidx.core.app.RemoteInput! getRemoteInput();
-    method public android.app.PendingIntent! getReplyPendingIntent();
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation {
+    method @Deprecated public long getLatestTimestamp();
+    method @Deprecated public String![]! getMessages();
+    method @Deprecated public String! getParticipant();
+    method @Deprecated public String![]! getParticipants();
+    method @Deprecated public android.app.PendingIntent! getReadPendingIntent();
+    method @Deprecated public androidx.core.app.RemoteInput! getRemoteInput();
+    method @Deprecated public android.app.PendingIntent! getReplyPendingIntent();
   }
 
-  public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
-    ctor public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
-    method public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
+  @Deprecated public static class NotificationCompat.CarExtender.UnreadConversation.Builder {
+    ctor @Deprecated public NotificationCompat.CarExtender.UnreadConversation.Builder(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! addMessage(String!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation! build();
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setLatestTimestamp(long);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReadPendingIntent(android.app.PendingIntent!);
+    method @Deprecated public androidx.core.app.NotificationCompat.CarExtender.UnreadConversation.Builder! setReplyAction(android.app.PendingIntent!, androidx.core.app.RemoteInput!);
   }
 
   public static class NotificationCompat.DecoratedCustomViewStyle extends androidx.core.app.NotificationCompat.Style {
diff --git a/core/core/src/main/java/androidx/core/app/NotificationCompat.java b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
index fb71fc8..f24995f 100644
--- a/core/core/src/main/java/androidx/core/app/NotificationCompat.java
+++ b/core/core/src/main/java/androidx/core/app/NotificationCompat.java
@@ -5179,7 +5179,11 @@
          *
          * @param unreadConversation The unread part of the conversation this notification conveys.
          * @return This object for method chaining.
+         *
+         * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+         * instead.
          */
+        @Deprecated
         public CarExtender setUnreadConversation(UnreadConversation unreadConversation) {
             mUnreadConversation = unreadConversation;
             return this;
@@ -5188,14 +5192,22 @@
         /**
          * Returns the unread conversation conveyed by this notification.
          * @see #setUnreadConversation(UnreadConversation)
+         *
+         * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+         * instead.
          */
+        @Deprecated
         public UnreadConversation getUnreadConversation() {
             return mUnreadConversation;
         }
 
         /**
          * A class which holds the unread messages from a conversation.
+         *
+         * @deprecated {@link UnreadConversation} is no longer supported. Use {@link MessagingStyle}
+         * instead.
          */
+        @Deprecated
         public static class UnreadConversation {
             private final String[] mMessages;
             private final RemoteInput mRemoteInput;
diff --git a/exifinterface/api/1.2.0-alpha01.txt b/exifinterface/api/1.2.0-alpha01.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/1.2.0-alpha01.txt
+++ b/exifinterface/api/1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/current.txt b/exifinterface/api/current.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/current.txt
+++ b/exifinterface/api/current.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt b/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
+++ b/exifinterface/api/public_plus_experimental_1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/public_plus_experimental_current.txt b/exifinterface/api/public_plus_experimental_current.txt
index 5029c8b..4bbc2ba 100644
--- a/exifinterface/api/public_plus_experimental_current.txt
+++ b/exifinterface/api/public_plus_experimental_current.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
diff --git a/exifinterface/api/restricted_1.2.0-alpha01.txt b/exifinterface/api/restricted_1.2.0-alpha01.txt
index 8c8bca9..5aacfe0 100644
--- a/exifinterface/api/restricted_1.2.0-alpha01.txt
+++ b/exifinterface/api/restricted_1.2.0-alpha01.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, @androidx.exifinterface.media.ExifInterface.ExifStreamType int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
@@ -342,5 +344,6 @@
   }
 
 
+
 }
 
diff --git a/exifinterface/api/restricted_current.txt b/exifinterface/api/restricted_current.txt
index 8c8bca9..5aacfe0 100644
--- a/exifinterface/api/restricted_current.txt
+++ b/exifinterface/api/restricted_current.txt
@@ -6,9 +6,9 @@
     ctor public ExifInterface(String) throws java.io.IOException;
     ctor public ExifInterface(java.io.FileDescriptor) throws java.io.IOException;
     ctor public ExifInterface(java.io.InputStream) throws java.io.IOException;
+    ctor public ExifInterface(java.io.InputStream, @androidx.exifinterface.media.ExifInterface.ExifStreamType int) throws java.io.IOException;
     method public void flipHorizontally();
     method public void flipVertically();
-    method public static androidx.exifinterface.media.ExifInterface fromStandalone(java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method public String? getAttribute(String);
     method public byte[]? getAttributeBytes(String);
@@ -175,6 +175,8 @@
     field public static final short SHARPNESS_HARD = 2; // 0x2
     field public static final short SHARPNESS_NORMAL = 0; // 0x0
     field public static final short SHARPNESS_SOFT = 1; // 0x1
+    field public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1; // 0x1
+    field public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0; // 0x0
     field public static final short SUBJECT_DISTANCE_RANGE_CLOSE_VIEW = 2; // 0x2
     field public static final short SUBJECT_DISTANCE_RANGE_DISTANT_VIEW = 3; // 0x3
     field public static final short SUBJECT_DISTANCE_RANGE_MACRO = 1; // 0x1
@@ -342,5 +344,6 @@
   }
 
 
+
 }
 
diff --git a/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java b/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
index a6526cd..a06d992 100644
--- a/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
+++ b/exifinterface/src/androidTest/java/androidx/exifinterface/media/ExifInterfaceTest.java
@@ -28,6 +28,7 @@
 import android.Manifest;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.location.Location;
 import android.os.Build;
 import android.os.Environment;
@@ -261,8 +262,13 @@
         public final float longitude;
         public final float altitude;
 
-        // Values.
+        // Make information
+        public final boolean hasMake;
+        public final int makeOffset;
+        public final int makeLength;
         public final String make;
+
+        // Values.
         public final String model;
         public final float aperture;
         public final String dateTimeOriginal;
@@ -316,8 +322,13 @@
             longitude = typedArray.getFloat(index++, 0f);
             altitude = typedArray.getFloat(index++, 0f);
 
-            // Reads values.
+            // Reads Make information.
+            hasMake = typedArray.getBoolean(index++, false);
+            makeOffset = typedArray.getInt(index++, -1);
+            makeLength = typedArray.getInt(index++, -1);
             make = getString(typedArray, index++);
+
+            // Reads values.
             model = getString(typedArray, index++);
             aperture = typedArray.getFloat(index++, 0f);
             dateTimeOriginal = getString(typedArray, index++);
@@ -821,14 +832,7 @@
                 assertEquals(expectedValue.thumbnailOffset, thumbnailRange[0]);
                 assertEquals(expectedValue.thumbnailLength, thumbnailRange[1]);
             }
-            byte[] thumbnailBytes = exifInterface.getThumbnailBytes();
-            assertNotNull(thumbnailBytes);
-            Bitmap thumbnailBitmap = exifInterface.getThumbnailBitmap();
-            assertNotNull(thumbnailBitmap);
-            assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
-            assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
-            assertEquals(expectedValue.isThumbnailCompressed,
-                    exifInterface.isThumbnailCompressed());
+            testThumbnail(expectedValue, exifInterface);
         } else {
             assertNull(exifInterface.getThumbnailRange());
             assertNull(exifInterface.getThumbnail());
@@ -856,6 +860,23 @@
         }
         assertEquals(expectedValue.altitude, exifInterface.getAltitude(.0), DIFFERENCE_TOLERANCE);
 
+        // Checks Make information.
+        String make = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
+        assertEquals(expectedValue.hasMake, make != null);
+        if (expectedValue.hasMake) {
+            assertNotNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+            if (assertRanges) {
+                final long[] makeRange = exifInterface
+                        .getAttributeRange(ExifInterface.TAG_MAKE);
+                assertEquals(expectedValue.makeOffset, makeRange[0]);
+                assertEquals(expectedValue.makeLength, makeRange[1]);
+            }
+            assertEquals(expectedValue.make, make);
+        } else {
+            assertNull(exifInterface.getAttributeRange(ExifInterface.TAG_MAKE));
+            assertFalse(exifInterface.hasAttribute(ExifInterface.TAG_MAKE));
+        }
+
         // Checks values.
         assertStringTag(exifInterface, ExifInterface.TAG_MAKE, expectedValue.make);
         assertStringTag(exifInterface, ExifInterface.TAG_MODEL, expectedValue.model);
@@ -923,7 +944,8 @@
         fis.read(exifBytes);
 
         ByteArrayInputStream bin = new ByteArrayInputStream(exifBytes);
-        ExifInterface exifInterface = ExifInterface.fromStandalone(bin);
+        ExifInterface exifInterface =
+                new ExifInterface(bin, ExifInterface.STREAM_TYPE_EXIF_DATA_ONLY);
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag, true);
     }
 
@@ -968,6 +990,60 @@
         }
     }
 
+    private void testExifInterfaceRange(String fileName, ExpectedValue expectedValue)
+            throws IOException {
+        File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
+
+        InputStream in = null;
+        try {
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasThumbnail) {
+                in.skip(expectedValue.thumbnailOffset);
+                byte[] thumbnailBytes = new byte[expectedValue.thumbnailLength];
+                if (in.read(thumbnailBytes) != expectedValue.thumbnailLength) {
+                    throw new IOException("Failed to read the expected thumbnail length");
+                }
+                // TODO: Need a way to check uncompressed thumbnail file
+                Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnailBytes, 0,
+                        thumbnailBytes.length);
+                assertNotNull(thumbnailBitmap);
+                assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+                assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
+            }
+
+            // TODO: Creating a new input stream is a temporary
+            //  workaround for BufferedInputStream#mark/reset not working properly for
+            //  LG_G4_ISO_800_DNG. Need to investigate cause.
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasMake) {
+                in.skip(expectedValue.makeOffset);
+                byte[] makeBytes = new byte[expectedValue.makeLength];
+                if (in.read(makeBytes) != expectedValue.makeLength) {
+                    throw new IOException("Failed to read the expected make length");
+                }
+                String makeString = new String(makeBytes);
+                // Remove null bytes
+                makeString = makeString.replaceAll("\u0000.*", "");
+                assertEquals(expectedValue.make, makeString);
+            }
+
+            in = new BufferedInputStream(new FileInputStream(imageFile.getAbsolutePath()));
+            if (expectedValue.hasXmp) {
+                in.skip(expectedValue.xmpOffset);
+                byte[] identifierBytes = new byte[expectedValue.xmpLength];
+                if (in.read(identifierBytes) != expectedValue.xmpLength) {
+                    throw new IOException("Failed to read the expected xmp length");
+                }
+                final String xmpIdentifier = "<?xpacket begin=";
+                assertTrue(new String(identifierBytes, Charset.forName("UTF-8"))
+                        .startsWith(xmpIdentifier));
+            }
+            // TODO: Add code for retrieving raw latitude data using offset and length
+        } finally {
+            closeQuietly(in);
+        }
+    }
+
     private void testSaveAttributes_withFileName(String fileName, ExpectedValue expectedValue)
             throws IOException {
         File imageFile = new File(Environment.getExternalStorageDirectory(), fileName);
@@ -976,15 +1052,23 @@
         ExifInterface exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         exifInterface.saveAttributes();
         exifInterface = new ExifInterface(imageFile.getAbsolutePath());
-
         compareWithExpectedValue(exifInterface, expectedValue, verboseTag, false);
 
         // Test for modifying one attribute.
         String backupValue = exifInterface.getAttribute(ExifInterface.TAG_MAKE);
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, "abc");
         exifInterface.saveAttributes();
+        // Check if thumbnail offset and length are properly updated without parsing the data again.
+        if (expectedValue.hasThumbnail) {
+            testThumbnail(expectedValue, exifInterface);
+        }
         exifInterface = new ExifInterface(imageFile.getAbsolutePath());
         assertEquals("abc", exifInterface.getAttribute(ExifInterface.TAG_MAKE));
+        // Check if thumbnail bytes can be retrieved from the new thumbnail range.
+        if (expectedValue.hasThumbnail) {
+            testThumbnail(expectedValue, exifInterface);
+        }
+
         // Restore the backup value.
         exifInterface.setAttribute(ExifInterface.TAG_MAKE, backupValue);
         exifInterface.saveAttributes();
@@ -1000,6 +1084,9 @@
         // Test for reading from external data storage.
         testExifInterfaceCommon(fileName, expectedValue);
 
+        // Test for checking expected range by retrieving raw data with given offset and length.
+        testExifInterfaceRange(fileName, expectedValue);
+
         // Test for saving attributes.
         testSaveAttributes_withFileName(fileName, expectedValue);
     }
@@ -1012,8 +1099,18 @@
         // Test for reading from external data storage.
         testExifInterfaceCommon(fileName, expectedValue);
 
-        // Since ExifInterface does not support for saving attributes for non-JPEG files, do not
-        // test about writing back in here.
+        // Test for checking expected range by retrieving raw data with given offset and length.
+        testExifInterfaceRange(fileName, expectedValue);
+    }
+
+    private void testThumbnail(ExpectedValue expectedValue, ExifInterface exifInterface) {
+        byte[] thumbnail = exifInterface.getThumbnail();
+        assertNotNull(thumbnail);
+        Bitmap thumbnailBitmap = BitmapFactory.decodeByteArray(thumbnail, 0,
+                thumbnail.length);
+        assertNotNull(thumbnailBitmap);
+        assertEquals(expectedValue.thumbnailWidth, thumbnailBitmap.getWidth());
+        assertEquals(expectedValue.thumbnailHeight, thumbnailBitmap.getHeight());
     }
 
     private void generateRandomExifTag(ByteBuffer buffer, int ifdType, Random random) {
diff --git a/exifinterface/src/androidTest/res/values/arrays.xml b/exifinterface/src/androidTest/res/values/arrays.xml
index 58af04b..d828bad 100644
--- a/exifinterface/src/androidTest/res/values/arrays.xml
+++ b/exifinterface/src/androidTest/res/values/arrays.xml
@@ -16,18 +16,24 @@
 
 <resources>
     <array name="exifbyteorderii_jpg">
+        <!--Whether thumbnail exists-->
         <item>true</item>
         <item>3500</item>
         <item>6265</item>
         <item>512</item>
         <item>288</item>
         <item>true</item>
+        <!--Whether GPS LatLong information exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>160</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>SM-N900S</item>
         <item>2.200</item>
@@ -54,18 +60,24 @@
         <item>0</item>
     </array>
     <array name="exifbyteorderii_standalone">
+        <!--Whether thumbnail exists-->
         <item>true</item>
         <item>3494</item>
         <item>6265</item>
         <item>512</item>
         <item>288</item>
         <item>true</item>
+        <!--Whether GPS LatLong information exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>154</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>SM-N900S</item>
         <item>2.200</item>
@@ -92,18 +104,24 @@
         <item>0</item>
     </array>
     <array name="exifbyteordermm_jpg">
+        <!--Whether thumbnail exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>false</item>
+        <!--Whether GPS LatLong information exists-->
         <item>true</item>
-        <item>572</item>
+        <item>584</item>
         <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>414</item>
+        <item>4</item>
         <item>LGE</item>
         <item>Nexus 5</item>
         <item>2.400</item>
@@ -130,18 +148,24 @@
         <item>0</item>
     </array>
     <array name="exifbyteordermm_standalone">
+        <!--Whether thumbnail exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>false</item>
+        <!--Whether GPS LatLong information exists-->
         <item>true</item>
-        <item>572</item>
+        <item>578</item>
         <item>24</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>408</item>
+        <item>4</item>
         <item>LGE</item>
         <item>Nexus 5</item>
         <item>2.400</item>
@@ -168,18 +192,24 @@
         <item>0</item>
     </array>
     <array name="lg_g4_iso_800_dng">
+        <!--Whether thumbnail exists-->
         <item>true</item>
-        <item>0</item>
+        <item>12570</item>
         <item>15179</item>
         <item>256</item>
         <item>144</item>
         <item>true</item>
+        <!--Whether GPS LatLong information exists-->
         <item>true</item>
         <item>12486</item>
         <item>24</item>
         <item>53.834507</item>
         <item>10.69585</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>102</item>
+        <item>4</item>
         <item>LGE</item>
         <item>LG-H815</item>
         <item>1.800</item>
@@ -206,18 +236,24 @@
         <item>10067</item>
     </array>
     <array name="lg_g4_iso_800_jpg">
+        <!--Whether thumbnail exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>0</item>
         <item>false</item>
+        <!--Whether GPS LatLong information exists-->
         <item>true</item>
-        <item>1662</item>
+        <item>1692</item>
         <item>24</item>
         <item>53.834507</item>
         <item>10.69585</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>84</item>
+        <item>4</item>
         <item>LGE</item>
         <item>LG-H815</item>
         <item>1.800</item>
@@ -244,18 +280,24 @@
         <item>13197</item>
     </array>
     <array name="exifbyteorderii_png">
+        <!--Whether thumbnail exists-->
         <item>true</item>
         <item>212271</item>
         <item>6265</item>
         <item>512</item>
         <item>288</item>
         <item>true</item>
+        <!--Whether GPS LatLong information exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>211525</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>SM-N900S</item>
         <item>2.200</item>
@@ -282,18 +324,24 @@
         <item>0</item>
     </array>
     <array name="exifbyteorderii_webp">
+        <!--Whether thumbnail exists-->
         <item>true</item>
         <item>9646</item>
         <item>6265</item>
         <item>512</item>
         <item>288</item>
         <item>true</item>
+        <!--Whether GPS LatLong information exists-->
         <item>false</item>
         <item>0</item>
         <item>0</item>
         <item>0.0</item>
         <item>0.0</item>
         <item>0.0</item>
+        <!--Whether Make information exists-->
+        <item>true</item>
+        <item>6306</item>
+        <item>8</item>
         <item>SAMSUNG</item>
         <item>SM-N900S</item>
         <item>2.200</item>
diff --git a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
index 0e1eacc..02e41f7 100644
--- a/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
+++ b/exifinterface/src/main/java/androidx/exifinterface/media/ExifInterface.java
@@ -2908,6 +2908,27 @@
      */
     public static final int REDUCED_RESOLUTION_IMAGE = 1;
 
+    /**
+     * Constant used to indicate that the input stream contains the full image data.
+     * <p>
+     * The format of the image data should follow one of the image formats supported by this class.
+     */
+    public static final int STREAM_TYPE_FULL_IMAGE_DATA = 0;
+    /**
+     * Constant used to indicate that the input stream contains only Exif data.
+     * <p>
+     * The format of the Exif-only data must follow the below structure:
+     *     Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
+     * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
+     */
+    public static final int STREAM_TYPE_EXIF_DATA_ONLY = 1;
+
+    /** @hide */
+    @RestrictTo(RestrictTo.Scope.LIBRARY)
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({STREAM_TYPE_FULL_IMAGE_DATA, STREAM_TYPE_EXIF_DATA_ONLY})
+    public @interface ExifStreamType {}
+
     // Maximum size for checking file type signature (see image_type_recognition_lite.cc)
     private static final int SIGNATURE_CHECK_SIZE = 5000;
 
@@ -3830,13 +3851,15 @@
     private FileDescriptor mSeekableFileDescriptor;
     private AssetManager.AssetInputStream mAssetInputStream;
     private int mMimeType;
-    private boolean mIsStandalone;
+    private boolean mIsExifDataOnly;
     @SuppressWarnings("unchecked")
     private final HashMap<String, ExifAttribute>[] mAttributes = new HashMap[EXIF_TAGS.length];
     private Set<Integer> mAttributesOffsets = new HashSet<>(EXIF_TAGS.length);
     private ByteOrder mExifByteOrder = ByteOrder.BIG_ENDIAN;
     private boolean mHasThumbnail;
-    // The following values used for indicating a thumbnail position.
+    private boolean mHasThumbnailStrips;
+    private boolean mAreThumbnailStripsConsecutive;
+    // Used to indicate the position of the thumbnail (includes offset to EXIF data segment).
     private int mThumbnailOffset;
     private int mThumbnailLength;
     private byte[] mThumbnailBytes;
@@ -3857,6 +3880,11 @@
 
     /**
      * Reads Exif tags from the specified image file.
+     *
+     * @param file the file of the image data
+     * @throws NullPointerException if file is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
     public ExifInterface(@NonNull File file) throws IOException {
         if (file == null) {
@@ -3867,6 +3895,11 @@
 
     /**
      * Reads Exif tags from the specified image file.
+     *
+     * @param filename the name of the file of the image data
+     * @throws NullPointerException if file name is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
     public ExifInterface(@NonNull String filename) throws IOException {
         if (filename == null) {
@@ -3879,6 +3912,11 @@
      * Reads Exif tags from the specified image file descriptor. Attribute mutation is supported
      * for writable and seekable file descriptors only. This constructor will not rewind the offset
      * of the given file descriptor. Developers should close the file descriptor after use.
+     *
+     * @param fileDescriptor the file descriptor of the image data
+     * @throws NullPointerException if file descriptor is null
+     * @throws IOException if an error occurs while duplicating the file descriptor via
+     *         {@link Os#dup(FileDescriptor)}.
      */
     public ExifInterface(@NonNull FileDescriptor fileDescriptor) throws IOException {
         if (fileDescriptor == null) {
@@ -3919,44 +3957,45 @@
      * for input streams. The given input stream will proceed from its current position. Developers
      * should close the input stream after use. This constructor is not intended to be used with
      * an input stream that performs any networking operations.
+     *
+     * @param inputStream the input stream that contains the image data
+     * @throws NullPointerException if the input stream is null
      */
     public ExifInterface(@NonNull InputStream inputStream) throws IOException {
         this(inputStream, false);
     }
 
     /**
-     * Reads Exif tags from the specified standalone input stream. Standalone data refers to Exif
-     * data that exists by itself and is not contained in a file format such as jpeg or png.
-     * The format of the standalone data must follow the below structure:
-     *     Exif Identifier Code ("Exif\0\0") + TIFF header + IFD data
-     * See JEITA CP-3451C Section 4.5.2 and 4.5.4 specifications for more details.
-     * <p>
-     * Attribute mutation is not supported for this constructor. The given input stream will proceed
-     * from its current position. Developers should close the input stream after use. This
-     * constructor is not intended to be used with an input stream that performs any networking
-     * operations.
+     * Reads Exif tags from the specified image input stream based on the stream type. Attribute
+     * mutation is not supported for input streams. The given input stream will proceed from its
+     * current position. Developers should close the input stream after use. This constructor is not
+     * intended to be used with an input stream that performs any networking operations.
      *
-     * @throws IOException if the data does not follow the aforementioned structure.
+     * @param inputStream the input stream that contains the image data
+     * @param streamType the type of input stream
+     * @throws NullPointerException if the input stream is null
+     * @throws IOException if an I/O error occurs while retrieving file descriptor via
+     *         {@link FileInputStream#getFD()}.
      */
-    @NonNull
-    public static ExifInterface fromStandalone(@NonNull InputStream inputStream)
+    public ExifInterface(@NonNull InputStream inputStream, @ExifStreamType int streamType)
             throws IOException {
-        if (isStandalone(inputStream)) {
-            return new ExifInterface(inputStream, true);
-        }
-        throw new IOException("Given data does not follow the structure of a standalone exif "
-                + "data.");
+        this(inputStream, (streamType == STREAM_TYPE_EXIF_DATA_ONLY) ? true : false);
     }
 
-    private ExifInterface(@NonNull InputStream inputStream, boolean isFromStandalone)
+    private ExifInterface(@NonNull InputStream inputStream, boolean shouldBeExifDataOnly)
             throws IOException {
         if (inputStream == null) {
             throw new NullPointerException("inputStream cannot be null");
         }
         mFilename = null;
 
-        if (isFromStandalone) {
-            mIsStandalone = true;
+        if (shouldBeExifDataOnly) {
+            inputStream = new BufferedInputStream(inputStream, SIGNATURE_CHECK_SIZE);
+            if (!isExifDataOnly((BufferedInputStream) inputStream)) {
+                Log.w(TAG, "Given data does not follow the structure of an Exif-only data.");
+                return;
+            }
+            mIsExifDataOnly = true;
             mAssetInputStream = null;
             mSeekableFileDescriptor = null;
         } else {
@@ -4462,10 +4501,9 @@
 
     /**
      * This function decides which parser to read the image data according to the given input stream
-     * type and the content of the input stream. In each case, it reads the first three bytes to
-     * determine whether the image data format is JPEG or not.
+     * type and the content of the input stream.
      */
-    private void loadAttributes(@NonNull InputStream in) throws IOException {
+    private void loadAttributes(@NonNull InputStream in) {
         if (in == null) {
             throw new NullPointerException("inputstream shouldn't be null");
         }
@@ -4476,7 +4514,7 @@
             }
 
             // Check file type
-            if (!mIsStandalone) {
+            if (!mIsExifDataOnly) {
                 in = new BufferedInputStream(in, SIGNATURE_CHECK_SIZE);
                 mMimeType = getMimeType((BufferedInputStream) in);
             }
@@ -4484,7 +4522,7 @@
             // Create byte-ordered input stream
             ByteOrderedDataInputStream inputStream = new ByteOrderedDataInputStream(in);
 
-            if (!mIsStandalone) {
+            if (!mIsExifDataOnly) {
                 switch (mMimeType) {
                     case IMAGE_TYPE_JPEG: {
                         getJpegAttributes(inputStream, 0, IFD_TYPE_PRIMARY); // 0 is offset
@@ -4553,12 +4591,15 @@
         }
     }
 
-    private static boolean isSeekableFD(FileDescriptor fd) throws IOException {
+    private static boolean isSeekableFD(FileDescriptor fd) {
         if (Build.VERSION.SDK_INT >= 21) {
             try {
                 Os.lseek(fd, 0, OsConstants.SEEK_CUR);
                 return true;
             } catch (Exception e) {
+                if (DEBUG) {
+                    Log.d(TAG, "The file descriptor for the given input is not seekable");
+                }
                 return false;
             }
         }
@@ -4744,6 +4785,7 @@
                 // Should not be reached this.
                 throw new FileNotFoundException();
             }
+
             if (in.skip(mThumbnailOffset) != mThumbnailOffset) {
                 throw new IOException("Corrupted image");
             }
@@ -4818,10 +4860,12 @@
 
     /**
      * Returns the offset and length of thumbnail inside the image file, or
-     * {@code null} if there is no thumbnail.
+     * {@code null} if either there is no thumbnail or the thumbnail bytes are stored
+     * non-consecutively.
      *
      * @return two-element array, the offset in the first value, and length in
-     *         the second, or {@code null} if no thumbnail was found.
+     *         the second, or {@code null} if no thumbnail was found or the thumbnail strips are
+     *         not placed consecutively.
      * @throws IllegalStateException if {@link #saveAttributes()} has been
      *             called since the underlying file was initially parsed, since
      *             that means offsets may have changed.
@@ -4834,13 +4878,12 @@
         }
 
         if (mHasThumbnail) {
-            if (mIsStandalone) {
-                return new long[] { mThumbnailOffset + mExifOffset, mThumbnailLength };
+            if (mHasThumbnailStrips && !mAreThumbnailStripsConsecutive) {
+                return null;
             }
             return new long[] { mThumbnailOffset, mThumbnailLength };
-        } else {
-            return null;
         }
+        return null;
     }
 
     /**
@@ -5393,10 +5436,11 @@
         return true;
     }
 
-    private static boolean isStandalone(InputStream inputStream) throws IOException {
+    private static boolean isExifDataOnly(BufferedInputStream in) throws IOException {
+        in.mark(IDENTIFIER_EXIF_APP1.length);
         byte[] signatureCheckBytes = new byte[IDENTIFIER_EXIF_APP1.length];
-        inputStream.read(signatureCheckBytes);
-
+        in.read(signatureCheckBytes);
+        in.reset();
         for (int i = 0; i < IDENTIFIER_EXIF_APP1.length; i++) {
             if (signatureCheckBytes[i] != IDENTIFIER_EXIF_APP1[i]) {
                 return false;
@@ -5476,10 +5520,9 @@
                         final int offset = start + IDENTIFIER_EXIF_APP1.length;
                         final byte[] value = Arrays.copyOfRange(bytes, IDENTIFIER_EXIF_APP1.length,
                                 bytes.length);
+                        // Save offset values for handling thumbnail and attribute offsets.
+                        mExifOffset = offset;
                         readExifSegment(value, imageType);
-
-                        // Save offset values for handleThumbnailFromJfif() function
-                        mExifOffset = (int) offset;
                     } else if (startsWith(bytes, IDENTIFIER_XMP_APP1)) {
                         // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
                         final int offset = start + IDENTIFIER_XMP_APP1.length;
@@ -5796,6 +5839,8 @@
                 if (in.read(bytes) != length) {
                     throw new IOException("Can't read exif");
                 }
+                // Save offset values for handling thumbnail and attribute offsets.
+                mExifOffset = offset;
                 readExifSegment(bytes, IFD_TYPE_PRIMARY);
             }
 
@@ -5808,13 +5853,13 @@
     }
 
     private void getStandaloneAttributes(ByteOrderedDataInputStream in) throws IOException {
+        in.skipBytes(IDENTIFIER_EXIF_APP1.length);
         // TODO: Need to handle potential OutOfMemoryError
         byte[] data = new byte[in.available()];
         in.readFully(data);
-        readExifSegment(data, IFD_TYPE_PRIMARY);
-
-        // Save offset values for handleThumbnailFromJfif() function
+        // Save offset values for handling thumbnail and attribute offsets.
         mExifOffset = IDENTIFIER_EXIF_APP1.length;
+        readExifSegment(data, IFD_TYPE_PRIMARY);
     }
 
     /**
@@ -5999,13 +6044,11 @@
                                 + "\n recorded CRC value: " + dataCrcValue + ", calculated CRC "
                                 + "value: " + crc.getValue());
                     }
-
+                    // Save offset values for handling thumbnail and attribute offsets.
+                    mExifOffset = bytesRead;
                     readExifSegment(data, IFD_TYPE_PRIMARY);
 
                     validateImages();
-
-                    // Save offset values for handleThumbnailFromJfif() function
-                    mExifOffset = bytesRead;
                     break;
                 } else {
                     // Skip to next chunk
@@ -6065,6 +6108,8 @@
                         throw new IOException("Failed to read given length for given PNG chunk "
                                 + "type: " + byteArrayToHexString(code));
                     }
+                    // Save offset values for handling thumbnail and attribute offsets.
+                    mExifOffset = bytesRead;
                     readExifSegment(payload, IFD_TYPE_PRIMARY);
                     break;
                 } else {
@@ -6087,8 +6132,6 @@
                     bytesRead += skipped;
                 }
             }
-            // Save offset values for handleThumbnailFromJfif() function
-            mExifOffset = bytesRead;
         } catch (EOFException e) {
             // Should not reach here. Will only reach here if the file is corrupted or
             // does not follow the WebP specifications
@@ -6119,7 +6162,7 @@
         // Write EXIF APP1 segment
         dataOutputStream.writeByte(MARKER);
         dataOutputStream.writeByte(MARKER_APP1);
-        writeExifSegment(dataOutputStream, 6);
+        writeExifSegment(dataOutputStream);
 
         byte[] bytes = new byte[4096];
 
@@ -6243,7 +6286,7 @@
                             ByteOrder.BIG_ENDIAN);
 
             // Store Exif data in separate byte array
-            writeExifSegment(exifDataOutputStream, 0);
+            writeExifSegment(exifDataOutputStream);
             byte[] exifBytes =
                     ((ByteArrayOutputStream) exifDataOutputStream.mOutputStream).toByteArray();
 
@@ -6526,7 +6569,7 @@
                 continue;
             }
 
-            final int bytesOffset = dataInputStream.peek();
+            final int bytesOffset = dataInputStream.peek() + mExifOffset;
             final byte[] bytes = new byte[(int) byteCount];
             dataInputStream.readFully(bytes);
             ExifAttribute attribute = new ExifAttribute(dataFormat, numberOfComponents,
@@ -6657,40 +6700,32 @@
             int thumbnailOffset = jpegInterchangeFormatAttribute.getIntValue(mExifByteOrder);
             int thumbnailLength = jpegInterchangeFormatLengthAttribute.getIntValue(mExifByteOrder);
 
-            switch (mMimeType) {
-                case IMAGE_TYPE_JPEG:
-                case IMAGE_TYPE_RAF:
-                case IMAGE_TYPE_RW2:
-                case IMAGE_TYPE_PNG:
-                case IMAGE_TYPE_WEBP:
-                    thumbnailOffset += mExifOffset;
-                    break;
-                case IMAGE_TYPE_ORF:
-                    // Update offset value since RAF files have IFD data preceding MakerNote data.
-                    thumbnailOffset += mOrfMakerNoteOffset;
-                    break;
+            if (mMimeType == IMAGE_TYPE_ORF) {
+                // Update offset value since RAF files have IFD data preceding MakerNote data.
+                thumbnailOffset += mOrfMakerNoteOffset;
             }
             // The following code limits the size of thumbnail size not to overflow EXIF data area.
             thumbnailLength = Math.min(thumbnailLength, in.getLength() - thumbnailOffset);
 
-            if (DEBUG) {
-                Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
-                        + ", length: " + thumbnailLength);
-            }
             if (thumbnailOffset > 0 && thumbnailLength > 0) {
                 mHasThumbnail = true;
-                mThumbnailOffset = thumbnailOffset;
+                // Need to add mExifOffset, which is the offset to the EXIF data segment
+                mThumbnailOffset = thumbnailOffset + mExifOffset;
                 mThumbnailLength = thumbnailLength;
                 if (mFilename == null && mAssetInputStream == null
                         && mSeekableFileDescriptor == null) {
                     // TODO: Need to handle potential OutOfMemoryError
                     // Save the thumbnail in memory if the input doesn't support reading again.
-                    byte[] thumbnailBytes = new byte[thumbnailLength];
-                    in.seek(thumbnailOffset);
+                    byte[] thumbnailBytes = new byte[mThumbnailLength];
+                    in.seek(mThumbnailOffset);
                     in.readFully(thumbnailBytes);
                     mThumbnailBytes = thumbnailBytes;
                 }
             }
+            if (DEBUG) {
+                Log.d(TAG, "Setting thumbnail attributes with offset: " + thumbnailOffset
+                        + ", length: " + thumbnailLength);
+            }
         }
     }
 
@@ -6708,12 +6743,16 @@
             long[] stripByteCounts =
                     convertToLongArray(stripByteCountsAttribute.getValue(mExifByteOrder));
 
-            if (stripOffsets == null) {
-                Log.w(TAG, "stripOffsets should not be null.");
+            if (stripOffsets == null || stripOffsets.length == 0) {
+                Log.w(TAG, "stripOffsets should not be null or have zero length.");
                 return;
             }
-            if (stripByteCounts == null) {
-                Log.w(TAG, "stripByteCounts should not be null.");
+            if (stripByteCounts == null || stripByteCounts.length == 0) {
+                Log.w(TAG, "stripByteCounts should not be null or have zero length.");
+                return;
+            }
+            if (stripOffsets.length != stripByteCounts.length) {
+                Log.w(TAG, "stripOffsets and stripByteCounts should have same length.");
                 return;
             }
 
@@ -6728,10 +6767,18 @@
 
             int bytesRead = 0;
             int bytesAdded = 0;
+            mHasThumbnail = mHasThumbnailStrips = mAreThumbnailStripsConsecutive = true;
             for (int i = 0; i < stripOffsets.length; i++) {
                 int stripOffset = (int) stripOffsets[i];
                 int stripByteCount = (int) stripByteCounts[i];
 
+                // Check if strips are consecutive
+                // TODO: Add test for non-consecutive thumbnail image
+                if (i < stripOffsets.length - 1
+                        && stripOffset + stripByteCount != stripOffsets[i + 1]) {
+                    mAreThumbnailStripsConsecutive = false;
+                }
+
                 // Skip to offset
                 int skipBytes = stripOffset - bytesRead;
                 if (skipBytes < 0) {
@@ -6751,10 +6798,13 @@
                         stripBytes.length);
                 bytesAdded += stripBytes.length;
             }
-
-            mHasThumbnail = true;
             mThumbnailBytes = totalStripBytes;
-            mThumbnailLength = totalStripBytes.length;
+
+            if (mAreThumbnailStripsConsecutive) {
+                // Need to add mExifOffset, which is the offset to the EXIF data segment
+                mThumbnailOffset = (int) stripOffsets[0] + mExifOffset;
+                mThumbnailLength = totalStripBytes.length;
+            }
         }
     }
 
@@ -6922,8 +6972,7 @@
     }
 
     // Writes an Exif segment into the given output stream.
-    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream,
-            int exifOffsetFromBeginning) throws IOException {
+    private int writeExifSegment(ByteOrderedDataOutputStream dataOutputStream) throws IOException {
         // The following variables are for calculating each IFD tag group size in bytes.
         int[] ifdOffsets = new int[EXIF_TAGS.length];
         int[] ifdDataSizes = new int[EXIF_TAGS.length];
@@ -6982,7 +7031,9 @@
         }
 
         // Calculate IFD offsets.
-        int position = 8; // 8 bytes are for TIFF headers
+        // 8 bytes are for TIFF headers: 2 bytes (byte order) + 2 bytes (identifier) + 4 bytes
+        // (offset of IFDs)
+        int position = 8;
         for (int ifdType = 0; ifdType < EXIF_TAGS.length; ++ifdType) {
             if (!mAttributes[ifdType].isEmpty()) {
                 ifdOffsets[ifdType] = position;
@@ -6993,7 +7044,8 @@
             int thumbnailOffset = position;
             mAttributes[IFD_TYPE_THUMBNAIL].put(JPEG_INTERCHANGE_FORMAT_TAG.name,
                     ExifAttribute.createULong(thumbnailOffset, mExifByteOrder));
-            mThumbnailOffset = exifOffsetFromBeginning + thumbnailOffset;
+            // Need to add mExifOffset, which is the offset to the EXIF data segment
+            mThumbnailOffset = thumbnailOffset + mExifOffset;
             position += mThumbnailLength;
         }
 
diff --git a/fragment/fragment/api/1.3.0-alpha01.txt b/fragment/fragment/api/1.3.0-alpha01.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/1.3.0-alpha01.txt
+++ b/fragment/fragment/api/1.3.0-alpha01.txt
@@ -49,7 +49,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/current.txt b/fragment/fragment/api/current.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/current.txt
+++ b/fragment/fragment/api/current.txt
@@ -49,7 +49,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt b/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
+++ b/fragment/fragment/api/public_plus_experimental_1.3.0-alpha01.txt
@@ -49,7 +49,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/public_plus_experimental_current.txt b/fragment/fragment/api/public_plus_experimental_current.txt
index 1b14942..16edfa9 100644
--- a/fragment/fragment/api/public_plus_experimental_current.txt
+++ b/fragment/fragment/api/public_plus_experimental_current.txt
@@ -49,7 +49,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -134,7 +134,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/restricted_1.3.0-alpha01.txt b/fragment/fragment/api/restricted_1.3.0-alpha01.txt
index 190a2f2..d4e2d2f 100644
--- a/fragment/fragment/api/restricted_1.3.0-alpha01.txt
+++ b/fragment/fragment/api/restricted_1.3.0-alpha01.txt
@@ -51,7 +51,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -138,7 +138,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/api/restricted_current.txt b/fragment/fragment/api/restricted_current.txt
index 190a2f2..d4e2d2f 100644
--- a/fragment/fragment/api/restricted_current.txt
+++ b/fragment/fragment/api/restricted_current.txt
@@ -51,7 +51,7 @@
     method public final androidx.fragment.app.FragmentManager getParentFragmentManager();
     method public Object? getReenterTransition();
     method public final android.content.res.Resources getResources();
-    method public final boolean getRetainInstance();
+    method @Deprecated public final boolean getRetainInstance();
     method public Object? getReturnTransition();
     method public final androidx.savedstate.SavedStateRegistry getSavedStateRegistry();
     method public Object? getSharedElementEnterTransition();
@@ -138,7 +138,7 @@
     method public void setInitialSavedState(androidx.fragment.app.Fragment.SavedState?);
     method public void setMenuVisibility(boolean);
     method public void setReenterTransition(Object?);
-    method public void setRetainInstance(boolean);
+    method @Deprecated public void setRetainInstance(boolean);
     method public void setReturnTransition(Object?);
     method public void setSharedElementEnterTransition(Object?);
     method public void setSharedElementReturnTransition(Object?);
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
index c845318..81251da 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/ActivityLeakTest.kt
@@ -48,6 +48,7 @@
 }
 
 object Retained : LeakConfiguration() {
+    @Suppress("DEPRECATION")
     override fun commit(fragmentManager: FragmentManager) = StrictFragment().apply {
         retainInstance = true
     }.also {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
index 73bd524..cb6ced7 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/FragmentLifecycleTest.kt
@@ -517,6 +517,66 @@
             .that(viewLifecycleOwner.lifecycle.currentState).isEqualTo(Lifecycle.State.DESTROYED)
     }
 
+    /**
+     * Test to ensure childFragment gets initState() called when parent is destroyed
+     */
+    @Test
+    @UiThreadTest
+    fun childFragmentInitWhenFragmentManagerDestroyed() {
+        val viewModelStore = ViewModelStore()
+        val fc = activityRule.startupFragmentController(viewModelStore)
+        val fm = fc.supportFragmentManager
+
+        val fragment = StrictViewFragment(R.layout.simple_container)
+        fm.beginTransaction()
+            .add(android.R.id.content, fragment)
+            .commitNow()
+
+        val childFragment = StrictViewFragment()
+
+        fragment.childFragmentManager.beginTransaction()
+            .add(R.id.fragmentContainer, childFragment, "child")
+            .commitNow()
+
+        val lifecycle = childFragment.lifecycle
+
+        fc.restart(activityRule, viewModelStore, false)
+
+        assertWithMessage("ChildFragment lifecycle instance is same")
+            .that(lifecycle).isNotSameInstanceAs(childFragment.lifecycle)
+    }
+
+    /**
+     * Test to ensure childFragment gets initState() called when parent is removed
+     */
+    @Test
+    @UiThreadTest
+    fun childFragmentInitWhenParentRemoved() {
+        val viewModelStore = ViewModelStore()
+        val fc = activityRule.startupFragmentController(viewModelStore)
+        val fm = fc.supportFragmentManager
+
+        val fragment = StrictViewFragment(R.layout.simple_container)
+        fm.beginTransaction()
+            .add(android.R.id.content, fragment)
+            .commitNow()
+
+        val childFragment = StrictViewFragment()
+
+        fragment.childFragmentManager.beginTransaction()
+            .add(R.id.fragmentContainer, childFragment, "child")
+            .commitNow()
+
+        val lifecycle = childFragment.lifecycle
+
+        fm.beginTransaction()
+            .remove(fragment)
+            .commitNow()
+
+        assertWithMessage("ChildFragment lifecycle instance is same")
+            .that(lifecycle).isNotSameInstanceAs(childFragment.lifecycle)
+    }
+
     @Test
     @UiThreadTest
     fun testSetArgumentsLifecycle() {
@@ -561,6 +621,7 @@
      * Ensure that FragmentManager rejects commit() and commitNow() prior to restoring
      * saved instance state
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun addRetainedBeforeRestoreSaveState() {
@@ -601,6 +662,7 @@
     /**
      * Ensure that FragmentManager
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun addRetainedAfterSaveState() {
@@ -636,6 +698,7 @@
             .isNull()
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun popBackStackImmediateAfterSaveState() {
@@ -670,6 +733,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun popBackStackAfterSaveState() {
@@ -704,6 +768,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun popBackStackAfterManagerDestroyed() {
@@ -733,6 +798,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun commitWhenFragmentManagerNeverAttached() {
@@ -760,6 +826,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun popBackStackAndFragmentHostDestroyed() {
@@ -796,6 +863,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun commitNowWhenFragmentHostNeverAttached() {
@@ -823,6 +891,7 @@
     /**
      * When a fragment is saved in non-config, it should be restored to the same index.
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun restoreNonConfig() {
@@ -875,6 +944,7 @@
     /**
      * Check that retained fragments in the backstack correctly restored after two "configChanges"
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun retainedFragmentInBackstack() {
@@ -1220,6 +1290,7 @@
         }
     }
 
+    @Suppress("DEPRECATION")
     class OnCreateFragment : Fragment() {
         var onCreateCalled: Boolean = false
 
@@ -1242,6 +1313,7 @@
     class RetainedInflatedChildFragment : Fragment(R.layout.nested_inflated_fragment_child) {
         internal var mOnInflateCount = 0
 
+        @Suppress("DEPRECATION")
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             retainInstance = true
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
index 93a60cc..867ada4 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/SaveStateFragmentTest.kt
@@ -340,6 +340,7 @@
         fc2.shutdown(viewModelStore)
     }
 
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun testSavedInstanceStateAfterRestore() {
@@ -685,6 +686,7 @@
         val retain: Boolean = false
     ) : StrictFragment() {
 
+        @Suppress("DEPRECATION")
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
             if (savedInstanceState != null) {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
index a3840b2..43c4770 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/TargetFragmentLifeCycleTest.kt
@@ -287,6 +287,7 @@
      * Test the availability of getTargetFragment() when the target fragment is
      * retained and the referrer fragment is not retained.
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun targetFragmentRetainedNonRetained() {
@@ -323,6 +324,7 @@
      * Test the availability of getTargetFragment() when the target fragment is
      * not retained and the referrer fragment is retained.
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun targetFragmentNonRetainedRetained() {
@@ -358,6 +360,7 @@
      * Test the availability of getTargetFragment() when the target fragment is
      * retained and the referrer fragment is also retained.
      */
+    @Suppress("DEPRECATION")
     @Test
     @UiThreadTest
     fun targetFragmentRetainedRetained() {
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
index 5e24f3d..0cafc8f 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/FragmentTestActivity.kt
@@ -43,6 +43,7 @@
         val childFragment: ChildFragment
             get() = childFragmentManager.findFragmentByTag(CHILD_FRAGMENT_TAG) as ChildFragment
 
+        @Suppress("DEPRECATION")
         override fun onCreate(savedInstanceState: Bundle?) {
             super.onCreate(savedInstanceState)
 
diff --git a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
index 2c011c6..344db8a 100644
--- a/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
+++ b/fragment/fragment/src/androidTest/java/androidx/fragment/app/test/NonConfigOnStopActivity.kt
@@ -29,6 +29,7 @@
             .commitNowAllowingStateLoss()
     }
 
+    @Suppress("DEPRECATION")
     class RetainedFragment : Fragment() {
         init {
             retainInstance = 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 0128a8f..7f2dd4a 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/Fragment.java
@@ -1129,7 +1129,12 @@
      *               changes, <code>false</code> otherwise.
      *
      * @see #getRetainInstance()
+     * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
+     * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
+     * its onCleared() callback provide the signal for initial creation and final destruction of
+     * the retained state.
      */
+    @Deprecated
     public void setRetainInstance(boolean retain) {
         mRetainInstance = retain;
         if (mFragmentManager != null) {
@@ -1149,7 +1154,13 @@
      *
      * @return whether or not this fragment instance will be retained.
      * @see #setRetainInstance(boolean)
+     *
+     * @deprecated Instead of retaining the Fragment itself, use a non-retained Fragment and keep
+     * retained state in a ViewModel attached to that Fragment. The ViewModel's constructor and
+     * its onCleared() callback provide the signal for initial creation and final destruction of
+     * the retained state.
      */
+    @Deprecated
     final public boolean getRetainInstance() {
         return mRetainInstance;
     }
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 5e42a1f..0477e84 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentManager.java
@@ -1158,6 +1158,7 @@
         return mCurState >= state;
     }
 
+    @SuppressWarnings("deprecation")
     void moveToState(@NonNull Fragment f, int newState) {
         FragmentStateManager fragmentStateManager = mActive.get(f.mWho);
         if (fragmentStateManager == null) {
@@ -1325,7 +1326,7 @@
                     // fall through
                 case Fragment.ATTACHED:
                     if (newState < Fragment.ATTACHED) {
-                        fragmentStateManager.detach();
+                        fragmentStateManager.detach(mNonConfig);
                     }
             }
         }
diff --git a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
index beeee96f..f9635d4 100644
--- a/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
+++ b/fragment/fragment/src/main/java/androidx/fragment/app/FragmentStateManager.java
@@ -468,7 +468,7 @@
         }
     }
 
-    void detach() {
+    void detach(@NonNull FragmentManagerViewModel nonConfig) {
         if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
             Log.d(TAG, "movefrom ATTACHED: " + mFragment);
         }
@@ -480,7 +480,10 @@
         mFragment.mParentFragment = null;
         mFragment.mFragmentManager = null;
         boolean beingRemoved = mFragment.mRemoving && !mFragment.isInBackStack();
-        if (beingRemoved) {
+        if (beingRemoved || nonConfig.shouldDestroy(mFragment)) {
+            if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
+                Log.d(TAG, "initState called for fragment: " + mFragment);
+            }
             mFragment.initState();
         }
     }
diff --git a/gradle.properties b/gradle.properties
index 04c18ae..f3b3e79 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -10,3 +10,5 @@
 // Run multiple kotlin compilations in parallel within the same project.
 // See also https://github.com/JetBrains/kotlin/blob/1978db9d0e68a2ec29aded30a07e9c3c740c29f6/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt#L100 and https://blog.jetbrains.com/kotlin/2019/01/kotlin-1-3-20-released/
 kotlin.parallel.tasks.in.project=true
+# TODO(b/144189353) : remove android.useNewJarCreator once it stops putting illegal timestamps into jars
+android.useNewJarCreator=false
diff --git a/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java b/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
index cd2a421..926311e 100644
--- a/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
+++ b/leanback/src/main/java/androidx/leanback/widget/picker/Picker.java
@@ -726,7 +726,7 @@
             }
         }
         VerticalGridView columnView = mColumnViews.get(columnIndex);
-        if (hasFocus()) {
+        if (hasFocus() && !columnView.hasFocus()) {
             columnView.requestFocus();
         }
     }
diff --git a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
index 326272b..210b8aa 100644
--- a/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
+++ b/navigation/navigation-common/src/androidTest/java/androidx/navigation/NavDeepLinkTest.kt
@@ -160,6 +160,74 @@
             .isEqualTo(myArg)
     }
 
+    // Ensure that arguments with multiple characters in the path get matched correctly.
+    @Test
+    fun deepLinkMultiCharacterArgumentMatchWithQueryParams() {
+        val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}?myarg={myarg}"
+        val deepLink = NavDeepLink(deepLinkArgument)
+
+        val id = 211
+        val myArg = "test"
+        val matchArgs = deepLink.getMatchingArguments(
+            Uri.parse(deepLinkArgument.replace("{id}", id.toString()).replace("{myarg}", myArg)),
+            mapOf("id" to intArgument(),
+                "myarg" to stringArgument())
+        )
+        assertWithMessage("Args should not be null")
+            .that(matchArgs)
+            .isNotNull()
+        assertWithMessage("Args should contain the id")
+            .that(matchArgs?.getInt("id"))
+            .isEqualTo(id)
+        assertWithMessage("Args should contain the argument")
+            .that(matchArgs?.getString("myarg"))
+            .isEqualTo(myArg)
+    }
+
+    // Ensure that a question mark at the end of path params matches same as if there was no
+    // question mark
+    @Test
+    fun deepLinkMultipleArgumentMatchQuestionMarkNoParams() {
+        val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}?"
+        val deepLink = NavDeepLink(deepLinkArgument)
+
+        val id = 211
+        val matchArgs = deepLink.getMatchingArguments(
+            Uri.parse(deepLinkArgument.replace("{id}", id.toString())),
+            mapOf("id" to intArgument(),
+                "myarg" to stringArgument())
+        )
+        assertWithMessage("Args should not be null")
+            .that(matchArgs)
+            .isNotNull()
+        assertWithMessage("Args should contain the id")
+            .that(matchArgs?.getInt("id"))
+            .isEqualTo(id)
+    }
+
+    // Ensure that path arguments between two literals matches appropriately
+    @Test
+    fun deepLinkMultiCharacterArgumentMiddleMatchWithQueryParams() {
+        val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users/{id}/posts?myarg={myarg}"
+        val deepLink = NavDeepLink(deepLinkArgument)
+
+        val id = 2
+        val myArg = "test"
+        val matchArgs = deepLink.getMatchingArguments(
+            Uri.parse(deepLinkArgument.replace("{id}", id.toString()).replace("{myarg}", myArg)),
+            mapOf("id" to intArgument())
+        )
+        assertWithMessage("Args should not be null")
+            .that(matchArgs)
+            .isNotNull()
+        assertWithMessage("Args should contain the id")
+            .that(matchArgs?.getInt("id"))
+            .isEqualTo(id)
+        assertWithMessage("Args should contain the argument")
+            .that(matchArgs?.getString("myarg"))
+            .isEqualTo(myArg)
+    }
+
     @Test
     fun deepLinkQueryParamArgumentMatch() {
         val deepLinkArgument = "$DEEP_LINK_EXACT_HTTPS/users?id={id}"
@@ -385,7 +453,7 @@
 
         val id = 2
         val matchArgs = deepLink.getMatchingArguments(
-            Uri.parse("$DEEP_LINK_EXACT_HTTPS/users&extraParam={extraParam}"),
+            Uri.parse("$DEEP_LINK_EXACT_HTTPS/users?extraParam={extraParam}"),
             mapOf("id" to intArgument(id))
         )
         assertWithMessage("Args should not be null")
diff --git a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
index af4810b..cbfdd73 100644
--- a/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
+++ b/navigation/navigation-common/src/main/java/androidx/navigation/NavDeepLink.java
@@ -56,7 +56,11 @@
             Matcher matcher = Pattern.compile("(\\?)").matcher(uri);
             if (matcher.find()) {
                 buildPathRegex(uri.substring(0, matcher.start()), uriRegex, fillInPattern);
-                uriRegex.append("(.+)?");
+                // Match either the end of string if all params are optional or match the
+                // question mark and 0 or more characters after it
+                // We do not use '.*' here because the finalregex would replace it with a quoted
+                // version below.
+                uriRegex.append("($|(\\?(.)*))");
             }
             mExactDeepLink = false;
             for (String paramName : parameterizedUri.getQueryParameterNames()) {
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
index 36cc993..04e24e3 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/ArgumentsGenerationTask.kt
@@ -22,13 +22,16 @@
 import com.google.gson.reflect.TypeToken
 import org.gradle.api.DefaultTask
 import org.gradle.api.GradleException
+import org.gradle.api.file.FileCollection
 import org.gradle.api.provider.Provider
 import org.gradle.api.resources.TextResource
 import org.gradle.api.tasks.Input
 import org.gradle.api.tasks.InputFiles
 import org.gradle.api.tasks.OutputDirectory
 import org.gradle.api.tasks.TaskAction
-import org.gradle.api.tasks.incremental.IncrementalTaskInputs
+import org.gradle.work.ChangeType
+import org.gradle.work.Incremental
+import org.gradle.work.InputChanges
 import java.io.File
 
 private const val MAPPING_FILE = "file_mappings.json"
@@ -50,8 +53,9 @@
     @get:OutputDirectory
     lateinit var outputDir: File
 
+    @get:Incremental
     @get:InputFiles
-    lateinit var navigationFiles: Provider<List<File>>
+    lateinit var navigationFiles: FileCollection
 
     @get:OutputDirectory
     lateinit var incrementalFolder: File
@@ -90,7 +94,7 @@
     }
 
     @TaskAction
-    internal fun taskAction(inputs: IncrementalTaskInputs) {
+    internal fun taskAction(inputs: InputChanges) {
         if (inputs.isIncremental) {
             doIncrementalTaskAction(inputs)
         } else {
@@ -106,16 +110,21 @@
         if (!outputDir.exists() && !outputDir.mkdirs()) {
             throw GradleException("Failed to create directory for navigation arguments")
         }
-        val (mappings, errors) = generateArgs(navigationFiles.get(), outputDir)
+        val (mappings, errors) = generateArgs(navigationFiles.files, outputDir)
         writeMappings(mappings)
         failIfErrors(errors)
     }
 
-    private fun doIncrementalTaskAction(inputs: IncrementalTaskInputs) {
+    private fun doIncrementalTaskAction(inputs: InputChanges) {
         val modifiedFiles = mutableSetOf<File>()
         val removedFiles = mutableSetOf<File>()
-        inputs.outOfDate { change -> modifiedFiles.add(change.file) }
-        inputs.removed { change -> removedFiles.add(change.file) }
+        inputs.getFileChanges(navigationFiles).forEach { change ->
+            if (change.changeType == ChangeType.MODIFIED || change.changeType == ChangeType.ADDED) {
+                modifiedFiles.add(change.file)
+            } else if (change.changeType == ChangeType.REMOVED) {
+                removedFiles.add(change.file)
+            }
+        }
 
         val oldMapping = readMappings()
         val (newMapping, errors) = generateArgs(modifiedFiles, outputDir)
diff --git a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
index 17587b9..e53e45c 100644
--- a/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
+++ b/navigation/navigation-safe-args-gradle-plugin/src/main/kotlin/androidx/navigation/safeargs/gradle/SafeArgsPlugin.kt
@@ -25,6 +25,7 @@
 import org.gradle.api.GradleException
 import org.gradle.api.Plugin
 import org.gradle.api.Project
+import org.gradle.api.file.FileCollection
 import org.gradle.api.provider.ProviderFactory
 import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension
 import java.io.File
@@ -70,7 +71,7 @@
             ) { task ->
                 setApplicationId(task, variant)
                 task.rFilePackage = variant.rFilePackage()
-                task.navigationFiles = navigationFiles(variant)
+                task.navigationFiles = navigationFiles(variant, project)
                 task.outputDir = File(project.buildDir, "$GENERATED_PATH/${variant.dirName}")
                 task.incrementalFolder = File(project.buildDir, "$INCREMENTAL_PATH/${task.name}")
                 task.useAndroidX = (project.findProperty("android.useAndroidX") == "true").also {
@@ -108,18 +109,21 @@
         parsed.getProperty("@package").toString()
     }
 
-    private fun navigationFiles(variant: BaseVariant) = providerFactory.provider {
-        variant.sourceSets
-            .flatMap { it.resDirectories }
-            .mapNotNull {
-                File(it, "navigation").let { navFolder ->
-                    if (navFolder.exists() && navFolder.isDirectory) navFolder else null
+    private fun navigationFiles(variant: BaseVariant, project: Project): FileCollection {
+        val fileProvider = providerFactory.provider {
+            variant.sourceSets
+                .flatMap { it.resDirectories }
+                .mapNotNull {
+                    File(it, "navigation").let { navFolder ->
+                        if (navFolder.exists() && navFolder.isDirectory) navFolder else null
+                    }
                 }
-            }
-            .flatMap { navFolder -> navFolder.listFiles().asIterable() }
-            .filter { file -> file.isFile }
-            .groupBy { file -> file.name }
-            .map { entry -> entry.value.last() }
+                .flatMap { navFolder -> navFolder.listFiles().asIterable() }
+                .filter { file -> file.isFile }
+                .groupBy { file -> file.name }
+                .map { entry -> entry.value.last() }
+        }
+        return project.files(fileProvider)
     }
 }
 
diff --git a/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/api/current.txt b/recyclerview/recyclerview-selection/api/current.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/current.txt
+++ b/recyclerview/recyclerview-selection/api/current.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/public_plus_experimental_1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt b/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
index cedd7b9..f80bfd39 100644
--- a/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
+++ b/recyclerview/recyclerview-selection/api/public_plus_experimental_current.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -83,13 +83,13 @@
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -98,7 +98,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -111,17 +111,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -149,9 +149,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt b/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
index 7058b89..f944138 100644
--- a/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
+++ b/recyclerview/recyclerview-selection/api/restricted_1.1.0-alpha07.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -81,16 +81,17 @@
     method public void onChanged();
   }
 
+
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -99,7 +100,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -112,17 +113,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -150,9 +151,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/api/restricted_current.txt b/recyclerview/recyclerview-selection/api/restricted_current.txt
index 7058b89..f944138 100644
--- a/recyclerview/recyclerview-selection/api/restricted_current.txt
+++ b/recyclerview/recyclerview-selection/api/restricted_current.txt
@@ -3,7 +3,7 @@
 
   public abstract class BandPredicate {
     ctor public BandPredicate();
-    method public abstract boolean canInitiate(android.view.MotionEvent!);
+    method public abstract boolean canInitiate(android.view.MotionEvent);
   }
 
   public static final class BandPredicate.EmptyArea extends androidx.recyclerview.selection.BandPredicate {
@@ -81,16 +81,17 @@
     method public void onChanged();
   }
 
+
   public class Selection<K> implements java.lang.Iterable<K> {
     method public boolean contains(K?);
     method public boolean isEmpty();
-    method public java.util.Iterator<K!>! iterator();
+    method public java.util.Iterator<K!> iterator();
     method public int size();
   }
 
   public final class SelectionPredicates {
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectAnything();
-    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>! createSelectSingleAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectAnything();
+    method public static <K> androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!> createSelectSingleAnything();
   }
 
   public abstract class SelectionTracker<K> {
@@ -99,7 +100,7 @@
     method public abstract boolean clearSelection();
     method public abstract void copySelection(androidx.recyclerview.selection.MutableSelection<K!>);
     method public abstract boolean deselect(K);
-    method public abstract androidx.recyclerview.selection.Selection<K!>! getSelection();
+    method public abstract androidx.recyclerview.selection.Selection<K!> getSelection();
     method public abstract boolean hasSelection();
     method public abstract boolean isSelected(K?);
     method public abstract void onRestoreInstanceState(android.os.Bundle?);
@@ -112,17 +113,17 @@
 
   public static final class SelectionTracker.Builder<K> {
     ctor public SelectionTracker.Builder(String, androidx.recyclerview.widget.RecyclerView, androidx.recyclerview.selection.ItemKeyProvider<K!>, androidx.recyclerview.selection.ItemDetailsLookup<K!>, androidx.recyclerview.selection.StorageStrategy<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker<K!>! build();
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandOverlay(@DrawableRes int);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withBandPredicate(androidx.recyclerview.selection.BandPredicate);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withGestureTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
-    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withPointerTooltypes(int...);
-    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!>! withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker<K!> build();
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandOverlay(@DrawableRes int);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withBandPredicate(androidx.recyclerview.selection.BandPredicate);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withFocusDelegate(androidx.recyclerview.selection.FocusDelegate<K!>);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withGestureTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnContextClickListener(androidx.recyclerview.selection.OnContextClickListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnDragInitiatedListener(androidx.recyclerview.selection.OnDragInitiatedListener);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOnItemActivatedListener(androidx.recyclerview.selection.OnItemActivatedListener<K!>);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withOperationMonitor(androidx.recyclerview.selection.OperationMonitor);
+    method @Deprecated public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withPointerTooltypes(int...);
+    method public androidx.recyclerview.selection.SelectionTracker.Builder<K!> withSelectionPredicate(androidx.recyclerview.selection.SelectionTracker.SelectionPredicate<K!>);
   }
 
   public abstract static class SelectionTracker.SelectionObserver<K> {
@@ -150,9 +151,9 @@
     ctor public StorageStrategy(Class<K!>);
     method public abstract android.os.Bundle asBundle(androidx.recyclerview.selection.Selection<K!>);
     method public abstract androidx.recyclerview.selection.Selection<K!>? asSelection(android.os.Bundle);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!>! createLongStorage();
-    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!>! createParcelableStorage(Class<K!>!);
-    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!>! createStringStorage();
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.Long!> createLongStorage();
+    method public static <K extends android.os.Parcelable> androidx.recyclerview.selection.StorageStrategy<K!> createParcelableStorage(Class<K!>);
+    method public static androidx.recyclerview.selection.StorageStrategy<java.lang.String!> createStringStorage();
   }
 
 }
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
index ca0e11f..bc0cbc98 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/BandSelectionHelperTest.java
@@ -16,18 +16,20 @@
 
 package androidx.recyclerview.selection;
 
-import static androidx.recyclerview.selection.testing.TestEvents.Mouse;
-import static androidx.recyclerview.selection.testing.TestEvents.Touch;
-
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
+import androidx.recyclerview.selection.GridModel.GridHost;
 import androidx.recyclerview.selection.testing.TestAdapter;
 import androidx.recyclerview.selection.testing.TestAutoScroller;
 import androidx.recyclerview.selection.testing.TestBandPredicate;
 import androidx.recyclerview.selection.testing.TestData;
+import androidx.recyclerview.selection.testing.TestEvents;
 import androidx.recyclerview.selection.testing.TestItemKeyProvider;
 import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -46,135 +48,148 @@
 
     private List<String> mItems;
     private BandSelectionHelper<String> mBandController;
-    private boolean mIsActive;
-    private TestBandHost mBandHost;
+    private TestHostEnvironment mHostEnv;
     private TestBandPredicate mBandPredicate;
     private TestAdapter<String> mAdapter;
     private SelectionTracker<String> mTracker;
+    TestItemKeyProvider<String> mKeyProvider;
+
+    // Builder for all drag events. Twiddle the button's and other stuff as needed.
+    TestEvents.Builder mBaseEvent;
 
     @Before
     public void setup() throws Exception {
         mItems = TestData.createStringData(10);
-        mIsActive = false;
         mAdapter = new TestAdapter<>();
         mAdapter.updateTestModelIds(mItems);
-        mBandHost = new TestBandHost();
+        mKeyProvider = new TestItemKeyProvider<>(ItemKeyProvider.SCOPE_MAPPED, mAdapter);
+        mHostEnv = new TestHostEnvironment();
         mBandPredicate = new TestBandPredicate();
-        ItemKeyProvider<String> keyProvider =
-                new TestItemKeyProvider<>(ItemKeyProvider.SCOPE_MAPPED, mAdapter);
+
         OperationMonitor operationMonitor = new OperationMonitor();
 
         mTracker = new DefaultSelectionTracker<>(
                 "band-selection-test",
-                keyProvider,
+                mKeyProvider,
                 SelectionPredicates.createSelectAnything(),
                 StorageStrategy.createStringStorage());
 
-        EventBridge.install(mAdapter, mTracker, keyProvider);
+        EventBridge.install(mAdapter, mTracker, mKeyProvider);
         FocusDelegate<String> focusDelegate = FocusDelegate.dummy();
 
         mBandController = new BandSelectionHelper<String>(
-                mBandHost,
+                mHostEnv,
                 new TestAutoScroller(),
-                keyProvider,
+                mKeyProvider,
                 mTracker,
                 mBandPredicate,
                 focusDelegate,
-                operationMonitor) {
-            @Override
-            public boolean isActive() {
-                return mIsActive;
-            }
-        };
+                operationMonitor);
+
+        // No buttons pressed. Tests can fiddle with this as needed.
+        mBaseEvent = TestEvents.builder()
+                .location(1, 1)
+                .mouse()
+                .move();
     }
 
-    @Test
-    public void testReset_HidesBand() {
-        mIsActive = true;
-        mBandController.reset();
-        mBandHost.assertBandHidden();
+    private boolean startBandSelect() {
+        return startBandSelect(mBaseEvent.primary().build());
+    }
+
+    // Allows tests to pass an event that might not start band selection.
+    private boolean startBandSelect(MotionEvent e) {
+        mBandController.onInterceptTouchEvent(null, e);
+        return mBandController.isResetRequired();
+    }
+
+    private boolean stopBandSelect() {
+        mBandController.onInterceptTouchEvent(null, mBaseEvent.up().build());
+        return !mBandController.isResetRequired();
     }
 
     @Test
     public void testStart() {
-        assertTrue(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
+        assertTrue(startBandSelect());
     }
 
     @Test
-    public void testStart_NoItems() {
+    public void testStart_RejectedByPredicate() {
+        mBandPredicate.setCanInitiate(false);
+        assertFalse(startBandSelect());
+    }
+
+    @Test
+    public void testRequiresReset() {
+        assertFalse(mBandController.isResetRequired());
+        startBandSelect();
+        assertTrue(mBandController.isResetRequired());
+    }
+
+    @Test
+    public void testReset() {
+        startBandSelect();
+        mBandController.reset();
+        assertFalse(mBandController.isResetRequired());
+    }
+
+    @Test
+    public void testReset_HidesBand() {
+        startBandSelect();
+        mBandController.reset();
+        mHostEnv.assertBandHidden();
+    }
+
+    @Test
+    public void testStart_IgnoresNonPrimaryDragEvents() {
+        // W/ no buttons pressed.
+        assertFalse(startBandSelect(mBaseEvent.build()));
+
+        // With wrong buttons pressed.
+        assertFalse(startBandSelect(mBaseEvent.secondary().build()));
+        assertFalse(startBandSelect(mBaseEvent.tertiary().build()));
+    }
+
+    @Test
+    public void testStart_IgnoresNonMoveEvents() {
+        // Primary button has to be pressed for controller to pay attention to an event.
+        mBaseEvent.primary();
+
+        // Override MOVE action with UP and DOWN to verify they are ignored.
+        assertFalse(startBandSelect(mBaseEvent.up().build()));
+        assertFalse(startBandSelect(mBaseEvent.down().build()));
+    }
+
+    @Test
+    public void testStarts_NoItems() {
         // Band selection can happen in a view without any items.
         mAdapter.updateTestModelIds(Collections.<String>emptyList());
-        assertTrue(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
-    }
 
-    @Test
-    public void testNoStart_NoButtons() {
-        assertFalse(mBandController.shouldStart(Mouse.MOVE));
-    }
-
-    @Test
-    public void testNoStart_SecondaryButton() {
-        assertFalse(mBandController.shouldStart(Mouse.SECONDARY_DRAG));
-    }
-
-    @Test
-    public void testNoStart_TertiaryButton() {
-        assertFalse(mBandController.shouldStart(Mouse.TERTIARY_DRAG));
-    }
-
-    @Test
-    public void testNoStart_Touch() {
-        assertFalse(mBandController.shouldStart(Touch.MOVE));
-    }
-
-    @Test
-    public void testNoStart_RejectedByPredicate() {
-        mBandPredicate.setCanInitiate(false);
-        assertFalse(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
-    }
-
-    @Test
-    public void testNoStart() {
-        // only starts on
-        assertFalse(mBandController.shouldStart(Mouse.DOWN));
-        assertFalse(mBandController.shouldStart(Mouse.UP));
-        assertFalse(mBandController.shouldStart(Mouse.POINTER_UP));
-        assertFalse(mBandController.shouldStart(Mouse.POINTER_DOWN));
-    }
-
-
-    @Test
-    public void testNoStart_AlreadyStarted() {
-        mIsActive = true;
-        assertFalse(mBandController.shouldStart(Mouse.PRIMARY_DRAG));
+        assertTrue(startBandSelect());
     }
 
     @Test
     public void testStops() {
-        mIsActive = true;
-        assertTrue(mBandController.shouldStop(Mouse.UP));
+        startBandSelect();
+        assertTrue(stopBandSelect());
     }
 
     @Test
-    public void testNoStop_Down() {
-        mIsActive = true;
-        // Not really sure when this would, happen, maybe a secondary
-        // or tertiary button press while dragging?
-        assertFalse(mBandController.shouldStop(Touch.DOWN));  // :) Touch Down!
+    public void testStop_IgnoresUpWhenNotStarted() {
+        assertTrue(stopBandSelect());
     }
 
-    @Test
-    public void testNoStop_NotActive() {
-        assertFalse(mBandController.shouldStop(Mouse.UP));
-        assertFalse(mBandController.shouldStop(Touch.MOVE));
-    }
+    // GridHost extends BandHost. We satisfy both by implementing GridHost.
+    private final class TestHostEnvironment extends GridHost<String> {
 
-    private final class TestBandHost extends BandSelectionHelper.BandHost<String> {
         private boolean mBandHidden;
 
         @Override
         GridModel<String> createGridModel() {
-            throw new UnsupportedOperationException();
+            return new GridModel<String>(
+                    this,
+                    mKeyProvider,
+                    SelectionPredicates.createSelectAnything());
         }
 
         @Override
@@ -194,6 +209,42 @@
 
         @Override
         void addOnScrollListener(OnScrollListener listener) {
+            // ignored for testing
+        }
+
+        @Override
+        void removeOnScrollListener(@NonNull OnScrollListener listener) {
+            // ignored for testing
+        }
+
+        @Override
+        Point createAbsolutePoint(@NonNull Point relativePoint) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        Rect getAbsoluteRectForChildViewAt(int index) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        int getAdapterPositionAt(int index) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        int getColumnCount() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        int getVisibleChildCount() {
+            return 0;
+        }
+
+        @Override
+        boolean hasView(int adapterPosition) {
+            throw new UnsupportedOperationException();
         }
     }
 }
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
index 5a0e600..8a81ec7 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/DefaultSelectionTrackerTest.java
@@ -24,6 +24,7 @@
 import android.os.Bundle;
 import android.util.SparseBooleanArray;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
 import androidx.recyclerview.selection.testing.Bundles;
 import androidx.recyclerview.selection.testing.SelectionProbe;
@@ -68,7 +69,7 @@
         mSelectionPredicate = new SelectionPredicate<String>() {
 
             @Override
-            public boolean canSetStateForKey(String id, boolean nextState) {
+            public boolean canSetStateForKey(@NonNull String id, boolean nextState) {
                 return !nextState || !mIgnored.contains(id);
             }
 
@@ -219,6 +220,70 @@
     }
 
     @Test
+    public void testRequiresReset_ForSelection() {
+        mTracker.select(mItems.get(1));
+
+        assertTrue(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testRequiresReset_ForProvisionalSelection() {
+        Set<String> items = new HashSet<>();
+        items.add(mItems.get(1));
+
+        mTracker.setProvisionalSelection(items);
+
+        assertTrue(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testRequiresReset_ForEstablishedRange() {
+        mTracker.startRange(15);
+
+        assertTrue(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testReset_ForSelection() {
+        mTracker.select(mItems.get(1));
+
+        mTracker.reset();
+        assertFalse(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testReset_ForProvisionalSelection() {
+        Set<String> items = new HashSet<>();
+        items.add(mItems.get(1));
+        mTracker.setProvisionalSelection(items);
+
+        mTracker.reset();
+        assertFalse(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testReset_Combined() {
+        mTracker.select(mItems.get(1));
+
+        Set<String> items = new HashSet<>();
+        items.add(mItems.get(1));
+        mTracker.setProvisionalSelection(items);
+
+        mTracker.startRange(15);
+
+        mTracker.reset();
+        assertFalse(mTracker.isResetRequired());
+    }
+
+    @Test
+    public void testReset_ForEstablishedRange() {
+        mTracker.startRange(15);
+
+        mTracker.reset();
+        assertFalse(mTracker.isResetRequired());
+    }
+
+    @Test
     public void testRangeSelection() {
         mTracker.startRange(15);
         mTracker.extendRange(19);
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
index 11db0a1..f3944cf 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/GestureSelectionHelperTest.java
@@ -78,6 +78,19 @@
     }
 
     @Test
+    public void testRequiresReset() {
+        mHelper.start();
+        assertTrue(mHelper.isResetRequired());
+    }
+
+    @Test
+    public void testReset() {
+        mHelper.start();
+        mHelper.reset();
+        assertFalse(mHelper.isResetRequired());
+    }
+
+    @Test
     public void testResetsOnCancel() {
         assertFalse(mHelper.onInterceptTouchEvent(null, MOVE));
     }
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
index a6568f9..a25a5d1 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/OperationMonitorTest.java
@@ -75,6 +75,19 @@
         mListener.assertLastState(false);
     }
 
+    @Test
+    public void testRequiresReset() {
+        mMonitor.start();
+        assertTrue(mMonitor.asResettable().isResetRequired());
+    }
+
+    @Test
+    public void testReset() {
+        mMonitor.start();
+        mMonitor.asResettable().reset();
+        assertFalse(mMonitor.asResettable().isResetRequired());
+    }
+
     private static final class TestListener implements OperationMonitor.OnChangeListener {
 
         private boolean mLastState;
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
index 704c8aa..8ff3c2b 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/ResetMangerTest.java
@@ -18,7 +18,7 @@
 
 import androidx.recyclerview.selection.testing.TestData;
 import androidx.recyclerview.selection.testing.TestEvents;
-import androidx.recyclerview.selection.testing.TestRunnable;
+import androidx.recyclerview.selection.testing.TestResettable;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -39,51 +39,74 @@
     private static final List<String> ITEMS = TestData.createStringData(100);
 
     private ResetManager<String> mManager;
-    private TestRunnable mListern1;
-    private TestRunnable mListern2;
+    private TestResettable mResettable1;
+    private TestResettable mResettable2;
 
     @Before
     public void setUp() {
         mManager = new ResetManager();
-        mListern1 = new TestRunnable();
-        mListern2 = new TestRunnable();
-        mManager.addResetListener(mListern1);
-        mManager.addResetListener(mListern2);
+        mResettable1 = new TestResettable(true);
+        mResettable2 = new TestResettable(true);
+        mManager.addResetHandler(mResettable1);
+        mManager.addResetHandler(mResettable2);
     }
 
     @Test
     public void notifiesListenersOnCancelEvent() {
         mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Unknown.CANCEL);
-        mListern1.assertRun();
-        mListern2.assertRun();
+        mResettable1.assertReset();
+        mResettable2.assertReset();
+    }
+
+    @Test
+    public void notifiesListenersOnSelectionCleared() {
+        mManager.getSelectionObserver().onSelectionCleared();
+        mResettable1.assertReset();
+        mResettable2.assertReset();
+    }
+
+    @Test
+    public void notifiesListenersOnSelectionRefreshed() {
+        mManager.getSelectionObserver().onSelectionRefresh();
+        mResettable1.assertReset();
+        mResettable2.assertReset();
+    }
+
+    @Test
+    public void notifiesListenersOnSelectionRestored() {
+        mManager.getSelectionObserver().onSelectionRestored();
+        mResettable1.assertReset();
+        mResettable2.assertReset();
     }
 
     @Test
     public void ignoresNonCancelEvents() {
         mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Mouse.CLICK);
         mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Touch.TAP);
-        mListern1.assertNotRun();
-        mListern2.assertNotRun();
+        mResettable1.assertNotReset();
+        mResettable2.assertNotReset();
     }
 
+
     @Test
-    public void notifiesListenersOnSelectionCleared() {
+    public void ignoresWhenResetNotRequired() {
+        mResettable1.setResetRequired(false);
+        mResettable2.setResetRequired(false);
+
+        mManager.getInputListener().onInterceptTouchEvent(null, TestEvents.Unknown.CANCEL);
+        mResettable1.assertNotReset();
+        mResettable2.assertNotReset();
+
         mManager.getSelectionObserver().onSelectionCleared();
-        mListern1.assertRun();
-        mListern2.assertRun();
-    }
+        mResettable1.assertNotReset();
+        mResettable2.assertNotReset();
 
-    @Test
-    public void notifiesListenersOnSelectionRefreshed() {
         mManager.getSelectionObserver().onSelectionRefresh();
-        mListern1.assertRun();
-        mListern2.assertRun();
-    }
+        mResettable1.assertNotReset();
+        mResettable2.assertNotReset();
 
-    @Test
-    public void notifiesListenersOnSelectionRestored() {
         mManager.getSelectionObserver().onSelectionRestored();
-        mListern1.assertRun();
-        mListern2.assertRun();
+        mResettable1.assertNotReset();
+        mResettable2.assertNotReset();
     }
 }
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
index ca21b9c..a03bd28 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestBandPredicate.java
@@ -18,6 +18,7 @@
 
 import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.BandPredicate;
 
 public class TestBandPredicate extends BandPredicate {
@@ -29,7 +30,7 @@
     }
 
     @Override
-    public boolean canInitiate(MotionEvent e) {
+    public boolean canInitiate(@NonNull MotionEvent e) {
         return mCanInitiate;
     }
 
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
index 88c1ca9..44dbe1b 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetails.java
@@ -18,6 +18,7 @@
 
 import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -55,7 +56,7 @@
     }
 
     @Override
-    public boolean inDragRegion(MotionEvent event) {
+    public boolean inDragRegion(@NonNull MotionEvent event) {
         return mInDragRegion;
     }
 
@@ -90,7 +91,7 @@
     }
 
     @Override
-    public boolean inSelectionHotspot(MotionEvent e) {
+    public boolean inSelectionHotspot(@NonNull MotionEvent e) {
         return mInSelectionHotspot;
     }
 }
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
index 82c2119..33294d9 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestItemDetailsLookup.java
@@ -18,6 +18,7 @@
 
 import android.view.MotionEvent;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.ItemDetailsLookup;
 
 import javax.annotation.Nullable;
@@ -30,7 +31,7 @@
     private @Nullable TestItemDetails mItem;
 
     @Override
-    public @Nullable ItemDetails<String> getItemDetails(MotionEvent e) {
+    public @Nullable ItemDetails<String> getItemDetails(@NonNull MotionEvent e) {
         return mItem;
     }
 
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java
new file mode 100644
index 0000000..09a3e28
--- /dev/null
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestResettable.java
@@ -0,0 +1,58 @@
+/*
+ * 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.recyclerview.selection.testing;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import androidx.recyclerview.selection.Resettable;
+
+public final class TestResettable implements Resettable {
+
+    private boolean mResetRequired;
+    private boolean mWasReset;
+
+    public TestResettable() {
+        // mRequiresReset defaults to false.
+    }
+
+    public TestResettable(boolean requiresReset) {
+        mResetRequired = requiresReset;
+    }
+
+    @Override
+    public void reset() {
+        mWasReset = true;
+    }
+
+    public void setResetRequired(boolean required) {
+        mResetRequired = required;
+    }
+
+    @Override
+    public boolean isResetRequired() {
+        return mResetRequired;
+    }
+
+    public void assertReset() {
+        assertTrue(mWasReset);
+    }
+
+    public void assertNotReset() {
+        assertFalse(mWasReset);
+    }
+}
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
index fbe06fe..49fba73 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionObserver.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
 
 import java.util.HashSet;
@@ -51,7 +52,7 @@
     }
 
     @Override
-    public void onItemStateChanged(K key, boolean selected) {
+    public void onItemStateChanged(@NonNull K key, boolean selected) {
         if (selected) {
             if (mStrict) {
                 assertNotSelected(key);
diff --git a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
index 32f16ee..de284b5 100644
--- a/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
+++ b/recyclerview/recyclerview-selection/src/androidTest/java/androidx/recyclerview/selection/testing/TestSelectionPredicate.java
@@ -16,6 +16,7 @@
 
 package androidx.recyclerview.selection.testing;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
 
 public final class TestSelectionPredicate<K> extends SelectionPredicate<K> {
@@ -37,7 +38,7 @@
     }
 
     @Override
-    public boolean canSetStateForKey(K key, boolean nextState) {
+    public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
         return mValue;
     }
 
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
index 5be26dd..3ec4ccb 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandPredicate.java
@@ -40,7 +40,7 @@
     /**
      * @return true if band selection can be initiated in response to the {@link MotionEvent}.
      */
-    public abstract boolean canInitiate(MotionEvent e);
+    public abstract boolean canInitiate(@NonNull MotionEvent e);
 
     @SuppressWarnings("WeakerAccess") /* synthetic access */
     static boolean hasSupportedLayoutManager(@NonNull RecyclerView recyclerView) {
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
index 5e70fd6..591d127 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/BandSelectionHelper.java
@@ -28,7 +28,6 @@
 import androidx.annotation.DrawableRes;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
 import androidx.recyclerview.selection.SelectionTracker.SelectionPredicate;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.recyclerview.widget.RecyclerView.OnItemTouchListener;
@@ -50,7 +49,7 @@
  *
  * @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
  */
-class BandSelectionHelper<K> implements OnItemTouchListener {
+class BandSelectionHelper<K> implements OnItemTouchListener, Resettable {
 
     static final String TAG = "BandSelectionHelper";
     static final boolean DEBUG = false;
@@ -140,18 +139,18 @@
                 lock);
     }
 
-    @VisibleForTesting
-    boolean isActive() {
-        boolean active = mModel != null;
-        if (DEBUG) mLock.checkStarted(active);
-        return active;
+    private boolean isActive() {
+        boolean started = mModel != null;
+        if (DEBUG) mLock.checkStarted(started);
+        return started;
     }
 
     /**
      * Clients must call reset when there are any material changes to the layout of items
      * in RecyclerView.
      */
-    void reset() {
+    @Override
+    public void reset() {
         if (!isActive()) {
             if (DEBUG) Log.d(TAG, "Ignoring reset request, not active.");
             return;
@@ -170,8 +169,12 @@
         // mLock is reset by reset manager.
     }
 
-    @VisibleForTesting
-    boolean shouldStart(@NonNull MotionEvent e) {
+    @Override
+    public boolean isResetRequired() {
+        return isActive();
+    }
+
+    private boolean shouldStart(@NonNull MotionEvent e) {
         // b/30146357 && b/23793622. onInterceptTouchEvent does not dispatch events to onTouchEvent
         // unless the event is != ACTION_DOWN. Thus, we need to actually start band selection when
         // mouse moves.
@@ -181,8 +184,7 @@
                 && !isActive();
     }
 
-    @VisibleForTesting
-    boolean shouldStop(@NonNull MotionEvent e) {
+    private boolean shouldStop(@NonNull MotionEvent e) {
         return isActive() && MotionEvents.isActionUp(e);
     }
 
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
index 85d695b..61985cf 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/DefaultSelectionTracker.java
@@ -50,7 +50,7 @@
  */
 @RestrictTo(LIBRARY)
 @SuppressWarnings("unchecked")
-public class DefaultSelectionTracker<K> extends SelectionTracker<K> {
+public class DefaultSelectionTracker<K> extends SelectionTracker<K> implements Resettable {
 
     private static final String TAG = "DefaultSelectionTracker";
     private static final String EXTRA_SELECTION_PREFIX = "androidx.recyclerview.selection";
@@ -106,13 +106,16 @@
         mObservers.add(callback);
     }
 
+    /**
+     * @return true if there is a primary or previsional selection.
+     */
     @Override
     public boolean hasSelection() {
         return !mSelection.isEmpty();
     }
 
     @Override
-    public Selection<K> getSelection() {
+    public @NonNull Selection<K> getSelection() {
         return mSelection;
     }
 
@@ -157,8 +160,6 @@
 
     @Override
     public boolean clearSelection() {
-        // Short circuiting guards against infinite recurision during reset.
-        // See companion test for some supporting details.
         if (!hasSelection()) {
             if (DEBUG) Log.d(TAG, "Ignoring clearSelection request. No selection.");
             return false;
@@ -199,13 +200,19 @@
         return prevSelection;
     }
 
-    void reset() {
+    @Override
+    public void reset() {
         if (DEBUG) Log.d(TAG, "Received reset request.");
         clearSelection();
         mRange = null;
     }
 
     @Override
+    public boolean isResetRequired() {
+        return hasSelection() || isRangeActive();
+    }
+
+    @Override
     public boolean select(@NonNull K key) {
         checkArgument(key != null);
 
@@ -377,7 +384,7 @@
     }
 
     @Override
-    protected AdapterDataObserver getAdapterDataObserver() {
+    protected @NonNull AdapterDataObserver getAdapterDataObserver() {
         return mAdapterObserver;
     }
 
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
index 763d789..046a8af 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/GestureSelectionHelper.java
@@ -37,7 +37,7 @@
  * when used in conjunction with RecyclerView and other classes in the ReyclerView
  * selection support package.
  */
-final class GestureSelectionHelper implements OnItemTouchListener {
+final class GestureSelectionHelper implements OnItemTouchListener, Resettable {
 
     private static final String TAG = "GestureSelectionHelper";
 
@@ -162,12 +162,18 @@
     /**
      * Immediately "Stops" active gesture selection, and resets all related state.
      */
+    @Override
     public void reset() {
         if (DEBUG) Log.d(TAG, "Received reset request.");
         mStarted = false;
         mScroller.reset();
     }
 
+    @Override
+    public boolean isResetRequired() {
+        return mStarted;
+    }
+
     private void endSelection() {
         mStarted = false;
         mScroller.reset();
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
index e2ac2e1..1cdf135 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ItemDetailsLookup.java
@@ -44,7 +44,7 @@
  *       mRecyclerView = recyclerView;
  *   }
  *
- *   public ItemDetails<Uri> getItemDetails(MotionEvent e) {
+ *   public @Nullable ItemDetails<Uri> getItemDetails(@NonNull MotionEvent e) {
  *       View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
  *       if (view != null) {
  *           ViewHolder holder = mRecyclerView.getChildViewHolder(view);
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
index d074df5..53d4b82 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/OperationMonitor.java
@@ -16,6 +16,7 @@
 
 package androidx.recyclerview.selection;
 
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
 import static androidx.core.util.Preconditions.checkArgument;
 import static androidx.core.util.Preconditions.checkState;
 import static androidx.recyclerview.selection.Shared.DEBUG;
@@ -24,6 +25,7 @@
 
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
+import androidx.annotation.RestrictTo;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -45,8 +47,26 @@
 
     private static final String TAG = "OperationMonitor";
 
+    private final List<OnChangeListener> mListeners = new ArrayList<>();
+
+    // Ideally OperationMonitor would implement Resettable
+    // directly, but Metalava couldn't understand that
+    // `OperationMonitor` was public API while `Resettable` was
+    // not. This is our klunkuy workaround.
+    private final Resettable mResettable = new Resettable() {
+
+        @Override
+        public boolean isResetRequired() {
+            return OperationMonitor.this.isResetRequired();
+        }
+
+        @Override
+        public void reset() {
+            OperationMonitor.this.reset();
+        }
+    };
+
     private int mNumOps = 0;
-    private List<OnChangeListener> mListeners = new ArrayList<>();
 
     @MainThread
     synchronized void start() {
@@ -74,6 +94,8 @@
         }
     }
 
+    /** @hide */
+    @RestrictTo(LIBRARY)
     @MainThread
     synchronized void reset() {
         if (DEBUG) Log.d(TAG, "Received reset request.");
@@ -84,10 +106,15 @@
         notifyStateChanged();
     }
 
+    /** @hide */
+    @RestrictTo(LIBRARY)
+    synchronized boolean isResetRequired() {
+        return isStarted();
+    }
+
     /**
      * @return true if there are any running operations.
      */
-    @SuppressWarnings("unused")
     public synchronized boolean isStarted() {
         return mNumOps > 0;
     }
@@ -126,6 +153,15 @@
     }
 
     /**
+     * Work around b/139109223.
+     * @hide
+     */
+    @RestrictTo(LIBRARY)
+    @NonNull Resettable asResettable() {
+        return mResettable;
+    }
+
+    /**
      * Listen to changes in operation status. Authors should avoid
      * changing the Adapter model while there are active operations.
      */
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
index 61a91b3..009db1b 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/ResetManager.java
@@ -30,11 +30,9 @@
 import java.util.List;
 
 /**
- * Manager resetting various states across the lib.
- *
- * E.g....
- * When selection is explicitly cleared, reset.
- * When cancel event is received, reset.
+ * Class managing resetting of library state in response to specific
+ * events like clearing of selection and MotionEvent.ACTION_CANCEL
+ * events.
  *
  * @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
  */
@@ -42,7 +40,7 @@
 
     private static final String TAG = "ResetManager";
 
-    private final List<Runnable> mListeners = new ArrayList<>();
+    private final List<Resettable> mResetHandlers = new ArrayList<>();
 
     private final OnItemTouchListener mInputListener = new OnItemTouchListener() {
         @Override
@@ -50,7 +48,7 @@
                 @NonNull MotionEvent e) {
             if (MotionEvents.isActionCancel(e)) {
                 if (DEBUG) Log.d(TAG, "Received CANCEL event.");
-                notifyResetListeners();
+                callResetHandlers();
             }
             return false;
         }
@@ -64,23 +62,29 @@
         }
     };
 
+    // Resettable interface has a #requiresReset method because DefaultSelectionTracker
+    // (owner of the state we observer with our SelectionObserver) is, itself,
+    // a Resettable. Such an arrangement introduces the real possibility of infinite recursion.
+    // When we call reset on DefaultSelectionTracker it'll eventually call back to
+    // notify us of the change via onSelectionCleared. We avoid recursion by
+    // checking #requiresReset before calling reset again.
     private final SelectionObserver<K> mSelectionObserver = new SelectionObserver<K>() {
         @Override
         protected void onSelectionCleared() {
             if (DEBUG) Log.d(TAG, "Received onSelectionCleared event.");
-            notifyResetListeners();
+            callResetHandlers();
         }
 
         @Override
         public void onSelectionRefresh() {
             if (DEBUG) Log.d(TAG, "Received onSelectionRefresh event.");
-            notifyResetListeners();
+            callResetHandlers();
         }
 
         @Override
         public void onSelectionRestored() {
             if (DEBUG) Log.d(TAG, "Received onSelectionRestored event.");
-            notifyResetListeners();
+            callResetHandlers();
         }
     };
 
@@ -93,19 +97,17 @@
     }
 
     /**
-     * Registers a new listener.
+     * Registers a new Resettable.
      */
-    void addResetListener(@NonNull Runnable listener) {
-        mListeners.add(listener);
+    void addResetHandler(@NonNull Resettable handler) {
+        mResetHandlers.add(handler);
     }
 
-    public void forceReset() {
-        notifyResetListeners();
-    }
-
-    void notifyResetListeners() {
-        for (Runnable listener : mListeners) {
-            listener.run();
+    void callResetHandlers() {
+        for (Resettable handler : mResetHandlers) {
+            if (handler.isResetRequired()) {
+                handler.reset();
+            }
         }
     }
 }
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java
new file mode 100644
index 0000000..85092aa
--- /dev/null
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Resettable.java
@@ -0,0 +1,45 @@
+/*
+ * 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.recyclerview.selection;
+
+import static androidx.annotation.RestrictTo.Scope.LIBRARY;
+
+import androidx.annotation.RestrictTo;
+
+/**
+ * Represents an object that can be reset and can advise on it's
+ * need to be reset.
+ *
+ * <p>Calling {@link #isResetRequired()} on an instance of {@link Resettable}
+ * should always return false when called immediately after {@link #reset()}
+ * has been called.
+ *
+ * @hide
+ */
+@RestrictTo(LIBRARY)
+public interface Resettable {
+
+    /**
+     * @return true if the object requires reset.
+     */
+    boolean isResetRequired();
+
+    /**
+     * Resets the object state.
+     */
+    void reset();
+}
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
index 6c49015..11dc284 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/Selection.java
@@ -90,7 +90,7 @@
      * {@inheritDoc}
      */
     @Override
-    public Iterator<K> iterator() {
+    public @NonNull Iterator<K> iterator() {
         return mSelection.iterator();
     }
 
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
index 1e13bde..58780af 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionPredicates.java
@@ -34,7 +34,7 @@
      * @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
      * @return
      */
-    public static <K> SelectionPredicate<K> createSelectAnything() {
+    public static @NonNull <K> SelectionPredicate<K> createSelectAnything() {
         return new SelectionPredicate<K>() {
             @Override
             public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
@@ -60,7 +60,7 @@
      * @param <K> Selection key type. @see {@link StorageStrategy} for supported types.
      * @return
      */
-    public static <K> SelectionPredicate<K> createSelectSingleAnything() {
+    public static @NonNull <K> SelectionPredicate<K> createSelectSingleAnything() {
         return new SelectionPredicate<K>() {
             @Override
             public boolean canSetStateForKey(@NonNull K key, boolean nextState) {
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
index e340f3c..50cc4ceb 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/SelectionTracker.java
@@ -126,7 +126,7 @@
      * of the selection that will not reflect future changes
      * to selection.
      */
-    public abstract Selection<K> getSelection();
+    public abstract @NonNull Selection<K> getSelection();
 
     /**
      * Updates {@code dest} to reflect the current selection.
@@ -183,7 +183,7 @@
 
     /** @hide */
     @RestrictTo(LIBRARY)
-    protected abstract AdapterDataObserver getAdapterDataObserver();
+    protected abstract @NonNull AdapterDataObserver getAdapterDataObserver();
 
     /**
      * Attempts to establish a range selection at {@code position}, selecting the item
@@ -560,7 +560,7 @@
          * @param predicate the predicate to be used.
          * @return this
          */
-        public Builder<K> withSelectionPredicate(
+        public @NonNull Builder<K> withSelectionPredicate(
                 @NonNull SelectionPredicate<K> predicate) {
 
             checkArgument(predicate != null);
@@ -575,7 +575,7 @@
          * @param monitor the monitor to be used
          * @return this
          */
-        public Builder<K> withOperationMonitor(
+        public @NonNull Builder<K> withOperationMonitor(
                 @NonNull OperationMonitor monitor) {
 
             checkArgument(monitor != null);
@@ -589,7 +589,7 @@
          * @param delegate the delegate to be used
          * @return this
          */
-        public Builder<K> withFocusDelegate(@NonNull FocusDelegate<K> delegate) {
+        public @NonNull Builder<K> withFocusDelegate(@NonNull FocusDelegate<K> delegate) {
             checkArgument(delegate != null);
             mFocusDelegate = delegate;
             return this;
@@ -601,7 +601,7 @@
          * @param listener the listener to be used
          * @return this
          */
-        public Builder<K> withOnItemActivatedListener(
+        public @NonNull Builder<K> withOnItemActivatedListener(
                 @NonNull OnItemActivatedListener<K> listener) {
 
             checkArgument(listener != null);
@@ -616,7 +616,7 @@
          * @param listener the listener to be used
          * @return this
          */
-        public Builder<K> withOnContextClickListener(
+        public @NonNull Builder<K> withOnContextClickListener(
                 @NonNull OnContextClickListener listener) {
 
             checkArgument(listener != null);
@@ -631,7 +631,7 @@
          * @param listener the listener to be used
          * @return this
          */
-        public Builder<K> withOnDragInitiatedListener(
+        public @NonNull Builder<K> withOnDragInitiatedListener(
                 @NonNull OnDragInitiatedListener listener) {
 
             checkArgument(listener != null);
@@ -651,7 +651,7 @@
          * and only that tool type. This method will be removed in a future release.
          */
         @Deprecated
-        public Builder<K> withGestureTooltypes(int... toolTypes) {
+        public @NonNull Builder<K> withGestureTooltypes(@NonNull int... toolTypes) {
             Log.w(TAG, "Setting gestureTooltypes is likely to result in unexpected behavior.");
             mGestureToolTypes = toolTypes;
             return this;
@@ -662,7 +662,7 @@
          *
          * @return this
          */
-        public Builder<K> withBandOverlay(@DrawableRes int bandOverlayId) {
+        public @NonNull Builder<K> withBandOverlay(@DrawableRes int bandOverlayId) {
             mBandOverlayId = bandOverlayId;
             return this;
         }
@@ -672,7 +672,7 @@
          *
          * @return this
          */
-        public Builder<K> withBandPredicate(@NonNull BandPredicate bandPredicate) {
+        public @NonNull Builder<K> withBandPredicate(@NonNull BandPredicate bandPredicate) {
             mBandPredicate = bandPredicate;
             return this;
         }
@@ -690,7 +690,7 @@
          * and only that tool type. This method will be removed in a future release.
          */
         @Deprecated
-        public Builder<K> withPointerTooltypes(int... toolTypes) {
+        public @NonNull Builder<K> withPointerTooltypes(@NonNull int... toolTypes) {
             Log.w(TAG, "Setting pointerTooltypes is likely to result in unexpected behavior.");
             mPointerToolTypes = toolTypes;
             return this;
@@ -701,7 +701,7 @@
          *
          * @return this
          */
-        public SelectionTracker<K> build() {
+        public @NonNull SelectionTracker<K> build() {
 
             DefaultSelectionTracker<K> tracker = new DefaultSelectionTracker<>(
                     mSelectionId, mKeyProvider, mSelectionPredicate, mStorage);
@@ -761,9 +761,9 @@
             // stream, not even ACTION_CANCEL events.
             eventRouter.set(MotionEvent.TOOL_TYPE_UNKNOWN, resetMgr.getInputListener());
 
-            resetMgr.addResetListener(tracker::reset);
-            resetMgr.addResetListener(mMonitor::reset);
-            resetMgr.addResetListener(gestureHelper::reset);
+            resetMgr.addResetHandler(tracker);
+            resetMgr.addResetHandler(mMonitor.asResettable());
+            resetMgr.addResetHandler(gestureHelper);
 
             // But before you move on, there's more work to do. Event plumbing has been
             // installed, but we haven't registered any of our helpers or callbacks.
@@ -870,7 +870,7 @@
                         mFocusDelegate,
                         mMonitor);
 
-                resetMgr.addResetListener(bandHelper::reset);
+                resetMgr.addResetHandler(bandHelper);
             }
 
             OnItemTouchListener pointerEventHandler = new PointerDragEventInterceptor(
diff --git a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
index 9334d8a..1fb7b75 100644
--- a/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
+++ b/recyclerview/recyclerview-selection/src/main/java/androidx/recyclerview/selection/StorageStrategy.java
@@ -39,11 +39,11 @@
  * for more detailed advice on which key type to use for your selection keys.
  *
  * @param <K> Selection key type. Built in support is provided for String, Long, and Parcelable
- *           types. Use the respective factory method to create a StorageStrategy instance
- *           appropriate to the desired type.
- *           {@link #createStringStorage()},
- *           {@link #createParcelableStorage(Class)},
- *           {@link #createLongStorage()}
+ *            types. Use the respective factory method to create a StorageStrategy instance
+ *            appropriate to the desired type.
+ *            {@link #createStringStorage()},
+ *            {@link #createParcelableStorage(Class)},
+ *            {@link #createLongStorage()}
  */
 public abstract class StorageStrategy<K> {
 
@@ -69,7 +69,6 @@
      * Create a {@link Selection} from supplied {@link Bundle}.
      *
      * @param state Bundle instance that may contain parceled Selection instance.
-     * @return
      */
     public abstract @Nullable Selection<K> asSelection(@NonNull Bundle state);
 
@@ -77,7 +76,6 @@
      * Creates a {@link Bundle} from supplied {@link Selection}.
      *
      * @param selection The selection to asBundle.
-     * @return
      */
     public abstract @NonNull Bundle asBundle(@NonNull Selection<K> selection);
 
@@ -89,21 +87,22 @@
      * @return StorageStrategy suitable for use with {@link Parcelable} keys
      * (like {@link android.net.Uri}).
      */
-    public static <K extends Parcelable> StorageStrategy<K> createParcelableStorage(Class<K> type) {
+    public static @NonNull <K extends Parcelable> StorageStrategy<K> createParcelableStorage(
+            @NonNull Class<K> type) {
         return new ParcelableStorageStrategy<>(type);
     }
 
     /**
      * @return StorageStrategy suitable for use with {@link String} keys.
      */
-    public static StorageStrategy<String> createStringStorage() {
+    public static @NonNull StorageStrategy<String> createStringStorage() {
         return new StringStorageStrategy();
     }
 
     /**
      * @return StorageStrategy suitable for use with {@link Long} keys.
      */
-    public static StorageStrategy<Long> createLongStorage() {
+    public static @NonNull StorageStrategy<Long> createLongStorage() {
         return new LongStorageStrategy();
     }
 
@@ -191,7 +190,7 @@
     private static class ParcelableStorageStrategy<K extends Parcelable>
             extends StorageStrategy<K> {
 
-        ParcelableStorageStrategy(Class<K> type) {
+        ParcelableStorageStrategy(@NonNull Class<K> type) {
             super(type);
             checkArgument(Parcelable.class.isAssignableFrom(type));
         }
diff --git a/room/common/api/2.3.0-alpha01.txt b/room/common/api/2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/2.3.0-alpha01.txt
+++ b/room/common/api/2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/current.txt b/room/common/api/current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/current.txt
+++ b/room/common/api/current.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
+++ b/room/common/api/public_plus_experimental_2.3.0-alpha01.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/public_plus_experimental_current.txt b/room/common/api/public_plus_experimental_current.txt
index 238967d..4e032bd 100644
--- a/room/common/api/public_plus_experimental_current.txt
+++ b/room/common/api/public_plus_experimental_current.txt
@@ -167,6 +167,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_2.3.0-alpha01.txt b/room/common/api/restricted_2.3.0-alpha01.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_2.3.0-alpha01.txt
+++ b/room/common/api/restricted_2.3.0-alpha01.txt
@@ -176,6 +176,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/api/restricted_current.txt b/room/common/api/restricted_current.txt
index ed6c4ee..a2a0510 100644
--- a/room/common/api/restricted_current.txt
+++ b/room/common/api/restricted_current.txt
@@ -176,6 +176,8 @@
     field public static final String INDEX_FROM_EMBEDDED_FIELD_IS_DROPPED = "ROOM_EMBEDDED_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_FIELD_IS_DROPPED = "ROOM_PARENT_FIELD_INDEX_IS_DROPPED";
     field public static final String INDEX_FROM_PARENT_IS_DROPPED = "ROOM_PARENT_INDEX_IS_DROPPED";
+    field public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+    field public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
     field public static final String MISSING_INDEX_ON_FOREIGN_KEY_CHILD = "ROOM_MISSING_FOREIGN_KEY_CHILD_INDEX";
     field public static final String MISSING_JAVA_TMP_DIR = "ROOM_MISSING_JAVA_TMP_DIR";
     field public static final String MISSING_SCHEMA_LOCATION = "ROOM_MISSING_SCHEMA_LOCATION";
diff --git a/room/common/src/main/java/androidx/room/RoomWarnings.java b/room/common/src/main/java/androidx/room/RoomWarnings.java
index e8ad213..66cc1b8 100644
--- a/room/common/src/main/java/androidx/room/RoomWarnings.java
+++ b/room/common/src/main/java/androidx/room/RoomWarnings.java
@@ -134,6 +134,47 @@
     public static final String RELATION_QUERY_WITHOUT_TRANSACTION =
             "ROOM_RELATION_QUERY_WITHOUT_TRANSACTION";
 
+    /**
+     * Reported when an `@Entity` field's type do not exactly match the getter type.
+     * For instance, in the following class:
+     * <pre>
+     * {@code @}Entity
+     * class Foo {
+     *     ...
+     *     private Boolean value;
+     *     public boolean getValue() {
+     *         return value == null ? false : value;
+     *     }
+     * }
+     * </pre>
+     *
+     * Trying to insert this entity into database will always set {@code value} column to
+     * {@code false} when {@code Foo.value} is {@code null} since Room will use the {@code getValue}
+     * method to read the value. So even thought the database column is nullable, it will never
+     * be inserted as {@code null} if inserted as a {@code Foo} instance.
+     */
+    public static final String MISMATCHED_GETTER = "ROOM_MISMATCHED_GETTER_TYPE";
+
+    /**
+     * Reported when an `@Entity` field's type do not exactly match the setter type.
+     * For instance, in the following class:
+     * <pre>
+     * {@code @}Entity
+     * class Foo {
+     *     ...
+     *     private Boolean value;
+     *     public void setValue(boolean value) {
+     *         this.value = value;
+     *     }
+     * }
+     * </pre>
+     *
+     * If Room reads this entity from the database, it will always set {@code Foo.value} to
+     * {@code false} when the column value is {@code null} since Room will use the {@code setValue}
+     * method to write the value.
+     */
+    public static final String MISMATCHED_SETTER = "ROOM_MISMATCHED_SETTER_TYPE";
+
     /** @deprecated This type should not be instantiated as it contains only static methods. */
     @Deprecated
     @SuppressWarnings("PrivateConstructorForUtilityClass")
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
index 235a457..745c40f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -718,6 +718,23 @@
         context.checker.check(
             success || bindingScope == FieldProcessor.BindingScope.READ_FROM_CURSOR,
             field.element, CANNOT_FIND_GETTER_FOR_FIELD)
+        if (success && !context.processingEnv.typeUtils.isSameType(field.getter.type, field.type)) {
+            // getter's parameter type is not exactly the same as the field type.
+            // put a warning and update the value statement binder.
+            context.logger.w(
+                warning = Warning.MISMATCHED_GETTER_TYPE,
+                element = field.element,
+                msg = ProcessorErrors.mismatchedGetter(
+                    fieldName = field.name,
+                    ownerType = element.asType().typeName(),
+                    getterType = field.getter.type.typeName(),
+                    fieldType = field.typeName
+                ))
+            field.statementBinder = context.typeAdapterStore.findStatementValueBinder(
+                input = field.getter.type,
+                affinity = field.affinity
+            )
+        }
     }
 
     private fun assignSetters(
@@ -769,6 +786,23 @@
         context.checker.check(
             success || bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT,
             field.element, CANNOT_FIND_SETTER_FOR_FIELD)
+        if (success && !context.processingEnv.typeUtils.isSameType(field.setter.type, field.type)) {
+            // setter's parameter type is not exactly the same as the field type.
+            // put a warning and update the value reader adapter.
+            context.logger.w(
+                warning = Warning.MISMATCHED_SETTER_TYPE,
+                element = field.element,
+                msg = ProcessorErrors.mismatchedSetter(
+                    fieldName = field.name,
+                    ownerType = element.asType().typeName(),
+                    setterType = field.setter.type.typeName(),
+                    fieldType = field.typeName
+                ))
+            field.cursorValueReader = context.typeAdapterStore.findCursorValueReader(
+                output = field.setter.type,
+                affinity = field.affinity
+            )
+        }
     }
 
     /**
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
index d331aa1..d5b85f4 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/ProcessorErrors.kt
@@ -730,4 +730,26 @@
     fun invalidChannelType(typeName: String) = "'$typeName' is not supported as a return type. " +
             "Instead declare return type as ${KotlinTypeNames.FLOW} and use Flow transforming " +
             "functions that converts the Flow into a Channel."
+
+    fun mismatchedGetter(
+        fieldName: String,
+        ownerType: TypeName,
+        getterType: TypeName,
+        fieldType: TypeName
+    ) = """
+            $ownerType's $fieldName field has type $fieldType but its getter returns $getterType.
+            This mismatch might cause unexpected $fieldName values in the database when $ownerType
+            is inserted into database.
+        """.trim()
+
+    fun mismatchedSetter(
+        fieldName: String,
+        ownerType: TypeName,
+        setterType: TypeName,
+        fieldType: TypeName
+    ) = """
+            $ownerType's $fieldName field has type $fieldType but its setter accepts $setterType.
+            This mismatch might cause unexpected $fieldName values when $ownerType is read from the
+            database.
+        """.trim()
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
index f9a5eaa..861fa1f 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineResultBinder.kt
@@ -45,6 +45,14 @@
         inTransaction: Boolean,
         scope: CodeGenScope
     ) {
+        val cancellationSignalVar = scope.getTmpVar("_cancellationSignal")
+        scope.builder().addStatement(
+            "final $T $L = $T.createCancellationSignal()",
+            AndroidTypeNames.CANCELLATION_SIGNAL,
+            cancellationSignalVar,
+            RoomTypeNames.DB_UTIL
+        )
+
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
             createRunQueryAndReturnStatements(
                 builder = this,
@@ -58,10 +66,11 @@
 
         scope.builder().apply {
             addStatement(
-                "return $T.execute($N, $L, $L, $N)",
+                "return $T.execute($N, $L, $L, $L, $N)",
                 RoomCoroutinesTypeNames.COROUTINES_ROOM,
                 dbField,
                 if (inTransaction) "true" else "false",
+                cancellationSignalVar,
                 callableImpl,
                 continuationParamName)
         }
diff --git a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
index 0abd15e9..f959979 100644
--- a/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/vo/Warning.kt
@@ -36,7 +36,9 @@
     DEFAULT_CONSTRUCTOR("ROOM_DEFAULT_CONSTRUCTOR"),
     MISSING_COPY_ANNOTATIONS("MISSING_COPY_ANNOTATIONS"),
     MISSING_INDEX_ON_JUNCTION("MISSING_INDEX_ON_JUNCTION"),
-    JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG");
+    JDK_VERSION_HAS_BUG("JDK_VERSION_HAS_BUG"),
+    MISMATCHED_GETTER_TYPE("ROOM_MISMATCHED_GETTER_TYPE"),
+    MISMATCHED_SETTER_TYPE("ROOM_MISMATCHED_SETTER_TYPE");
 
     companion object {
         val PUBLIC_KEY_MAP = Warning.values().associateBy { it.publicKey }
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
index 448ab8f..4ffb54a 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/FieldReadWriteWriter.kt
@@ -189,7 +189,10 @@
                     val constructorFields = node.directFields.filter {
                         it.field.setter.callType == CallType.CONSTRUCTOR
                     }.associateBy { fwi ->
-                        FieldReadWriteWriter(fwi).readIntoTmpVar(cursorVar, scope)
+                        FieldReadWriteWriter(fwi).readIntoTmpVar(
+                            cursorVar,
+                            fwi.field.setter.type.typeName(),
+                            scope)
                     }
                     // read decomposed fields (e.g. embedded)
                     node.subNodes.forEach(::visitNode)
@@ -349,9 +352,12 @@
     /**
      * Reads the value into a temporary local variable.
      */
-    fun readIntoTmpVar(cursorVar: String, scope: CodeGenScope): String {
+    fun readIntoTmpVar(
+        cursorVar: String,
+        typeName: TypeName,
+        scope: CodeGenScope
+    ): String {
         val tmpField = scope.getTmpVar("_tmp${field.name.capitalize()}")
-        val typeName = field.getter.type.typeName()
         scope.builder().apply {
             addStatement("final $T $L", typeName, tmpField)
             if (alwaysExists) {
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
index b9ec119..f9b4038 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/TableEntityProcessorTest.kt
@@ -17,6 +17,7 @@
 package androidx.room.processor
 
 import COMMON
+import androidx.room.ext.typeName
 import androidx.room.parser.SQLTypeAffinity
 import androidx.room.processor.ProcessorErrors.RELATION_IN_ENTITY
 import androidx.room.vo.CallType
@@ -28,6 +29,8 @@
 import androidx.room.vo.Pojo
 import androidx.room.vo.columnNames
 import com.google.testing.compile.JavaFileObjects
+import com.squareup.javapoet.ClassName
+import com.squareup.javapoet.TypeName
 import compileLibrarySource
 import org.hamcrest.CoreMatchers.`is`
 import org.hamcrest.CoreMatchers.hasItems
@@ -35,6 +38,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import java.lang.AssertionError
 import javax.lang.model.type.TypeKind.INT
 
 @RunWith(JUnit4::class)
@@ -141,6 +145,46 @@
     }
 
     @Test
+    fun setterWithAssignableType_2() {
+        singleEntity("""
+                @PrimaryKey
+                private Integer id;
+                public Integer getId() {return id;}
+                public void setId(int id) {}
+                """) { entity, invocation ->
+            val idField = entity.fields.first()
+            val cursorValueReader = idField.cursorValueReader
+                ?: throw AssertionError("must have a cursor value reader")
+            assertThat(cursorValueReader.typeMirror().typeName(),
+                `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+        }.compilesWithoutError()
+            .withWarningContaining(
+                ProcessorErrors.mismatchedSetter(
+                    fieldName = "id",
+                    ownerType = ClassName.bestGuess("foo.bar.MyEntity"),
+                    setterType = TypeName.INT,
+                    fieldType = TypeName.INT.box()
+                )
+            )
+    }
+
+    @Test
+    fun getterWithAssignableType_2() {
+        singleEntity("""
+                @PrimaryKey
+                private Integer id;
+                public int getId() {return id == null ? 0 : id;}
+                public void setId(Integer id) {}
+                """) { entity, invocation ->
+            val idField = entity.fields.first()
+            val statementBinder = idField.statementBinder
+                ?: throw AssertionError("must have a statement binder")
+            assertThat(statementBinder.typeMirror().typeName(),
+                `is`(invocation.typeUtils.getPrimitiveType(INT).typeName()))
+        }.compilesWithoutError()
+    }
+
+    @Test
     fun noSetter() {
         singleEntity("""
                 @PrimaryKey
diff --git a/room/integration-tests/testapp/build.gradle b/room/integration-tests/testapp/build.gradle
index 7e0f759..5f24684 100644
--- a/room/integration-tests/testapp/build.gradle
+++ b/room/integration-tests/testapp/build.gradle
@@ -75,6 +75,7 @@
     androidTestImplementation(ANDROIDX_TEST_RUNNER)
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(ESPRESSO_CORE)
+    androidTestImplementation(TRUTH)
     androidTestImplementation(MOCKITO_CORE, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
     androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy) // DexMaker has it's own MockMaker
 
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
new file mode 100644
index 0000000..fd2afd2
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/test/BoxedPrimitivesTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.room.integration.testapp.test;
+
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_BOOLEAN_VALUE;
+import static androidx.room.integration.testapp.test.BoxedPrimitivesTest.BaseBoxed.DEFAULT_NUMBER_VALUE;
+
+import android.content.Context;
+
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Database;
+import androidx.room.Entity;
+import androidx.room.Insert;
+import androidx.room.PrimaryKey;
+import androidx.room.Query;
+import androidx.room.Room;
+import androidx.room.RoomDatabase;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@MediumTest
+@RunWith(AndroidJUnit4.class)
+public class BoxedPrimitivesTest {
+    private BoxingTestDatabase mDb;
+
+    @Before
+    public void initDb() {
+        Context context = ApplicationProvider.getApplicationContext();
+        mDb = Room.inMemoryDatabaseBuilder(
+                context,
+                BoxingTestDatabase.class)
+                .build();
+    }
+
+    @After
+    public void closeDb() {
+        mDb.close();
+    }
+
+    @Test
+    public void unboxedConstructor() {
+        test(mDb.constructor());
+    }
+
+    @Test
+    public void unboxedGetter() {
+        test(mDb.field());
+    }
+
+    /**
+     * Assert that if a nullable pojo is provided, we can actually insert/read null
+     */
+    private void test(BaseDao<? extends BaseBoxed> dao) {
+        long rowId = dao.insert(new BoxedBooleanHolder(null, null));
+        BaseBoxed read = dao.find(rowId);
+        Truth.assertThat(read.mFlag).isNull();
+        Truth.assertThat(read.mNumber).isNull();
+    }
+
+    @Test
+    public void testInsert_constructor() {
+        long rowId = mDb.constructor().insertTyped(new ConstructorEntity(null, null));
+        testInsertedAsEntity(mDb.constructor(), rowId);
+    }
+
+    @Test
+    public void testInsert_field() {
+        long rowId = mDb.field().insertTyped(new FieldEntity());
+        testInsertedAsEntity(mDb.field(), rowId);
+    }
+
+    /**
+     * assert the case where row was inserted via entity hence we should've read the default values
+     * already.
+     **/
+    private void testInsertedAsEntity(BaseDao<? extends BaseBoxed> dao, long rowId) {
+        BaseBoxed read = dao.find(rowId);
+        // default getter value
+        Truth.assertThat(read.mFlag).isEqualTo(DEFAULT_BOOLEAN_VALUE);
+        Truth.assertThat(read.mNumber).isEqualTo(DEFAULT_NUMBER_VALUE);
+    }
+
+    static class BaseBoxed {
+        @ColumnInfo(name = "boxed_bool")
+        Boolean mFlag;
+        @ColumnInfo(name = "boxed_int")
+        Integer mNumber;
+
+        static final boolean DEFAULT_BOOLEAN_VALUE = true;
+        static final int DEFAULT_NUMBER_VALUE = 41;
+
+        @SuppressWarnings("unused")
+        boolean getFlag() {
+            return mFlag == null ? DEFAULT_BOOLEAN_VALUE : mFlag;
+        }
+
+        @SuppressWarnings("unused")
+        int getNumber() {
+            return mNumber == null ? DEFAULT_NUMBER_VALUE : mNumber;
+        }
+    }
+
+    @Entity
+    static class ConstructorEntity extends BaseBoxed {
+        @PrimaryKey(autoGenerate = true)
+        public long rowId = 0;
+
+        ConstructorEntity(Boolean flag, Integer number) {
+            this.mFlag = flag;
+            this.mNumber = number;
+        }
+    }
+
+    @Entity
+    static class FieldEntity extends BaseBoxed {
+        @PrimaryKey(autoGenerate = true)
+        public long rowId = 0;
+
+        void setBoxed(Boolean boxed) {
+            this.mFlag = boxed;
+        }
+
+        void setNumber(Integer number) {
+            this.mNumber = number;
+        }
+    }
+
+    static class BoxedBooleanHolder {
+        @ColumnInfo(name = "boxed_bool")
+        final Boolean mFlag;
+        @ColumnInfo(name = "boxed_int")
+        final Integer mNumber;
+
+        BoxedBooleanHolder(Boolean flag, Integer number) {
+            mFlag = flag;
+            mNumber = number;
+        }
+    }
+
+    interface BaseDao<T> {
+        long insert(BoxedBooleanHolder t);
+
+        @Insert
+        long insertTyped(T t);
+
+        T find(long rowId);
+    }
+
+    @Dao
+    interface BoxedConstructorDao extends BaseDao<ConstructorEntity> {
+        @Override
+        @Insert(entity = ConstructorEntity.class)
+        long insert(BoxedBooleanHolder item);
+
+        @Override
+        @Query("SELECT * FROM ConstructorEntity WHERE rowId = :rowId")
+        ConstructorEntity find(long rowId);
+    }
+
+    @Dao
+    interface BoxedFieldDao extends BaseDao<FieldEntity> {
+
+        @Insert(entity = FieldEntity.class)
+        long insert(BoxedBooleanHolder item);
+
+        @Override
+        @Query("SELECT * FROM FieldEntity WHERE rowId = :rowId")
+        FieldEntity find(long rowId);
+    }
+
+    @Database(
+            entities = {FieldEntity.class, ConstructorEntity.class},
+            version = 1,
+            exportSchema = false
+    )
+    abstract static class BoxingTestDatabase extends RoomDatabase {
+        abstract BoxedConstructorDao constructor();
+
+        abstract BoxedFieldDao field();
+    }
+}
diff --git a/room/ktx/api/restricted_2.3.0-alpha01.txt b/room/ktx/api/restricted_2.3.0-alpha01.txt
index 20837edc..289fdbe 100644
--- a/room/ktx/api/restricted_2.3.0-alpha01.txt
+++ b/room/ktx/api/restricted_2.3.0-alpha01.txt
@@ -4,12 +4,14 @@
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class CoroutinesRoom {
     method public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
     method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, java.util.concurrent.Callable<R> inTransaction, kotlin.coroutines.Continuation<? super R> callable);
+    method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, android.os.CancellationSignal inTransaction, java.util.concurrent.Callable<R> cancellationSignal, kotlin.coroutines.Continuation<? super R> callable);
     field public static final androidx.room.CoroutinesRoom.Companion! Companion;
   }
 
   public static final class CoroutinesRoom.Companion {
     method public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
     method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
+    method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
   }
 
   public final class CoroutinesRoomKt {
diff --git a/room/ktx/api/restricted_current.txt b/room/ktx/api/restricted_current.txt
index 20837edc..289fdbe 100644
--- a/room/ktx/api/restricted_current.txt
+++ b/room/ktx/api/restricted_current.txt
@@ -4,12 +4,14 @@
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class CoroutinesRoom {
     method public static <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
     method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, java.util.concurrent.Callable<R> inTransaction, kotlin.coroutines.Continuation<? super R> callable);
+    method public static suspend <R> Object! execute(androidx.room.RoomDatabase p, boolean db, android.os.CancellationSignal inTransaction, java.util.concurrent.Callable<R> cancellationSignal, kotlin.coroutines.Continuation<? super R> callable);
     field public static final androidx.room.CoroutinesRoom.Companion! Companion;
   }
 
   public static final class CoroutinesRoom.Companion {
     method public <R> kotlinx.coroutines.flow.Flow<R> createFlow(androidx.room.RoomDatabase db, boolean inTransaction, String![] tableNames, java.util.concurrent.Callable<R> callable);
     method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
+    method public suspend <R> Object! execute(androidx.room.RoomDatabase db, boolean inTransaction, android.os.CancellationSignal cancellationSignal, java.util.concurrent.Callable<R> callable, kotlin.coroutines.Continuation<? super R> p);
   }
 
   public final class CoroutinesRoomKt {
diff --git a/room/ktx/build.gradle b/room/ktx/build.gradle
index 5d5528b..38b18eb 100644
--- a/room/ktx/build.gradle
+++ b/room/ktx/build.gradle
@@ -35,6 +35,12 @@
     testImplementation(MOCKITO_CORE)
     testImplementation(TRUTH)
     testImplementation("androidx.lifecycle:lifecycle-livedata-core:2.0.0")
+    testImplementation(ANDROIDX_TEST_RUNNER)
+    testImplementation(KOTLIN_COROUTINES_TEST)
+
+    androidTestImplementation(TRUTH)
+    androidTestImplementation(ANDROIDX_TEST_RUNNER)
+    androidTestImplementation(KOTLIN_COROUTINES_TEST)
 }
 
 androidx {
diff --git a/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt b/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt
new file mode 100644
index 0000000..b340852
--- /dev/null
+++ b/room/ktx/src/androidTest/java/androidx/room/CoroutineRoomCancellationTest.kt
@@ -0,0 +1,188 @@
+/*
+ * 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.room
+
+import android.database.sqlite.SQLiteException
+import android.os.CancellationSignal
+import androidx.sqlite.db.SupportSQLiteOpenHelper
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.cancelAndJoin
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.TestCoroutineDispatcher
+import kotlinx.coroutines.test.TestCoroutineScope
+import org.junit.Assert.assertTrue
+import org.junit.Assert.fail
+import org.junit.Test
+import java.util.concurrent.Callable
+import java.util.concurrent.CountDownLatch
+
+@SmallTest
+@SdkSuppress(minSdkVersion = 16)
+@ExperimentalCoroutinesApi
+class CoroutineRoomCancellationTest {
+
+    private val testDispatcher = TestCoroutineDispatcher()
+    val testScope = TestCoroutineScope(testDispatcher)
+
+    private val database = TestDatabase()
+
+    @Test
+    fun testSuspend_cancellable_duringLongQuery() = runBlocking {
+        database.backingFieldMap["QueryDispatcher"] = Dispatchers.IO
+
+        val inQueryLatch = CountDownLatch(1)
+        val cancelledLatch = CountDownLatch(1)
+
+        val cancellationSignal = CancellationSignal()
+        cancellationSignal.setOnCancelListener {
+            // query was cancelled so now we can finish our test
+            cancelledLatch.countDown()
+        }
+
+        val job = GlobalScope.launch(Dispatchers.IO) {
+            CoroutinesRoom.execute(
+                db = database,
+                inTransaction = false,
+                cancellationSignal = cancellationSignal,
+                callable = Callable {
+                    // we're triggering our fake query
+                    inQueryLatch.countDown()
+                    // fake a long query so we can cancel
+                    cancelledLatch.await()
+                }
+            )
+        }
+        inQueryLatch.await()
+        // we're in the query so we can cancel
+        job.cancelAndJoin()
+
+        assertThat(cancellationSignal.isCanceled).isTrue()
+    }
+
+    @Test
+    fun testSuspend_cancellable_beforeQueryStarts() = runBlocking {
+        database.backingFieldMap["QueryDispatcher"] = testDispatcher
+
+        val inCoroutineLatch = CountDownLatch(1)
+        val cancelledLatch = CountDownLatch(1)
+
+        val cancellationSignal = CancellationSignal()
+        cancellationSignal.setOnCancelListener {
+            // query was cancelled so now we can finish our test
+            cancelledLatch.countDown()
+        }
+
+        val job = GlobalScope.launch(Dispatchers.IO) {
+            // Coroutine started so now we can cancel it
+            inCoroutineLatch.countDown()
+
+            // We're using a different dispatcher for queries.
+            // Pausing it, to simulate that we're cancelling the query before it's triggered
+            testDispatcher.pauseDispatcher()
+            CoroutinesRoom.execute(
+                db = database,
+                inTransaction = false,
+                cancellationSignal = cancellationSignal,
+                callable = Callable {
+                    // this should never execute
+                    fail("Blocking query triggered")
+                }
+            )
+        }
+        inCoroutineLatch.await()
+        job.cancelAndJoin()
+        testDispatcher.resumeDispatcher()
+
+        assertThat(cancellationSignal.isCanceled).isTrue()
+    }
+
+    @Test
+    fun testSuspend_exception_in_query() = runBlocking {
+        database.backingFieldMap["QueryDispatcher"] = Dispatchers.IO
+        val cancellationSignal = CancellationSignal()
+
+        GlobalScope.launch(Dispatchers.IO) {
+            try {
+                CoroutinesRoom.execute(
+                    db = database,
+                    inTransaction = false,
+                    cancellationSignal = cancellationSignal,
+                    callable = Callable {
+                        throw SQLiteException("stuff happened")
+                    }
+                )
+            } catch (exception: Throwable) {
+                assertTrue(exception is SQLiteException)
+            }
+        }
+
+        assertThat(cancellationSignal.isCanceled).isFalse()
+    }
+
+    @Test
+    fun testSuspend_notCancelled() = runBlocking {
+        database.backingFieldMap["QueryDispatcher"] = testDispatcher
+
+        val cancellationSignal = CancellationSignal()
+
+        val job = testScope.launch {
+            CoroutinesRoom.execute(
+                db = database,
+                inTransaction = false,
+                cancellationSignal = cancellationSignal,
+                callable = Callable { /* nothing to do */ }
+            )
+        }
+        // wait for the job to be finished
+        job.join()
+
+        assertThat(cancellationSignal.isCanceled).isFalse()
+    }
+
+    private class TestDatabase : RoomDatabase() {
+
+        override fun createOpenHelper(config: DatabaseConfiguration?): SupportSQLiteOpenHelper {
+            throw UnsupportedOperationException("Shouldn't be called!")
+        }
+
+        override fun createInvalidationTracker(): InvalidationTracker {
+            return TestInvalidationTracker(this)
+        }
+
+        override fun clearAllTables() {
+            throw UnsupportedOperationException("Shouldn't be called!")
+        }
+    }
+
+    private class TestInvalidationTracker(db: RoomDatabase) : InvalidationTracker(db) {
+        val observers = mutableListOf<Observer>()
+
+        override fun addObserver(observer: Observer) {
+            observers.add(observer)
+        }
+
+        override fun removeObserver(observer: Observer) {
+            observers.remove(observer)
+        }
+    }
+}
diff --git a/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt b/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
index c7befed..83613d5 100644
--- a/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
+++ b/room/ktx/src/main/java/androidx/room/CoroutinesRoom.kt
@@ -16,15 +16,22 @@
 
 package androidx.room
 
+import android.os.Build
+import android.os.CancellationSignal
 import androidx.annotation.RestrictTo
 import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.GlobalScope
 import kotlinx.coroutines.asCoroutineDispatcher
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import java.util.concurrent.Callable
 import kotlin.coroutines.coroutineContext
+import kotlin.coroutines.resume
+import kotlin.coroutines.resumeWithException
 
 /**
  * A helper class for supporting Kotlin Coroutines in Room.
@@ -56,6 +63,39 @@
         }
 
         @JvmStatic
+        suspend fun <R> execute(
+            db: RoomDatabase,
+            inTransaction: Boolean,
+            cancellationSignal: CancellationSignal,
+            callable: Callable<R>
+        ): R {
+            if (db.isOpen && db.inTransaction()) {
+                return callable.call()
+            }
+
+            // Use the transaction dispatcher if we are on a transaction coroutine, otherwise
+            // use the database dispatchers.
+            val context = coroutineContext[TransactionElement]?.transactionDispatcher
+                ?: if (inTransaction) db.transactionDispatcher else db.queryDispatcher
+            return suspendCancellableCoroutine<R> { continuation ->
+                val job = GlobalScope.launch(context) {
+                    try {
+                        val result = callable.call()
+                        continuation.resume(result)
+                    } catch (exception: Throwable) {
+                        continuation.resumeWithException(exception)
+                    }
+                }
+                continuation.invokeOnCancellation {
+                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+                        cancellationSignal.cancel()
+                    }
+                    job.cancel()
+                }
+            }
+        }
+
+        @JvmStatic
         fun <R> createFlow(
             db: RoomDatabase,
             inTransaction: Boolean,
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
index 9dc8227..92ed977 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyDetailsLookup.java
@@ -19,6 +19,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.selection.ItemDetailsLookup;
 import androidx.recyclerview.widget.RecyclerView;
@@ -36,7 +37,7 @@
     }
 
     @Override
-    public ItemDetails<Uri> getItemDetails(MotionEvent e) {
+    public ItemDetails<Uri> getItemDetails(@NonNull MotionEvent e) {
         @Nullable View view = mRecView.findChildViewUnder(e.getX(), e.getY());
         if (view != null) {
             ViewHolder holder = mRecView.getChildViewHolder(view);
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
index a145403..6637d88 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancyHolder.java
@@ -54,12 +54,12 @@
             }
 
             @Override
-            public boolean inDragRegion(MotionEvent e) {
+            public boolean inDragRegion(@NonNull MotionEvent e) {
                 return FancyHolder.this.inDragRegion(e);
             }
 
             @Override
-            public boolean inSelectionHotspot(MotionEvent e) {
+            public boolean inSelectionHotspot(@NonNull MotionEvent e) {
                 return FancyHolder.this.inSelectRegion(e);
             }
 
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
index 27a3b04..c54368b 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/fancy/FancySelectionDemoActivity.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.ContextMenu;
@@ -30,6 +31,7 @@
 
 import androidx.annotation.CallSuper;
 import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
 import androidx.appcompat.app.AppCompatActivity;
 import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
 import androidx.recyclerview.selection.ItemKeyProvider;
@@ -83,9 +85,9 @@
         mSelectionTracker = builder
                 .withSelectionPredicate(SelectionPredicates.createSelectAnything())
                 .withOnDragInitiatedListener(new OnDragInitiatedListener(this))
-                .withOnContextClickListener(new OnContextClickListener(this))
+                .withOnContextClickListener(new OnContextClickListener())
                 .withOnItemActivatedListener(new OnItemActivatedListener(this))
-                .withFocusDelegate(new FocusDelegate(this))
+                .withFocusDelegate(new FocusDelegate())
                 .withBandOverlay(R.drawable.selection_demo_band_overlay)
                 .build();
 
@@ -107,7 +109,7 @@
     }
 
     @Override
-    protected void onSaveInstanceState(Bundle state) {
+    protected void onSaveInstanceState(@NonNull Bundle state) {
         super.onSaveInstanceState(state);
         mSelectionTracker.onSaveInstanceState(state);
         state.putInt(EXTRA_COLUMN_COUNT, mColumnCount);
@@ -219,15 +221,10 @@
     private static final class FocusDelegate extends
             androidx.recyclerview.selection.FocusDelegate<Uri> {
 
-        private final Context mContext;
         private ItemDetails<Uri> mFocusedItem;
 
-        private FocusDelegate(Context context) {
-            mContext = context;
-        }
-
         @Override
-        public void focusItem(ItemDetails<Uri> item) {
+        public void focusItem(@NonNull ItemDetails<Uri> item) {
             mFocusedItem = item;
             Log.i(TAG, "focusItem called for " + item);
         }
@@ -269,14 +266,7 @@
     private final class OnContextClickListener implements
             androidx.recyclerview.selection.OnContextClickListener {
 
-        private boolean mShowByViewHolder;
-
-        private final Context mContext;
-
-        OnContextClickListener(Context context) {
-            mContext = context;
-        }
-
+        @RequiresApi(api = Build.VERSION_CODES.N)
         @Override
         public boolean onContextClick(MotionEvent e) {
             View view = mRecView.findChildViewUnder(e.getX(), e.getY());
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
index 81bda7f..51e39c1 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoDetailsLookup.java
@@ -18,6 +18,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.recyclerview.selection.ItemDetailsLookup;
 import androidx.recyclerview.widget.RecyclerView;
@@ -35,7 +36,7 @@
     }
 
     @Override
-    public ItemDetails<Long> getItemDetails(MotionEvent e) {
+    public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
         @Nullable View view = mRecView.findChildViewUnder(e.getX(), e.getY());
         if (view != null) {
             ViewHolder holder = mRecView.getChildViewHolder(view);
diff --git a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
index ad28e23..9759905 100644
--- a/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
+++ b/samples/Support7Demos/src/main/java/com/example/android/supportv7/widget/selection/simple/DemoHolder.java
@@ -20,6 +20,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
 import androidx.recyclerview.widget.RecyclerView;
 
@@ -49,12 +50,12 @@
             }
 
             @Override
-            public boolean inDragRegion(MotionEvent e) {
+            public boolean inDragRegion(@NonNull MotionEvent e) {
                 return DemoHolder.this.inDragRegion(e);
             }
 
             @Override
-            public boolean inSelectionHotspot(MotionEvent e) {
+            public boolean inSelectionHotspot(@NonNull MotionEvent e) {
                 return DemoHolder.this.inSelectRegion(e);
             }
         };
diff --git a/serialization/serialization-schema/build.gradle b/serialization/serialization-schema/build.gradle
index d6a7de9..c361ea0 100644
--- a/serialization/serialization-schema/build.gradle
+++ b/serialization/serialization-schema/build.gradle
@@ -27,6 +27,7 @@
 }
 
 dependencies {
+    api(project(":serialization:serialization-annotation"))
     implementation(KOTLIN_STDLIB)
     testImplementation(JUNIT)
 }
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt
new file mode 100644
index 0000000..de20f52
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Reserved.kt
@@ -0,0 +1,45 @@
+/*
+ * 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.serialization.schema
+
+/**
+ * A collection of reserved IDs or names for a message class, enum class, or service interface.
+ *
+ * @property ids Message field, enum value, or service action IDs to reserve.
+ * @property names Message field, enum value, or service action names to reserve.
+ * @property idRanges Ranges of IDs to reserve in bulk.
+ * @see androidx.serialization.Reserved
+ */
+data class Reserved(
+    val ids: Set<Int> = emptySet(),
+    val names: Set<String> = emptySet(),
+    val idRanges: Set<IntRange> = emptySet()
+) {
+    operator fun contains(id: Int): Boolean {
+        return id in ids || idRanges.any { id in it }
+    }
+
+    operator fun contains(name: String): Boolean {
+        return name in names
+    }
+
+    companion object {
+        private val EMPTY_INSTANCE = Reserved()
+
+        fun empty(): Reserved = EMPTY_INSTANCE
+    }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt
new file mode 100644
index 0000000..e7d6c73
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Schema.kt
@@ -0,0 +1,33 @@
+/*
+ * 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.serialization.schema
+
+/**
+ * A schema consisting of messages, enums, and services.
+ *
+ * Clients who have subclassed [Message], [Enum], or [Service] may wish to subclass this class to
+ * provide type safety around their subclassed types.
+ *
+ * @property messages Messages declared in the schema.
+ * @property enums Enums declared in the schema.
+ * @property services Services declared in the schema.
+ */
+open class Schema(
+    open val messages: List<Message> = emptyList(),
+    open val enums: List<Enum> = emptyList(),
+    open val services: List<Service> = emptyList()
+)
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt
new file mode 100644
index 0000000..aebd8fc
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/Type.kt
@@ -0,0 +1,343 @@
+/*
+ * 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.serialization.schema
+
+import androidx.serialization.ProtoEncoding
+import androidx.serialization.ProtoEncoding.SIGNED_FIXED
+import androidx.serialization.ProtoEncoding.SIGNED_VARINT
+import androidx.serialization.ProtoEncoding.UNSIGNED_FIXED
+import androidx.serialization.ProtoEncoding.UNSIGNED_VARINT
+import androidx.serialization.ProtoEncoding.ZIG_ZAG_VARINT
+
+/**
+ * Root of the serialization type hierarchy.
+ */
+sealed class Type
+
+// Declared Types ////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A user-declared message, enum, or service.
+ *
+ * @property name The qualified name of the type.
+ * @property members Members of the type, such as message fields, enum values, or service actions.
+ * @property reserved Reserved IDs and names within this type
+ */
+sealed class DeclaredType(
+    val name: TypeName,
+    val members: List<Member>,
+    val reserved: Reserved
+) : Type() {
+    /**
+     * A member of a user-declared type, such as a message field, enum value, or service action.
+     */
+    abstract class Member(
+        val id: Int,
+        val name: String
+    )
+}
+
+/**
+ * A user-declared message.
+ *
+ * Clients of this package may wish to subclass [Message] and [Field] to add additional context
+ * or data such as source location.
+ *
+ * @property fields Fields of the message.
+ *
+ * Consider overriding this property in a subclass if you subclass [Field].
+ */
+open class Message(
+    name: TypeName,
+    open val fields: List<Field>,
+    reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, fields, reserved) {
+    /**
+     * A field of a user-declared message.
+     *
+     * @property type The type of the field, may be any type starting from root.
+     * @see androidx.serialization.Field
+     */
+    open class Field(
+        id: Int,
+        name: String,
+        val type: Type
+    ) : Member(id, name)
+}
+
+/**
+ * A user-declared serializable enum.
+ *
+ * Clients of this package may wish to subclass [Enum] and [Value] to add additional context
+ * or data such as source location.
+ *
+ * @property values Values of the enum.
+ *
+ * Consider overriding this property in a subclass if you subclass [Value].
+ */
+open class Enum(
+    name: TypeName,
+    open val values: List<Value>,
+    reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, values, reserved) {
+    /**
+     * A value of a user-declared enum.
+     *
+     * @see androidx.serialization.EnumValue
+     */
+    open class Value(
+        id: Int,
+        name: String
+    ) : Member(id, name)
+}
+
+/**
+ * A user-declared service interface.
+ *
+ * Clients of this package may wish to subclass [Service] and [Action] to add additional context
+ * or data such as source location.
+ *
+ * @property actions Actions of the service.
+ *
+ * Consider overriding this property in a subclass if you subclass [Action].
+ */
+open class Service(
+    name: TypeName,
+    open val actions: List<Action>,
+    reserved: Reserved = Reserved.empty()
+) : DeclaredType(name, actions, reserved) {
+    /**
+     * An action of a user-declared service interface.
+     *
+     * Consider overriding [request] and [response] if you subclass [Message].
+     *
+     * @property request The request message type, or null for a nullary action method.
+     * @property response The response message type, or null for a void action method.
+     * @property mode The synchronization mode of the action.
+     * @see androidx.serialization.Action
+     */
+    open class Action(
+        id: Int,
+        name: String,
+        open val request: Message? = null,
+        open val response: Message? = null,
+        val mode: Mode = Mode.BLOCKING
+    ) : Member(id, name) {
+        /**
+         * The synchronization mode of an action.
+         */
+        enum class Mode {
+            /**
+             * Action method blocks until transaction completes on remote process.
+             */
+            BLOCKING,
+
+            /**
+             * Action method returns immediately and does not return a response.
+             *
+             * @see android.os.IBinder.FLAG_ONEWAY
+             */
+            ONE_WAY
+        }
+    }
+}
+
+// Collections ///////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A linear collection of values, such as a [Collection] or an [Array].
+ */
+open class CollectionType(val type: Type) : Type()
+
+/**
+ * An associative collection of keys and values, such as a [Map] or a [android.util.SparseArray].
+ */
+open class MapType(val keyType: Type, val valueType: Type) : Type()
+
+// Scalars ///////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A scalar value.
+ *
+ * Scalar fields have a default value of zero, empty, or false.
+ *
+ * @property name Scalar name, as used in proto.
+ * @property protoEncoding Proto encoding of integral scalar values.
+ */
+sealed class Scalar(
+    val name: String,
+    val protoEncoding: ProtoEncoding = ProtoEncoding.DEFAULT
+) : Type()
+
+/**
+ * Boolean scalar.
+ */
+object BoolScalar : Scalar("bool")
+
+/**
+ * Byte array scalar, such as [ByteArray] or [java.nio.ByteBuffer].
+ */
+object BytesScalar : Scalar("bytes")
+
+/**
+ * A 64-bit floating point scalar.
+ */
+object DoubleScalar : Scalar("double")
+
+/**
+ * A 32-bit floating point scalar.
+ */
+object FloatScalar : Scalar("float")
+
+/**
+ * String scalar.
+ */
+object StringScalar : Scalar("string")
+
+/**
+ * A 32-bit integer scalar type.
+ */
+sealed class IntScalar(name: String, protoEncoding: ProtoEncoding) : Scalar(name, protoEncoding)
+
+/**
+ * A 32-bit signed integer scalar using the [SIGNED_VARINT] encoding.
+ */
+object Int32Scalar : IntScalar("int32", SIGNED_VARINT)
+
+/**
+ * A 32-bit signed integer scalar using the [ZIG_ZAG_VARINT] encoding.
+ */
+object SInt32Scalar : IntScalar("sint32", ZIG_ZAG_VARINT)
+
+/**
+ * A 32-bit unsigned integer scalar using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt32Scalar : IntScalar("uint32", UNSIGNED_VARINT)
+
+/**
+ * A 32-bit unsigned fixed width integer scalar.
+ */
+object Fixed32Scalar : IntScalar("fixed32", UNSIGNED_FIXED)
+
+/**
+ * A 32-bit signed fixed width integer scalar.
+ */
+object SFixed32Scalar : IntScalar("sfixed32", SIGNED_FIXED)
+
+/**
+ * A 64-bit integer scalar type.
+ */
+sealed class LongScalar(name: String, protoEncoding: ProtoEncoding) : Scalar(name, protoEncoding)
+
+/**
+ * A 64-bit signed integer scalar using the [SIGNED_VARINT] encoding.
+ */
+object Int64Scalar : LongScalar("int64", SIGNED_VARINT)
+
+/**
+ * A 64-bit signed integer scalar using the [ZIG_ZAG_VARINT] encoding.
+ */
+object SInt64Scalar : LongScalar("sint64", ZIG_ZAG_VARINT)
+
+/**
+ * A 64-bit unsigned integer scalar using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt64Scalar : LongScalar("uint64", UNSIGNED_VARINT)
+
+/**
+ * A 64-bit unsigned fixed width integer scalar.
+ */
+object Fixed64Scalar : LongScalar("fixed64", UNSIGNED_FIXED)
+
+/**
+ * A 64-bit signed fixed width integer scalar.
+ */
+object SFixed64Scalar : LongScalar("sfixed64", SIGNED_FIXED)
+
+// Wrapper Messages //////////////////////////////////////////////////////////////////////////////
+
+/**
+ * A message type that wraps a scalar value.
+ *
+ * This provides support for nullable field types. The message types are derived from proto's
+ * [well known types][1].
+ *
+ * [1]: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf
+ *
+ * @property scalar The wrapped scalar type.
+ */
+sealed class Wrapper(simpleName: String, val scalar: Scalar) : Type() {
+    /**
+     * The name of the type in the `google.protobuf` package.
+     */
+    val name = TypeName("google.protobuf", simpleName)
+}
+
+/**
+ * Boolean wrapper message.
+ */
+object BoolWrapper : Wrapper("BoolWrapper", BoolScalar)
+
+/**
+ * Bytes wrapper message, such as a nullable [ByteArray] or [java.nio.ByteBuffer].
+ */
+object BytesWrapper : Wrapper("BytesValue", BytesScalar)
+
+/**
+ * A 64-bit floating point wrapper message.
+ */
+object DoubleWrapper : Wrapper("DoubleValue", DoubleScalar)
+
+/**
+ * A 32-bit floating point wrapper message.
+ */
+object FloatWrapper : Wrapper("FloatValue", FloatScalar)
+
+/**
+ * String wrapper message.
+ */
+object StringWrapper : Wrapper("StringValue", StringScalar)
+
+/**
+ * A 32-bit integer wrapper message type.
+ */
+sealed class IntWrapper(name: String, scalar: IntScalar) : Wrapper(name, scalar)
+
+/**
+ * A signed 32-bit integer wrapper message using the [SIGNED_VARINT] encoding.
+ */
+object Int32Wrapper : IntWrapper("Int32Value", Int32Scalar)
+
+/**
+ * An unsigned 32-bit integer wrapper message using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt32Wrapper : IntWrapper("UInt32Value", UInt32Scalar)
+
+/**
+ * A 64-bit integer wrapper message type.
+ */
+sealed class LongWrapper(name: String, scalar: LongScalar) : Wrapper(name, scalar)
+
+/**
+ * A signed 64-bit integer wrapper message using the [SIGNED_VARINT] encoding.
+ */
+object Int64Wrapper : LongWrapper("Int64Value", Int64Scalar)
+
+/**
+ * An unsigned 64-bit integer wrapper message using the [UNSIGNED_VARINT] encoding.
+ */
+object UInt64Wrapper : LongWrapper("UInt64Value", UInt64Scalar)
diff --git a/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt
new file mode 100644
index 0000000..706311e
--- /dev/null
+++ b/serialization/serialization-schema/src/main/kotlin/androidx/serialization/schema/TypeName.kt
@@ -0,0 +1,91 @@
+/*
+ * 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.serialization.schema
+
+/**
+ * The qualified name of a declared, wrapper, or well-known type.
+ *
+ * For example, the nested enum class `Bar` below would be represented as
+ * `TypeName("com.example", "Foo", "Bar")`
+ *
+ * ```kotlin
+ * package com.example
+ *
+ * data class Foo(@Field(1) val bar: Bar) {
+ *     enum class Bar {
+ *         @EnumValue(0)
+ *         ZERO,
+ *         @EnumValue(1)
+ *         ONE
+ *     }
+ * }
+ * ```
+ *
+ * @property packageName The package containing the type, or null for the default package.
+ * @property names A list of nested type names.
+ */
+class TypeName(
+    packageName: String? = null,
+    val names: List<String>
+) {
+    init {
+        require(names.isNotEmpty()) { "names must contain at least one name" }
+        require(names.none { it.isEmpty() }) {
+            "names must not contain empty names. names: $names"
+        }
+    }
+
+    constructor(
+        packageName: String?,
+        vararg names: String
+    ) : this(packageName, names.asList())
+
+    val packageName: String? = packageName?.ifEmpty { null }
+
+    /**
+     * The simple name of the type.
+     *
+     * For `com.example.Foo.Bar`, this is `Bar`.
+     */
+    val simpleName: String = names.last()
+
+    /**
+     * The canonical name of the type, separated with dots.
+     */
+    val canonicalName: String by lazy {
+        buildString {
+            if (packageName != null) {
+                append(packageName)
+                append(".")
+            }
+            names.joinTo(this, ".")
+        }
+    }
+
+    override fun toString(): String = canonicalName
+
+    override fun hashCode(): Int {
+        return (packageName.hashCode() * 31) + names.hashCode()
+    }
+
+    override fun equals(other: Any?): Boolean {
+        return when (other) {
+            is TypeName -> this.packageName == other.packageName && this.names == other.names
+            else -> false
+        }
+    }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt
new file mode 100644
index 0000000..9d780e7
--- /dev/null
+++ b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/ReservedTest.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.serialization.schema
+
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * Tests for [Reserved].
+ */
+class ReservedTest {
+    @Test
+    fun testContainsIds() {
+        val reserved = Reserved(ids = setOf(1, 2))
+        assertTrue(1 in reserved)
+        assertTrue(2 in reserved)
+        assertFalse(3 in reserved)
+    }
+
+    @Test
+    fun testContainsNames() {
+        val reserved = Reserved(names = setOf("foo", "bar"))
+        assertTrue("foo" in reserved)
+        assertTrue("bar" in reserved)
+        assertFalse("quux" in reserved)
+    }
+
+    @Test
+    fun testContainsIdRanges() {
+        val reserved = Reserved(idRanges = setOf(1..10, 21..40))
+
+        for (i in 1..10) {
+            assertTrue(i in reserved)
+        }
+
+        for (i in 11..20) {
+            assertFalse(i in reserved)
+        }
+
+        for (i in 21..40) {
+            assertTrue(i in reserved)
+        }
+    }
+}
\ No newline at end of file
diff --git a/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt
new file mode 100644
index 0000000..75adb3c
--- /dev/null
+++ b/serialization/serialization-schema/src/test/kotlin/androidx/serialization/schema/TypeNameTest.kt
@@ -0,0 +1,102 @@
+/*
+ * 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.serialization.schema
+
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+
+/**
+ * Tests for [TypeName].
+ */
+class TypeNameTest {
+    @Test(expected = IllegalArgumentException::class)
+    fun testAtLeastOneNameRequirement() {
+        TypeName("com.example", emptyList())
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun testNonEmptyNameRequirement() {
+        TypeName("com.example", "Foo", "", "Bar")
+    }
+
+    @Test
+    fun testDefaultNullPackage() {
+        assertNull(TypeName(names = listOf("Foo")).packageName)
+    }
+
+    @Test
+    fun testEmptyPackageName() {
+        assertNull(TypeName("", "Foo").packageName)
+    }
+
+    @Test
+    fun testCanonicalNameSingle() {
+        assertEquals("com.example.Foo", TypeName("com.example", "Foo").canonicalName)
+    }
+
+    @Test
+    fun testCanonicalNameNested() {
+        assertEquals("com.example.Foo.Bar", TypeName("com.example", "Foo", "Bar").canonicalName)
+    }
+
+    @Test
+    fun testCanonicalNameNullPackage() {
+        assertEquals("Foo", TypeName(null, "Foo").canonicalName)
+    }
+
+    @Test
+    fun testSimpleNameSingle() {
+        assertEquals("Foo", TypeName("com.example", "Foo").simpleName)
+    }
+
+    @Test
+    fun testSimpleNameNested() {
+        assertEquals("Bar", TypeName("com.example", "Foo", "Bar").simpleName)
+    }
+
+    @Test
+    fun testToString() {
+        val name = TypeName("com.example", "Foo", "Bar")
+        assertEquals(name.canonicalName, name.toString())
+    }
+
+    @Test
+    fun testHashCode() {
+        val a = TypeName("com.example", "Foo")
+        val b = TypeName("com.example", "Foo")
+        val c = TypeName("com.example", "Bar")
+
+        assertEquals(a.hashCode(), b.hashCode())
+        assertNotEquals(a.hashCode(), c.hashCode())
+    }
+
+    @Test
+    fun testEquals() {
+        val a = TypeName("com.example", "Foo")
+        val b = TypeName("com.example", "Foo")
+        val c = TypeName("com.example", "Bar")
+
+        assertTrue(a == b)
+        assertTrue(b == a)
+        assertFalse(a == c)
+        assertFalse(c == a)
+    }
+}
\ No newline at end of file
diff --git a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
index 2d75deb..f0c401b7 100644
--- a/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
+++ b/slices/test/src/main/java/androidx/slice/test/SampleSliceProvider.java
@@ -59,6 +59,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -806,13 +807,18 @@
         IconCompat icon = IconCompat.createWithResource(getContext(), R.drawable.ic_star_on);
         SliceAction primaryAction = SliceAction.create(
                 getBroadcastIntent(ACTION_TOAST, "open download"), icon, ICON_IMAGE,  "Download");
+        int progress = PROGRESS.next();
+        if (progress != 100) {
+            mHandler.postDelayed(() -> getContext().getContentResolver().notifyChange(sliceUri,
+                    null), 500);
+        }
         return new ListBuilder(getContext(), sliceUri, INFINITY)
                 .setAccentColor(0xffff4081)
                 .addRange(new RangeBuilder()
                         .setTitle("Download progress")
                         .setSubtitle("Download is happening")
                         .setMax(100)
-                        .setValue(75)
+                        .setValue(progress)
                         .setPrimaryAction(primaryAction))
                 .build();
     }
@@ -1185,4 +1191,18 @@
         return PendingIntent.getBroadcast(getContext(), requestCode, intent,
                 PendingIntent.FLAG_UPDATE_CURRENT);
     }
+
+    static final class RandomProgressGenerator {
+        private int mProgress = 0;
+        private int mEnd = 100;
+        private int mInterval = 5;
+
+        int next() {
+            if (mProgress >= mEnd) return mEnd;
+            mProgress += new Random().nextInt(mInterval);
+            return Math.min(mEnd, mProgress);
+        }
+    }
+
+    private static final RandomProgressGenerator PROGRESS = new RandomProgressGenerator();
 }
diff --git a/slices/view/src/main/java/androidx/slice/widget/RowView.java b/slices/view/src/main/java/androidx/slice/widget/RowView.java
index 56808ef..3fe3367 100644
--- a/slices/view/src/main/java/androidx/slice/widget/RowView.java
+++ b/slices/view/src/main/java/androidx/slice/widget/RowView.java
@@ -78,6 +78,7 @@
 import androidx.annotation.RestrictTo;
 import androidx.core.graphics.drawable.DrawableCompat;
 import androidx.core.graphics.drawable.IconCompat;
+import androidx.core.view.ViewCompat;
 import androidx.slice.SliceItem;
 import androidx.slice.SliceStructure;
 import androidx.slice.core.SliceAction;
@@ -195,6 +196,9 @@
         mActionSpinner = findViewById(R.id.action_sent_indicator);
         SliceViewUtil.tintIndeterminateProgressBar(getContext(), mActionSpinner);
         mEndContainer = (LinearLayout) findViewById(android.R.id.widget_frame);
+        ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
+        ViewCompat.setImportantForAccessibility(
+                mContent, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
     @Override
@@ -557,6 +561,12 @@
                 && mLoadingActions.contains(mRowAction.getSliceItem())) {
             mShowActionSpinner = true;
         }
+
+        ViewCompat.setImportantForAccessibility(mRootView,
+                (mRootView.isClickable() && mToggles.isEmpty() && mActions.isEmpty())
+                        ? ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO
+                        : ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO
+        );
     }
 
     @Override
diff --git a/ui/gradle.properties b/ui/gradle.properties
index 799d540..39f2467 100644
--- a/ui/gradle.properties
+++ b/ui/gradle.properties
@@ -12,3 +12,5 @@
 // Run multiple kotlin compilations in parallel within the same project.
 // See also https://github.com/JetBrains/kotlin/blob/1978db9d0e68a2ec29aded30a07e9c3c740c29f6/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt#L100 and https://blog.jetbrains.com/kotlin/2019/01/kotlin-1-3-20-released/
 kotlin.parallel.tasks.in.project=true
+# TODO(b/144189353) : remove android.useNewJarCreator once it stops putting illegal timestamps into jars
+android.useNewJarCreator=false
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
index 374552e..cd8e9029 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/NestedScrollerTestCase.kt
@@ -25,13 +25,13 @@
 import androidx.ui.foundation.ColoredRect
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.FlexColumn
 import androidx.ui.foundation.HorizontalScroller
 import androidx.ui.layout.Row
 import androidx.ui.foundation.ScrollerPosition
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
 import androidx.ui.material.MaterialTheme
 import androidx.ui.material.surface.Surface
 import androidx.ui.test.ComposeTestCase
@@ -71,7 +71,7 @@
             Row(ExpandedWidth) {
                 repeat(6) {
                     WithDensity {
-                        FlexColumn(crossAxisAlignment = CrossAxisAlignment.Start) {
+                        FlexColumn {
                             val color = +memo {
                                 val red = Random.nextInt(256)
                                 val green = Random.nextInt(256)
@@ -88,15 +88,17 @@
                                     text = "Some title",
                                     style = TextStyle(Color.Black, 60.px.toSp())
                                 )
-                                Row(
-                                    ExpandedWidth,
-                                    crossAxisAlignment = CrossAxisAlignment.Center
-                                ) {
-                                    Text("3.5 ★", style = TextStyle(fontSize = 40.px.toSp()))
+                                Row(ExpandedWidth) {
+                                    Text(
+                                        "3.5 ★",
+                                        style = TextStyle(fontSize = 40.px.toSp()),
+                                        modifier = Gravity.Center
+                                    )
                                     ColoredRect(
                                         width = 40.px.toDp(),
                                         height = 40.px.toDp(),
-                                        color = playStoreColor
+                                        color = playStoreColor,
+                                        modifier = Gravity.Center
                                     )
                                 }
                             }
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
index 21e32e8..de1288b 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/ScrollerTestCase.kt
@@ -26,7 +26,6 @@
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.foundation.ScrollerPosition
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.graphics.Paint
@@ -46,10 +45,7 @@
         VerticalScroller(
             scrollerPosition = scrollerPosition
         ) {
-            Column(
-                ExpandedHeight,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Column(ExpandedHeight) {
                 for (green in 0..0xFF) {
                     ColorStripe(0xFF, green, 0)
                 }
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 3a37022..b777fc1 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -1,3 +1,11 @@
+pluginManagement {
+    repositories {
+        maven {
+            url = new File(buildscript.sourceFile.parent + "/../../../prebuilts/androidx/external").getCanonicalFile()
+        }
+    }
+}
+
 // Calling includeProject(name, filePath) is shorthand for:
 //
 //   include(name)
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
index 8e0dd99..ce87853 100644
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/TextLayoutSpanTest.kt
@@ -26,11 +26,11 @@
 import androidx.text.style.BaselineShiftSpan
 import androidx.text.style.SkewXSpan
 import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers
 import org.mockito.Mockito.doAnswer
 import org.mockito.Mockito.spy
 import org.mockito.stubbing.Answer
@@ -67,12 +67,12 @@
         // first baselineShiftSpan is applied
         var expectShift = (-fontSize * spanOutterMult).toInt()
         doAnswer(updatePaintAnswer(baselineShift = expectShift))
-            .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateMeasureState(any())
 
         // second baselineShiftSpan is applied
         expectShift = (-fontSize * (spanOutterMult + spanInnerMult)).toInt()
         doAnswer(updatePaintAnswer(baselineShift = expectShift))
-            .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanInner).updateMeasureState(any())
 
         val paint = simplePaint(fontSize.toFloat())
         TextLayout(
@@ -98,12 +98,12 @@
         // first baselineShiftSpan is applied
         var expectShift = (-fontSize * spanOutterMult).toInt()
         doAnswer(updatePaintAnswer(baselineShift = expectShift))
-            .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateDrawState(any())
 
         // second baselineShiftSpan is applied
         expectShift = (-fontSize * (spanOutterMult + spanInnerMult)).toInt()
         doAnswer(updatePaintAnswer(baselineShift = expectShift))
-            .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanInner).updateDrawState(any())
 
         val paint = simplePaint(fontSize.toFloat())
         TextLayout(
@@ -126,9 +126,9 @@
         text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
 
         doAnswer(updatePaintAnswer(skewX = skewXOutter))
-            .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateDrawState(any())
         doAnswer(updatePaintAnswer(skewX = skewXInner + skewXOutter))
-            .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanInner).updateDrawState(any())
 
         TextLayout(
             text,
@@ -150,9 +150,9 @@
         text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
 
         doAnswer(updatePaintAnswer(skewX = skewXOutter))
-            .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateMeasureState(any())
         doAnswer(updatePaintAnswer(skewX = skewXInner + skewXOutter))
-            .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanInner).updateMeasureState(any())
 
         TextLayout(
             text,
@@ -174,9 +174,9 @@
         text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
 
         doAnswer(updatePaintAnswer(scaleX = scaleXOutter))
-            .`when`(spanOutter).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateDrawState(any())
         doAnswer(updatePaintAnswer(scaleX = scaleXInner * scaleXOutter))
-            .`when`(spanInner).updateDrawState(ArgumentMatchers.any())
+            .`when`(spanInner).updateDrawState(any())
 
         TextLayout(
             text,
@@ -198,9 +198,9 @@
         text.setSpan(spanInner, 0, text.length / 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
 
         doAnswer(updatePaintAnswer(scaleX = scaleXOutter))
-            .`when`(spanOutter).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanOutter).updateMeasureState(any())
         doAnswer(updatePaintAnswer(scaleX = scaleXInner * scaleXOutter))
-            .`when`(spanInner).updateMeasureState(ArgumentMatchers.any())
+            .`when`(spanInner).updateMeasureState(any())
 
         TextLayout(
             text,
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java
deleted file mode 100644
index ff4e53c..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class BaselineShiftSpanTest {
-    @Test
-    public void updateMeasureState_changePaintBaselineShift() {
-        final float multiplier = 2.0f;
-        final BaselineShiftSpan span = new BaselineShiftSpan(multiplier);
-        final TextPaint textPaint = new TextPaint();
-        // Make sure baseline shift is zero when created
-        assertThat(textPaint.baselineShift).isEqualTo(0);
-
-        span.updateMeasureState(textPaint);
-        assertThat(textPaint.baselineShift).isNotEqualTo(0);
-    }
-
-    @Test
-    public void updateDrawState_changePaintBaselineShift() {
-        final float multiplier = 2.0f;
-        final BaselineShiftSpan span = new BaselineShiftSpan(multiplier);
-        final TextPaint textPaint = new TextPaint();
-        // Make sure baseline shift is zero when created
-        assertThat(textPaint.baselineShift).isEqualTo(0);
-
-        span.updateDrawState(textPaint);
-        assertThat(textPaint.baselineShift).isNotEqualTo(0);
-    }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt
new file mode 100644
index 0000000..62cbcb3
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/BaselineShiftSpanTest.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class BaselineShiftSpanTest {
+    @Test
+    fun updateMeasureState_changePaintBaselineShift() {
+        val multiplier = 2.0f
+        val span = BaselineShiftSpan(multiplier)
+        val textPaint = TextPaint()
+        // Make sure baseline shift is zero when created
+        assertThat(textPaint.baselineShift).isEqualTo(0)
+
+        span.updateMeasureState(textPaint)
+        assertThat(textPaint.baselineShift).isNotEqualTo(0)
+    }
+
+    @Test
+    fun updateDrawState_changePaintBaselineShift() {
+        val multiplier = 2.0f
+        val span = BaselineShiftSpan(multiplier)
+        val textPaint = TextPaint()
+        // Make sure baseline shift is zero when created
+        assertThat(textPaint.baselineShift).isEqualTo(0)
+
+        span.updateDrawState(textPaint)
+        assertThat(textPaint.baselineShift).isNotEqualTo(0)
+    }
+}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java
deleted file mode 100644
index c843f3f..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class FontFeatureSpanTest {
-    @Test(expected = NullPointerException.class)
-    public void constructor_withNull_throwsException() {
-        new FontFeatureSpan(null);
-    }
-
-    @Test
-    public void updateMeasureState_changePaintFontFeatureSettings() {
-        final String fontFeatureSettings = "\"kern\" 0";
-        final FontFeatureSpan span = new FontFeatureSpan(fontFeatureSettings);
-        final TextPaint textPaint = new TextPaint();
-        // Make sure baseline shift is zero when created
-        assertThat(textPaint.getFontFeatureSettings()).isNull();
-
-        span.updateMeasureState(textPaint);
-        assertThat(textPaint.getFontFeatureSettings()).isEqualTo(fontFeatureSettings);
-    }
-
-    @Test
-    public void updateDrawState_changePaintBaselineShift() {
-        final String fontFeatureSettings = "\"kern\" 0";
-        final FontFeatureSpan span = new FontFeatureSpan(fontFeatureSettings);
-        final TextPaint textPaint = new TextPaint();
-        // Make sure baseline shift is zero when created
-        assertThat(textPaint.getFontFeatureSettings()).isNull();
-
-        span.updateDrawState(textPaint);
-        assertThat(textPaint.getFontFeatureSettings()).isEqualTo(fontFeatureSettings);
-    }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt
new file mode 100644
index 0000000..389c7f6
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/FontFeatureSpanTest.kt
@@ -0,0 +1,49 @@
+/*
+ * 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class FontFeatureSpanTest {
+    @Test
+    fun updateMeasureState_changePaintFontFeatureSettings() {
+        val fontFeatureSettings = "\"kern\" 0"
+        val span = FontFeatureSpan(fontFeatureSettings)
+        val textPaint = TextPaint()
+        // Make sure baseline shift is zero when created
+        Truth.assertThat(textPaint.fontFeatureSettings).isNull()
+        span.updateMeasureState(textPaint)
+        Truth.assertThat(textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
+    }
+
+    @Test
+    fun updateDrawState_changePaintBaselineShift() {
+        val fontFeatureSettings = "\"kern\" 0"
+        val span = FontFeatureSpan(fontFeatureSettings)
+        val textPaint = TextPaint()
+        // Make sure baseline shift is zero when created
+        Truth.assertThat(textPaint.fontFeatureSettings).isNull()
+        span.updateDrawState(textPaint)
+        Truth.assertThat(textPaint.fontFeatureSettings).isEqualTo(fontFeatureSettings)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java
deleted file mode 100644
index 774bdfc..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.text.style;
-
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class LetterSpacingSpanTest {
-    @Test
-    public void updateDrawState_changePaintLetterSpacing() {
-        final float letterSpacing = 5.0f;
-        final LetterSpacingSpan span = new LetterSpacingSpan(letterSpacing);
-        final TextPaint paint = new TextPaint();
-
-        span.updateDrawState(paint);
-        assertThat(paint.getLetterSpacing()).isEqualTo(letterSpacing);
-    }
-
-    @Test
-    public void updateMeasureState_changePaintLetterSpacing() {
-        final float letterSpacing = 5.0f;
-        final LetterSpacingSpan span = new LetterSpacingSpan(letterSpacing);
-        final TextPaint paint = new TextPaint();
-
-        span.updateMeasureState(paint);
-        assertThat(paint.getLetterSpacing()).isEqualTo(letterSpacing);
-    }
-
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt
new file mode 100644
index 0000000..09ebd6a
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/LetterSpacingSpanTest.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class LetterSpacingSpanTest {
+    @Test
+    fun updateDrawState_changePaintLetterSpacing() {
+        val letterSpacing = 5.0f
+        val span = LetterSpacingSpan(letterSpacing)
+        val paint = TextPaint()
+        span.updateDrawState(paint)
+        Truth.assertThat(paint.letterSpacing).isEqualTo(letterSpacing)
+    }
+
+    @Test
+    fun updateMeasureState_changePaintLetterSpacing() {
+        val letterSpacing = 5.0f
+        val span = LetterSpacingSpan(letterSpacing)
+        val paint = TextPaint()
+        span.updateMeasureState(paint)
+        Truth.assertThat(paint.letterSpacing).isEqualTo(letterSpacing)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java
deleted file mode 100644
index 56b79ca..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.text.style;
-
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class ShadowSpanTest {
-    @Test
-    public void updateDrawStateTest() {
-        final int color = 0xFF00FF00;
-        final float offsetX = 1f;
-        final float offsetY = 2f;
-        final float radius = 3f;
-        final ShadowSpan shadowSpan = new ShadowSpan(color, offsetX, offsetY, radius);
-
-        final TextPaint textPaint = mock(TextPaint.class);
-        shadowSpan.updateDrawState(textPaint);
-        verify(textPaint, times(1)).setShadowLayer(radius, offsetX, offsetY, color);
-    }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt
new file mode 100644
index 0000000..55222ac
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/ShadowSpanTest.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito
+
+@RunWith(JUnit4::class)
+@SmallTest
+class ShadowSpanTest {
+    @Test
+    fun updateDrawStateTest() {
+        val color = -0xff0100
+        val offsetX = 1f
+        val offsetY = 2f
+        val radius = 3f
+        val shadowSpan = ShadowSpan(color, offsetX, offsetY, radius)
+        val textPaint = Mockito.mock(TextPaint::class.java)
+        shadowSpan.updateDrawState(textPaint)
+        Mockito.verify(textPaint, Mockito.times(1))
+            .setShadowLayer(radius, offsetX, offsetY, color)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java
deleted file mode 100644
index 6de9ab9..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class SkewXSpanTest {
-    @Test
-    public void updateMeasureState_changePaintTextSkewX() {
-        final float skewX = 0.5f;
-        final SkewXSpan span = new SkewXSpan(skewX);
-        final TextPaint paint = new TextPaint();
-
-        assertThat(span.getSkewX()).isEqualTo(skewX);
-        span.updateMeasureState(paint);
-        assertThat(paint.getTextSkewX()).isEqualTo(skewX);
-    }
-
-    @Test
-    public void updateDrawState_changePaintTextSkewX() {
-        final float skewX = 0.5f;
-        final SkewXSpan span = new SkewXSpan(skewX);
-        final TextPaint paint = new TextPaint();
-
-        span.updateDrawState(paint);
-        assertThat(paint.getTextSkewX()).isEqualTo(skewX);
-    }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt
new file mode 100644
index 0000000..a134467
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/SkewXSpanTest.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.text.style
+
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class SkewXSpanTest {
+    @Test
+    fun updateMeasureState_changePaintTextSkewX() {
+        val skewX = 0.5f
+        val span = SkewXSpan(skewX)
+        val paint = TextPaint()
+        Truth.assertThat(span.skewX).isEqualTo(skewX)
+        span.updateMeasureState(paint)
+        Truth.assertThat(paint.textSkewX).isEqualTo(skewX)
+    }
+
+    @Test
+    fun updateDrawState_changePaintTextSkewX() {
+        val skewX = 0.5f
+        val span = SkewXSpan(skewX)
+        val paint = TextPaint()
+        span.updateDrawState(paint)
+        Truth.assertThat(paint.textSkewX).isEqualTo(skewX)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java
deleted file mode 100644
index 9ed453e..0000000
--- a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.text.style;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-
-import android.graphics.Typeface;
-import android.text.TextPaint;
-
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-@SmallTest
-public class TypefaceSpanTest {
-    @Test
-    public void updateDrawState_changesTypeface() {
-        final Typeface typeface = mock(Typeface.class);
-        final TypefaceSpan span = new TypefaceSpan(typeface);
-        final TextPaint paint = new TextPaint();
-
-        span.updateDrawState(paint);
-
-        assertThat(paint.getTypeface()).isSameInstanceAs(typeface);
-    }
-
-    @Test
-    public void updateMeasureState_changesTypeface() {
-        final Typeface typeface = mock(Typeface.class);
-        final TypefaceSpan span = new TypefaceSpan(typeface);
-        final TextPaint paint = new TextPaint();
-
-        span.updateMeasureState(paint);
-
-        assertThat(paint.getTypeface()).isSameInstanceAs(typeface);
-    }
-}
diff --git a/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt
new file mode 100644
index 0000000..74adc0ea
--- /dev/null
+++ b/ui/ui-android-text/src/androidTest/java/androidx/text/style/TypefaceSpanTest.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.text.style
+
+import android.graphics.Typeface
+import android.text.TextPaint
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito
+
+@RunWith(JUnit4::class)
+@SmallTest
+class TypefaceSpanTest {
+    @Test
+    fun updateDrawState_changesTypeface() {
+        val typeface = Mockito.mock(Typeface::class.java)
+        val span = TypefaceSpan(typeface)
+        val paint = TextPaint()
+        span.updateDrawState(paint)
+        Truth.assertThat(paint.typeface).isSameInstanceAs(typeface)
+    }
+
+    @Test
+    fun updateMeasureState_changesTypeface() {
+        val typeface = Mockito.mock(Typeface::class.java)
+        val span = TypefaceSpan(typeface)
+        val paint = TextPaint()
+        span.updateMeasureState(paint)
+        Truth.assertThat(paint.typeface).isSameInstanceAs(typeface)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java
deleted file mode 100644
index beb22ef..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Span which shifts the vertical position of baseline.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class BaselineShiftSpan extends MetricAffectingSpan {
-    private final float mMultiplier;
-
-    /**
-     * Create a {@link BaselineShiftSpan}.
-     * @param multiplier shift the baseline above by (baseline - ascent) * multiplier pixels.
-     */
-    public BaselineShiftSpan(float multiplier) {
-        mMultiplier = multiplier;
-    }
-
-    @Override
-    public void updateMeasureState(@NonNull TextPaint textPaint) {
-        textPaint.baselineShift += (int)(textPaint.ascent() * mMultiplier);
-    }
-
-    @Override
-    public void updateDrawState(@NonNull TextPaint textPaint) {
-        textPaint.baselineShift += (int)(textPaint.ascent() * mMultiplier);
-    }
-
-    public float getMultiplier() {
-        return mMultiplier;
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt
new file mode 100644
index 0000000..7e0c7be
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/BaselineShiftSpan.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.text.style
+
+import kotlin.math.ceil
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span which shifts the vertical position of baseline.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+open class BaselineShiftSpan(val multiplier: Float) : MetricAffectingSpan() {
+
+    override fun updateMeasureState(textPaint: TextPaint) {
+        textPaint.baselineShift += ceil(textPaint.ascent() * multiplier).toInt()
+    }
+
+    override fun updateDrawState(textPaint: TextPaint) {
+        textPaint.baselineShift += ceil(textPaint.ascent() * multiplier).toInt()
+    }
+}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java
deleted file mode 100644
index fa94f3e..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-import androidx.text.Preconditions;
-
-/**
- * Span that change font feature settings for font.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class FontFeatureSpan extends MetricAffectingSpan {
-    private final String mFontFeatureSettings;
-    public FontFeatureSpan(@NonNull String fontFeatureSettings) {
-        mFontFeatureSettings = Preconditions.checkNotNull(fontFeatureSettings);
-    }
-
-    @Override
-    public void updateMeasureState(@NonNull TextPaint textPaint) {
-        textPaint.setFontFeatureSettings(mFontFeatureSettings);
-    }
-
-    @Override
-    public void updateDrawState(TextPaint textPaint) {
-        textPaint.setFontFeatureSettings(mFontFeatureSettings);
-    }
-
-    /**
-     * @return a font feature setting string this span specifies.
-     */
-    public String getFontFeatureSettings() {
-        return mFontFeatureSettings;
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.kt
new file mode 100644
index 0000000..f35ca59
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/FontFeatureSpan.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.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span that change font feature settings for font.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class FontFeatureSpan(val fontFeatureSettings: String) : MetricAffectingSpan() {
+    override fun updateMeasureState(textPaint: TextPaint) {
+        textPaint.fontFeatureSettings = fontFeatureSettings
+    }
+
+    override fun updateDrawState(textPaint: TextPaint) {
+        textPaint.fontFeatureSettings = fontFeatureSettings
+    }
+}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java
deleted file mode 100644
index 48f5585..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-// TODO(haoyuchang): Should support passing pixel when framework is ready.
-/**
- * Span used to adjust the letter spacing.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class LetterSpacingSpan extends MetricAffectingSpan {
-    private final float mLetterSpacing;
-
-    /**
-     * Constructor of LetterSpacingSpan.
-     *
-     * @param letterSpacing the extra letter spacing in the unit of EM
-     */
-    public LetterSpacingSpan(float letterSpacing) {
-        mLetterSpacing = letterSpacing;
-    }
-
-    @Override
-    public void updateDrawState(@NonNull TextPaint textPaint) {
-        textPaint.setLetterSpacing(mLetterSpacing);
-    }
-
-    @Override
-    public void updateMeasureState(@NonNull TextPaint textPaint) {
-        textPaint.setLetterSpacing(mLetterSpacing);
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt
new file mode 100644
index 0000000..30520b2
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/LetterSpacingSpan.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+// TODO(haoyuchang): Should support passing pixel when framework is ready.
+/**
+ * Span used to adjust the letter spacing.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class LetterSpacingSpan(val letterSpacing: Float) : MetricAffectingSpan() {
+    override fun updateDrawState(textPaint: TextPaint) {
+        textPaint.letterSpacing = letterSpacing
+    }
+
+    override fun updateMeasureState(textPaint: TextPaint) {
+        textPaint.letterSpacing = letterSpacing
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java
deleted file mode 100644
index 837e61a..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.graphics.Paint;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Px;
-import androidx.annotation.RestrictTo;
-
-/**
- * The span which modifies the height of the covered paragraphs. A paragraph is defined as a
- * segment of string divided by '\n' character. To make sure the span work as expected, the
- * boundary of this span should align with paragraph boundary.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class LineHeightSpan implements android.text.style.LineHeightSpan {
-
-    @Px
-    private final int mLineHeight;
-
-    /**
-     * Create a LineHeightSpan which sets the line height to <code>height</code> physical pixels.
-     * @param lineHeight The specified line height in pixel unit, which is the space between the
-     *                   baseline of adjacent lines.
-     */
-    public LineHeightSpan(@Px int lineHeight) {
-        mLineHeight = lineHeight;
-    }
-
-    @Override
-    public void chooseHeight(@NonNull CharSequence text, int start, int end, int spanstartv,
-            int lineHeight, @NonNull Paint.FontMetricsInt fontMetricsInt) {
-
-        // In StaticLayout, line height is computed with descent - ascent
-        final int currentHeight = fontMetricsInt.descent - fontMetricsInt.ascent;
-        // If current height is not positive, do nothing.
-        if (currentHeight <= 0) {
-            return;
-        }
-        final float ratio = mLineHeight * 1.0f / currentHeight;
-        fontMetricsInt.descent = (int) Math.ceil(fontMetricsInt.descent * ratio);
-        fontMetricsInt.ascent = fontMetricsInt.descent - mLineHeight;
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt
new file mode 100644
index 0000000..e3c1c7a
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/LineHeightSpan.kt
@@ -0,0 +1,51 @@
+/*
+ * 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.text.style
+
+import android.graphics.Paint.FontMetricsInt
+import androidx.annotation.RestrictTo
+
+/**
+ * The span which modifies the height of the covered paragraphs. A paragraph is defined as a
+ * segment of string divided by '\n' character. To make sure the span work as expected, the
+ * boundary of this span should align with paragraph boundary.
+ * @constructor Create a LineHeightSpan which sets the line height to `height` physical pixels.
+ * @param lineHeight The specified line height in pixel unit, which is the space between the
+ * baseline of adjacent lines.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class LineHeightSpan(val lineHeight: Int) : android.text.style.LineHeightSpan {
+    override fun chooseHeight(
+        text: CharSequence,
+        start: Int,
+        end: Int,
+        spanstartVertical: Int,
+        lineHeight: Int,
+        fontMetricsInt: FontMetricsInt
+    ) { // In StaticLayout, line height is computed with descent - ascent
+        val currentHeight = fontMetricsInt.descent - fontMetricsInt.ascent
+        // If current height is not positive, do nothing.
+        if (currentHeight <= 0) {
+            return
+        }
+        val ratio = this.lineHeight * 1.0f / currentHeight
+        fontMetricsInt.descent =
+            Math.ceil(fontMetricsInt.descent * ratio.toDouble()).toInt()
+        fontMetricsInt.ascent = fontMetricsInt.descent - this.lineHeight
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java
deleted file mode 100644
index 19dfa7a..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.CharacterStyle;
-
-import androidx.annotation.ColorInt;
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * A span which applies a shadow effect to the covered text.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class ShadowSpan extends CharacterStyle {
-    private final int mColor;
-    private final float mOffsetX;
-    private final float mOffsetY;
-    private final float mRadius;
-
-    public ShadowSpan(@ColorInt int color, float offsetX, float offsetY, float radius) {
-        mColor = color;
-        mOffsetX = offsetX;
-        mOffsetY = offsetY;
-        mRadius = radius;
-    }
-
-    @Override
-    public void updateDrawState(@NonNull TextPaint tp) {
-        tp.setShadowLayer(mRadius, mOffsetX, mOffsetY, mColor);
-    }
-
-    public int getColor() {
-        return mColor;
-    }
-
-    public float getOffsetX() {
-        return mOffsetX;
-    }
-
-    public float getOffsetY() {
-        return mOffsetY;
-    }
-
-    public float getRadius() {
-        return mRadius;
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.kt
new file mode 100644
index 0000000..b046c9d
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/ShadowSpan.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.text.style
+
+import android.text.TextPaint
+import android.text.style.CharacterStyle
+import androidx.annotation.RestrictTo
+
+/**
+ * A span which applies a shadow effect to the covered text.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class ShadowSpan(
+    val color: Int,
+    val offsetX: Float,
+    val offsetY: Float,
+    val radius: Float
+) : CharacterStyle() {
+    override fun updateDrawState(tp: TextPaint) {
+        tp.setShadowLayer(radius, offsetX, offsetY, color)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java
deleted file mode 100644
index acacda1..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.RestrictTo;
-
-/**
- * Span which shear text in x direction. A pixel at (x, y) will be transfer to (x + y * skewX, y),
- * where y is the distant above baseline.
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class SkewXSpan extends MetricAffectingSpan {
-    private final float mSkewX;
-
-    public SkewXSpan(float skewX) {
-        mSkewX = skewX;
-    }
-
-    /**
-     * @return the skew factor specified by this span.
-     */
-    public float getSkewX() {
-        return mSkewX;
-    }
-
-    @Override
-    public void updateDrawState(TextPaint textPaint) {
-        textPaint.setTextSkewX(mSkewX + textPaint.getTextSkewX());
-    }
-
-    @Override
-    public void updateMeasureState(TextPaint textPaint) {
-        textPaint.setTextSkewX(mSkewX + textPaint.getTextSkewX());
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.kt
new file mode 100644
index 0000000..5755446
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/SkewXSpan.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.text.style
+
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span which shear text in x direction. A pixel at (x, y) will be transfer to (x + y * skewX, y),
+ * where y is the distant above baseline.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+open class SkewXSpan(val skewX: Float) : MetricAffectingSpan() {
+    override fun updateDrawState(textPaint: TextPaint) {
+        textPaint.textSkewX = skewX + textPaint.textSkewX
+    }
+
+    override fun updateMeasureState(textPaint: TextPaint) {
+        textPaint.textSkewX = skewX + textPaint.textSkewX
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java
deleted file mode 100644
index 792c8b0..0000000
--- a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package androidx.text.style;
-
-import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
-
-import android.graphics.Paint;
-import android.graphics.Typeface;
-import android.text.TextPaint;
-import android.text.style.MetricAffectingSpan;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.RestrictTo;
-
-/**
- * Span that displays text in the given Typeface. In Android Framework, TypefaceSpan that accepts
- * a Typeface as constructor argument was added in API 28, therefore was not usable before 28.
- *
- * @hide
- */
-@RestrictTo(LIBRARY_GROUP)
-public class TypefaceSpan extends MetricAffectingSpan {
-
-    @NonNull
-    private final Typeface mTypeface;
-
-    /**
-     * Constructs a {@link android.text.style.TypefaceSpan} from a {@link Typeface}. The previous
-     * style of the TextPaint is overridden and the style of the typeface is used.
-     *
-     * @param typeface Typeface to render the text with
-     */
-    public TypefaceSpan(@NonNull Typeface typeface) {
-        mTypeface = typeface;
-    }
-
-    /**
-     * Returns the typeface set in the span.
-     *
-     * @return the typeface set
-     * @see #TypefaceSpan(Typeface)
-     */
-    @NonNull
-    public Typeface getTypeface() {
-        return mTypeface;
-    }
-
-    @Override
-    public void updateDrawState(@NonNull TextPaint ds) {
-        updateTypeface(ds);
-    }
-
-    @Override
-    public void updateMeasureState(@NonNull TextPaint paint) {
-        updateTypeface(paint);
-    }
-
-    private void updateTypeface(@NonNull Paint paint) {
-        if (mTypeface != null) {
-            paint.setTypeface(mTypeface);
-        }
-    }
-}
diff --git a/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt
new file mode 100644
index 0000000..7e71a96
--- /dev/null
+++ b/ui/ui-android-text/src/main/java/androidx/text/style/TypefaceSpan.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package androidx.text.style
+
+import android.graphics.Paint
+import android.graphics.Typeface
+import android.text.TextPaint
+import android.text.style.MetricAffectingSpan
+import androidx.annotation.RestrictTo
+
+/**
+ * Span that displays text in the given Typeface. In Android Framework, TypefaceSpan that accepts
+ * a Typeface as constructor argument was added in API 28, therefore was not usable before 28.
+ *
+ * @constructor Constructs a [android.text.style.TypefaceSpan] from a [Typeface]. The previous
+ * style of the TextPaint is overridden and the style of the typeface is used.
+ * @param typeface Typeface to render the text with.
+ *
+ * @hide
+ */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+class TypefaceSpan(val typeface: Typeface) : MetricAffectingSpan() {
+    override fun updateDrawState(ds: TextPaint) {
+        updateTypeface(ds)
+    }
+
+    override fun updateMeasureState(paint: TextPaint) {
+        updateTypeface(paint)
+    }
+
+    private fun updateTypeface(paint: Paint) {
+        paint.typeface = typeface
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-core/api/0.1.0-dev03.txt b/ui/ui-core/api/0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/0.1.0-dev03.txt
+++ b/ui/ui-core/api/0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/api_lint.ignore b/ui/ui-core/api/api_lint.ignore
index 9024498..cdb5983 100644
--- a/ui/ui-core/api/api_lint.ignore
+++ b/ui/ui-core/api/api_lint.ignore
@@ -205,10 +205,16 @@
     Missing nullability on field `Companion` in class `class androidx.ui.engine.geometry.Size`
 MissingNullability: androidx.ui.graphics.Color#Companion:
     Missing nullability on field `Companion` in class `class androidx.ui.graphics.Color`
+MissingNullability: androidx.ui.graphics.FixedScale#equals(Object) parameter #0:
+    Missing nullability on parameter `p` in method `equals`
+MissingNullability: androidx.ui.graphics.FixedScale#toString():
+    Missing nullability on method `toString` return
 MissingNullability: androidx.ui.graphics.MaskFilter#Companion:
     Missing nullability on field `Companion` in class `class androidx.ui.graphics.MaskFilter`
 MissingNullability: androidx.ui.graphics.Path#Companion:
     Missing nullability on field `Companion` in class `class androidx.ui.graphics.Path`
+MissingNullability: androidx.ui.graphics.ScaleFit#Companion:
+    Missing nullability on field `Companion` in class `class androidx.ui.graphics.ScaleFit`
 MissingNullability: androidx.ui.graphics.colorspace.ColorSpaces#INSTANCE:
     Missing nullability on field `INSTANCE` in class `class androidx.ui.graphics.colorspace.ColorSpaces`
 MissingNullability: androidx.ui.graphics.colorspace.Illuminant#INSTANCE:
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-core/api/public_plus_experimental_0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/public_plus_experimental_current.txt b/ui/ui-core/api/public_plus_experimental_current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/public_plus_experimental_current.txt
+++ b/ui/ui-core/api/public_plus_experimental_current.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/restricted_0.1.0-dev03.txt b/ui/ui-core/api/restricted_0.1.0-dev03.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-core/api/restricted_0.1.0-dev03.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index 2c07274..ba2d75d 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -1454,6 +1454,14 @@
     enum_constant public static final androidx.ui.graphics.FilterQuality none;
   }
 
+  public final class FixedScale implements androidx.ui.graphics.ScaleFit {
+    ctor public FixedScale(float value);
+    method public float component1();
+    method public androidx.ui.graphics.FixedScale copy(float value);
+    method public float getValue();
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+  }
+
   public interface Image {
     method public androidx.ui.graphics.colorspace.ColorSpace getColorSpace();
     method public androidx.ui.graphics.ImageConfig getConfig();
@@ -1647,6 +1655,30 @@
     method public androidx.ui.graphics.RadialGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, float centerX, float centerY, float radius, androidx.ui.graphics.TileMode tileMode);
   }
 
+  public interface ScaleFit {
+    method public float scale(androidx.ui.core.PxSize srcSize, androidx.ui.core.PxSize dstSize);
+    field public static final androidx.ui.graphics.ScaleFit.Companion! Companion;
+  }
+
+  public static final class ScaleFit.Companion {
+    method public androidx.ui.graphics.ScaleFit getFillHeight();
+    method public androidx.ui.graphics.ScaleFit getFillMaxDimension();
+    method public androidx.ui.graphics.ScaleFit getFillMinDimension();
+    method public androidx.ui.graphics.ScaleFit getFillWidth();
+    method public androidx.ui.graphics.ScaleFit getFit();
+    method public androidx.ui.graphics.FixedScale getNone();
+    property public final androidx.ui.graphics.ScaleFit FillHeight;
+    property public final androidx.ui.graphics.ScaleFit FillMaxDimension;
+    property public final androidx.ui.graphics.ScaleFit FillMinDimension;
+    property public final androidx.ui.graphics.ScaleFit FillWidth;
+    property public final androidx.ui.graphics.ScaleFit Fit;
+    property public final androidx.ui.graphics.FixedScale None;
+  }
+
+  public final class ScaleFitKt {
+    ctor public ScaleFitKt();
+  }
+
   public final class Shader {
     ctor public Shader(android.graphics.Shader nativeShader);
     method public android.graphics.Shader getNativeShader();
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Em.kt b/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
index 6a49013..fea4caf 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Em.kt
@@ -17,6 +17,10 @@
 
 package androidx.ui.core
 
+import androidx.compose.Immutable
+import kotlin.math.max
+import kotlin.math.min
+
 /**
  * Dimension value representing Em. 1 Em is defined to be the font size when doing the text layout.
  * For example:
@@ -35,6 +39,7 @@
  *         }
  *     }
  */
+@Immutable
 data /*inline*/ class Em(val value: Float) {
     /**
      * Add two [Em]s together.
@@ -118,9 +123,9 @@
 inline operator fun Int.times(other: Em) =
     Em(this * other.value)
 
-inline fun min(a: Em, b: Em): Em = Em(value = kotlin.math.min(a.value, b.value))
+inline fun min(a: Em, b: Em): Em = Em(value = min(a.value, b.value))
 
-inline fun max(a: Em, b: Em): Em = Em(value = kotlin.math.max(a.value, b.value))
+inline fun max(a: Em, b: Em): Em = Em(value = max(a.value, b.value))
 
 /**
  * Ensures that this value lies in the specified range [minimumValue]..[maximumValue].
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt b/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
index ff853bd..6668aa7 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Sp.kt
@@ -17,6 +17,10 @@
 
 package androidx.ui.core
 
+import androidx.compose.Immutable
+import kotlin.math.max
+import kotlin.math.min
+
 /**
  * Dimension value representing scaled pixels (sp). Font related APIs specify their
  * dimensions such as font size in SP with Sp objects. Sp are normally
@@ -30,6 +34,7 @@
  * [toPx] is normally needed only for painting operations.
  */
 @Suppress("EXPERIMENTAL_FEATURE_WARNING")
+@Immutable
 data /*inline*/ class Sp(val value: Float) {
     /**
      * Add two [Sp]s together.
@@ -140,11 +145,11 @@
 }
 
 inline fun min(a: Sp, b: Sp): Sp = checkNotInherit(a, b) {
-    Sp(value = kotlin.math.min(a.value, b.value))
+    Sp(value = min(a.value, b.value))
 }
 
 inline fun max(a: Sp, b: Sp): Sp = checkNotInherit(a, b) {
-    Sp(value = kotlin.math.max(a.value, b.value))
+    Sp(value = max(a.value, b.value))
 }
 
 /**
diff --git a/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt
new file mode 100644
index 0000000..a91c695
--- /dev/null
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/ScaleFit.kt
@@ -0,0 +1,126 @@
+/*
+ * 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.graphics
+
+import androidx.ui.core.PxSize
+
+private const val OriginalScale = 1.0f
+
+/**
+ * Represents a rule to apply to scale a source rectangle to be inscribed into a destination
+ */
+interface ScaleFit {
+
+    /**
+     * Computes the scale factor to apply to both dimensions in order to fit the source
+     * appropriately with the given destination size
+     */
+    fun scale(srcSize: PxSize, dstSize: PxSize): Float
+
+    /**
+     * Companion object containing commonly used [ScaleFit] implementations
+     */
+    companion object {
+
+        /**
+         * Scale the source maintaining the aspect ratio so that the bounds match the maximum of
+         * the destination width or height. This can cover a larger area than the destination.
+         */
+        val FillMaxDimension = object : ScaleFit {
+            override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+                computeFillMaxDimension(srcSize, dstSize)
+        }
+
+        /**
+         * Scale the source maintaining the aspect ratio so that the bounds match the minimum of
+         * the destination width or height. This will always fill an area smaller than or equal to
+         * the destination.
+         */
+        val FillMinDimension = object : ScaleFit {
+            override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+                computeFillMinDimension(srcSize, dstSize)
+        }
+
+        /**
+         * Scale the source maintaining the aspect ratio so that the bounds match the destination
+         * height. This can cover a larger area than the destination if the height is larger than
+         * the width.
+         */
+        val FillHeight = object : ScaleFit {
+            override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+                computeFillHeight(srcSize, dstSize)
+        }
+
+        /**
+         * Scale the source maintaining the aspect ratio so that the bounds match the
+         * destination width. This can cover a larger area than the destination if the width is
+         * larger than the height.
+         */
+        val FillWidth = object : ScaleFit {
+            override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+                computeFillWidth(srcSize, dstSize)
+        }
+
+        /**
+         * Scale the source to maintain the aspect ratio to fit within the destination bounds
+         * if the source is larger than the destination. If the source is smaller than or equal
+         * to the destination in both dimensions, this behaves similarly to [None]. This will
+         * always be contained within the bounds of the destination.
+         */
+        val Fit = object : ScaleFit {
+            override fun scale(srcSize: PxSize, dstSize: PxSize): Float =
+                if (srcSize.width <= dstSize.width && srcSize.height <= dstSize.height) {
+                    OriginalScale
+                } else {
+                    computeFillMinDimension(srcSize, dstSize)
+                }
+        }
+
+        /**
+         * Do not apply any scaling to the source
+         */
+        val None = FixedScale(OriginalScale)
+    }
+}
+
+/**
+ * [ScaleFit] implementation that always scales the dimension by the provided
+ * fixed floating point value
+ */
+data class FixedScale(val value: Float) : ScaleFit {
+    override fun scale(srcSize: PxSize, dstSize: PxSize): Float = value
+}
+
+private fun computeFillMaxDimension(srcSize: PxSize, dstSize: PxSize): Float =
+    if (dstSize.width > dstSize.height) {
+        computeFillWidth(srcSize, dstSize)
+    } else {
+        computeFillHeight(srcSize, dstSize)
+    }
+
+private fun computeFillMinDimension(srcSize: PxSize, dstSize: PxSize): Float =
+    if (dstSize.width < dstSize.height) {
+        computeFillWidth(srcSize, dstSize)
+    } else {
+        computeFillHeight(srcSize, dstSize)
+    }
+
+private fun computeFillWidth(srcSize: PxSize, dstSize: PxSize): Float =
+    dstSize.width.value / srcSize.width.value
+
+private fun computeFillHeight(srcSize: PxSize, dstSize: PxSize): Float =
+    dstSize.height.value / srcSize.height.value
diff --git a/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
index 7f8cbc9..9b15e42 100644
--- a/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/Shadow.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.graphics
 
+import androidx.compose.Immutable
 import androidx.ui.core.Px
 import androidx.ui.core.lerp
 import androidx.ui.core.px
@@ -24,6 +25,7 @@
 /**
  * A single shadow.
  */
+@Immutable
 data class Shadow(
     val color: Color = Color(0xFF000000),
     val offset: Offset = Offset.zero,
diff --git a/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt b/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt
new file mode 100644
index 0000000..d33cc18
--- /dev/null
+++ b/ui/ui-core/src/test/java/androidx/ui/graphics/ScaleFitTest.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.graphics
+
+import androidx.test.filters.SmallTest
+import androidx.ui.core.IntPx
+import androidx.ui.core.PxSize
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class ScaleFitTest {
+
+    @Test
+    fun testScaleNone() {
+        val scale = ScaleFit.None.scale(
+            srcSize = PxSize(IntPx(100), IntPx(100)),
+            dstSize = PxSize(IntPx(200), IntPx(200))
+        )
+        assertEquals(1.0f, scale)
+    }
+
+    @Test
+    fun testScaleFit() {
+        val scale = ScaleFit.Fit.scale(
+            srcSize = PxSize(IntPx(200), IntPx(100)),
+            dstSize = PxSize(IntPx(100), IntPx(200))
+        )
+        assertEquals(.5f, scale)
+    }
+
+    @Test
+    fun testScaleFillWidth() {
+        val scale = ScaleFit.FillWidth.scale(
+            srcSize = PxSize(IntPx(400), IntPx(100)),
+            dstSize = PxSize(IntPx(100), IntPx(200))
+        )
+        assertEquals(0.25f, scale)
+    }
+
+    @Test
+    fun testScaleFillHeight() {
+        val scale = ScaleFit.FillHeight.scale(
+            srcSize = PxSize(IntPx(400), IntPx(100)),
+            dstSize = PxSize(IntPx(100), IntPx(200))
+        )
+        assertEquals(2.0f, scale)
+    }
+
+    @Test
+    fun testScaleFillMaxDimension() {
+        val scale = ScaleFit.FillMaxDimension.scale(
+            srcSize = PxSize(IntPx(400), IntPx(100)),
+            dstSize = PxSize(IntPx(100), IntPx(200))
+        )
+        assertEquals(2.0f, scale)
+    }
+
+    @Test
+    fun testScaleFillMinDimension() {
+        val scale = ScaleFit.FillMinDimension.scale(
+            srcSize = PxSize(IntPx(400), IntPx(100)),
+            dstSize = PxSize(IntPx(100), IntPx(200))
+        )
+        assertEquals(0.25f, scale)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-foundation/OWNERS b/ui/ui-foundation/OWNERS
index 40a5c8b..0a4bd6c 100644
--- a/ui/ui-foundation/OWNERS
+++ b/ui/ui-foundation/OWNERS
@@ -3,3 +3,4 @@
 andreykulikov@google.com
 malkov@google.com
 lpf@google.com
+qqd@google.com
diff --git a/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt b/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
index 84d0564..3a4dff7 100644
--- a/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
+++ b/ui/ui-foundation/integration-tests/foundation-demos/src/main/java/androidx/ui/foundation/demos/PopupActivity.kt
@@ -24,6 +24,7 @@
 import androidx.ui.core.Alignment
 import androidx.ui.core.Dp
 import androidx.ui.core.Draw
+import androidx.ui.core.Modifier
 import androidx.ui.core.Text
 import androidx.ui.core.TextField
 import androidx.ui.core.dp
@@ -51,9 +52,10 @@
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.layout.Wrap
 import androidx.ui.graphics.Paint
-import androidx.ui.layout.CrossAxisAlignment
+import androidx.ui.layout.ColumnScope
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
 import androidx.ui.text.ParagraphStyle
 import androidx.ui.text.TextStyle
 import androidx.ui.text.style.TextAlign
@@ -66,9 +68,9 @@
             val exampleIndex = +state { 0 }
             val totalExamples = 9
 
-            Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+            Column {
                 FlexRow(
-                    ExpandedWidth,
+                    ExpandedWidth wraps Gravity.Center,
                     mainAxisAlignment = MainAxisAlignment.SpaceBetween
                 ) {
                     inflexible {
@@ -155,11 +157,11 @@
 }
 
 @Composable
-fun PopupToggle() {
+fun ColumnScope.PopupToggle() {
     val showPopup = +state { true }
     val containerSize = 100.dp
 
-    Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+    Column(Gravity.Center) {
         Container(width = containerSize, height = containerSize) {
             if (showPopup.value) {
                 Popup(alignment = Alignment.Center) {
@@ -187,9 +189,8 @@
 }
 
 @Composable
-fun PopupWithChangingContent() {
-    Container {
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithChangingContent() {
+    Column(Gravity.Center) {
             val heightSize = 120.dp
             val widthSize = 160.dp
             val popupContentState = +state { 0 }
@@ -229,11 +230,10 @@
                 }
             )
         }
-    }
 }
 
 @Composable
-fun PopupWithChangingParent() {
+fun ColumnScope.PopupWithChangingParent() {
     val containerWidth = 400.dp
     val containerHeight = 200.dp
     val parentAlignment = +state { Alignment.TopLeft }
@@ -241,7 +241,7 @@
     val parentHeight = +state { 60.dp }
     val parentSizeChanged = +state { false }
 
-    Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+    Column(Gravity.Center) {
         Container(
             height = containerHeight,
             width = containerWidth,
@@ -290,9 +290,8 @@
 }
 
 @Composable
-fun PopupDropdownAlignment() {
-    Container {
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupDropdownAlignment() {
+    Column(Gravity.Center) {
             val heightSize = 120.dp
             val widthSize = 160.dp
             val dropDownAlignment = +state { DropDownAlignment.Left }
@@ -327,18 +326,17 @@
                 }
             }
         }
-    }
 }
 
 @Composable
-fun PopupAlignmentDemo() {
-    Container(alignment = Alignment.Center) {
+fun ColumnScope.PopupAlignmentDemo() {
+    Container(Gravity.Center) {
         val heightSize = 200.dp
         val widthSize = 400.dp
         val counter = +state { 0 }
         val popupAlignment = +state { Alignment.TopLeft }
 
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+        Column {
             ColoredContainer(
                 height = heightSize,
                 width = widthSize,
@@ -368,7 +366,7 @@
             }
 
             HeightSpacer(10.dp)
-            ColoredContainer(color = Color.White) {
+            ColoredContainer(color = Color.White, modifier = Gravity.Center) {
                 Text("Alignment: " + popupAlignment.value.toString())
             }
         }
@@ -376,9 +374,8 @@
 }
 
 @Composable
-fun PopupWithEditText() {
-    Container {
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithEditText() {
+    Column(Gravity.Center) {
             val widthSize = 190.dp
             val heightSize = 120.dp
             val editLineSize = 150.dp
@@ -393,7 +390,8 @@
             ColoredContainer(
                 height = heightSize,
                 width = widthSize,
-                color = Color.Red
+                color = Color.Red,
+                modifier = Gravity.Center
             ) {
                 if (showPopup.value) {
                     Popup(
@@ -419,13 +417,11 @@
                 }
             }
         }
-    }
 }
 
 @Composable
-fun PopupWithChangingSize() {
-    Container {
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
+fun ColumnScope.PopupWithChangingSize() {
+    Column(Gravity.Center) {
             val showPopup = +state { true }
             val heightSize = 120.dp
             val widthSize = 160.dp
@@ -473,21 +469,16 @@
                 }
             )
         }
-    }
 }
 
 @Composable
-fun PopupInsideScroller() {
+fun ColumnScope.PopupInsideScroller() {
     val heightSize = 400.dp
     val widthSize = 200.dp
-    Container(width = widthSize, height = heightSize) {
+    Container(width = widthSize, height = heightSize, modifier = Gravity.Center) {
         VerticalScroller {
-            Column(
-                ExpandedHeight,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                ColoredContainer(
-                    width = 80.dp,
+            Column(ExpandedHeight) {
+                ColoredContainer(width = 80.dp,
                     height = 160.dp,
                     color = Color(0xFF00FF00)
                 ) {
@@ -497,7 +488,7 @@
                 }
 
                 for (i in 0..30) {
-                    Text("Scroll #$i")
+                    Text(text = "Scroll #$i", modifier = Gravity.Center)
                 }
             }
         }
@@ -506,40 +497,39 @@
 
 @Composable
 fun PopupOnKeyboardUp() {
-    Container {
-        Column(crossAxisAlignment = CrossAxisAlignment.Center) {
-            val widthSize = 190.dp
-            val heightSize = 120.dp
+    Column {
+        val widthSize = 190.dp
+        val heightSize = 120.dp
 
-            HeightSpacer(350.dp)
-            Text("Start typing in the EditText below the parent(Red rectangle)")
-            ColoredContainer(
-                height = heightSize,
-                width = widthSize,
-                color = Color.Red
-            ) {
-                Popup(Alignment.Center) {
-                    ColoredContainer(color = Color.Green) {
-                        Text("Popup")
-                    }
+        HeightSpacer(350.dp)
+        Text("Start typing in the EditText below the parent(Red rectangle)")
+        ColoredContainer(
+            height = heightSize,
+            width = widthSize,
+            color = Color.Red,
+            modifier = Gravity.Center
+        ) {
+            Popup(Alignment.Center) {
+                ColoredContainer(color = Color.Green) {
+                    Text("Popup")
                 }
             }
-
-            EditLine(initialText = "Continue typing...", color = Color.Gray)
-
-            HeightSpacer(24.dp)
         }
+
+        EditLine(initialText = "Continue typing...", color = Color.Gray)
+
+        HeightSpacer(24.dp)
     }
 }
 
 @Composable
-fun ClickableTextWithBackground(
+fun ColumnScope.ClickableTextWithBackground(
     text: String,
     color: Color,
     onClick: (() -> Unit)? = null,
     padding: EdgeInsets = EdgeInsets(0.dp)
 ) {
-    Wrap {
+    Container(Gravity.Center) {
         DrawShape(RectangleShape, color)
         Clickable( {
             Container(padding = padding) {
@@ -551,6 +541,7 @@
 
 @Composable
 fun ColoredContainer(
+    modifier: Modifier = Modifier.None,
     width: Dp? = null,
     height: Dp? = null,
     color: Color,
@@ -560,6 +551,7 @@
     children: @Composable() () -> Unit
 ) {
     Container(
+        modifier = modifier,
         width = width,
         height = height,
         alignment = alignment,
diff --git a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
index ece96a5..e03a0a4 100644
--- a/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
+++ b/ui/ui-foundation/src/androidTest/java/androidx/ui/foundation/ScrollerTest.kt
@@ -42,7 +42,6 @@
 import androidx.ui.layout.Column
 import androidx.ui.layout.ConstrainedBox
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.DpConstraints
 import androidx.ui.core.Text
 import androidx.ui.core.dp
@@ -278,7 +277,7 @@
                     Align(alignment = Alignment.TopLeft) {
                         ConstrainedBox(constraints = constraints) {
                             VerticalScroller(scrollerPosition = scrollerPosition) {
-                                Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                                Column {
                                     colors.forEach { color ->
                                         Container(
                                             height = 5.px.toDp(),
@@ -316,7 +315,7 @@
                     Align(alignment = Alignment.TopLeft) {
                         ConstrainedBox(constraints = constraints) {
                             HorizontalScroller(scrollerPosition = scrollerPosition) {
-                                Row(crossAxisAlignment = CrossAxisAlignment.Start) {
+                                Row {
                                     colors.forEach { color ->
                                         Container(
                                             width = 5.px.toDp(),
diff --git a/ui/ui-framework/api/0.1.0-dev03.txt b/ui/ui-framework/api/0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/0.1.0-dev03.txt
+++ b/ui/ui-framework/api/0.1.0-dev03.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/api/current.txt b/ui/ui-framework/api/current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/current.txt
+++ b/ui/ui-framework/api/current.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-framework/api/public_plus_experimental_0.1.0-dev03.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/api/public_plus_experimental_current.txt b/ui/ui-framework/api/public_plus_experimental_current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/public_plus_experimental_current.txt
+++ b/ui/ui-framework/api/public_plus_experimental_current.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/api/restricted_0.1.0-dev03.txt b/ui/ui-framework/api/restricted_0.1.0-dev03.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-framework/api/restricted_0.1.0-dev03.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/api/restricted_current.txt b/ui/ui-framework/api/restricted_current.txt
index da3f890..8cff587 100644
--- a/ui/ui-framework/api/restricted_current.txt
+++ b/ui/ui-framework/api/restricted_current.txt
@@ -145,7 +145,9 @@
     method public static androidx.compose.Ambient<kotlin.coroutines.CoroutineContext> getCoroutineContextAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.Density> getDensityAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.input.FocusManager> getFocusManagerAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.text.font.Font.ResourceLoader> getFontLoaderAmbient();
     method public static androidx.compose.Ambient<androidx.ui.core.LayoutDirection> getLayoutDirectionAmbient();
+    method public static androidx.compose.Ambient<androidx.ui.input.TextInputService> getTextInputServiceAmbient();
     method public static androidx.compose.CompositionContext? setContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> content);
     method public static androidx.compose.CompositionContext? setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
@@ -347,13 +349,13 @@
 
   public final class VectorAssetKt {
     ctor public VectorAssetKt();
-    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode);
+    method public static void DrawVector(androidx.ui.graphics.vector.VectorAsset vectorImage, androidx.ui.graphics.Color tintColor = Color.Transparent, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = Alignment.Center, androidx.ui.graphics.ScaleFit fit = ScaleFit.Fit);
   }
 
   public final class VectorComposeKt {
     ctor public VectorComposeKt();
-    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
-    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Dp defaultWidth, androidx.ui.core.Dp defaultHeight, float viewportWidth = -1.0f, float viewportHeight = -1.0f, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
+    method public static void DrawVector(androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth = defaultWidth.value, float viewportHeight = defaultHeight.value, androidx.ui.graphics.Color tintColor = DefaultTintColor, androidx.ui.graphics.BlendMode tintBlendMode = DefaultTintBlendMode, androidx.ui.core.Alignment alignment = androidx.ui.graphics.vector.VectorComposeKt.DefaultAlignment, androidx.ui.graphics.ScaleFit scaleFit = ScaleFit.Fit, String name = "", kotlin.jvm.functions.Function3<? super androidx.ui.graphics.vector.VectorScope,? super java.lang.Float,? super java.lang.Float,kotlin.Unit> children);
     method public static void Group(androidx.ui.graphics.vector.VectorScope, String name = "", float rotation = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translationX = 0.0f, float translationY = 0.0f, java.util.List<androidx.ui.graphics.vector.PathNode> clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vector.VectorScope,kotlin.Unit> children);
     method public static void Path(androidx.ui.graphics.vector.VectorScope, java.util.List<androidx.ui.graphics.vector.PathNode> pathData, String name = "", androidx.ui.graphics.Brush? fill = null, float fillAlpha = 1.0f, androidx.ui.graphics.Brush? stroke = null, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.graphics.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.graphics.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
index cb6aa17..634bfd1 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL1.kt
@@ -24,7 +24,6 @@
 import androidx.ui.core.px
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.material.Button
 import androidx.ui.material.MaterialTheme
@@ -33,6 +32,7 @@
 import androidx.compose.unaryPlus
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
 
 /** A [SemanticProperty] is used to store semantic information about a component.
  *
@@ -174,12 +174,13 @@
                 InvokeActionsByParameters(actions)
             }
         }
-        Row(
-            ExpandedWidth,
-            mainAxisAlignment = MainAxisAlignment.Center,
-            crossAxisAlignment = CrossAxisAlignment.Center
-        ) {
-            Container(height = 300.dp, width = 500.dp, children = children)
+        Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Center) {
+            Container(
+                height = 300.dp,
+                width = 500.dp,
+                modifier = Gravity.Center,
+                children = children
+            )
         }
     }
 }
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
index 2b44e7b..5237a98 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/VectorGraphicsActivity.kt
@@ -28,6 +28,7 @@
 import androidx.ui.graphics.Color
 import androidx.ui.graphics.HorizontalGradient
 import androidx.ui.graphics.RadialGradient
+import androidx.ui.graphics.ScaleFit
 import androidx.ui.graphics.SolidColor
 import androidx.ui.graphics.TileMode
 import androidx.ui.graphics.VerticalGradient
@@ -52,10 +53,10 @@
                 val vectorAsset = +loadVectorResource(R.drawable.ic_crane)
                 WithDensity {
                     vectorAsset.resource.resource?.let {
-                        val width = it.defaultWidth.toDp()
-                        val height = it.defaultHeight.toDp()
-                        Container(width = width, height = height) {
-                            DrawVector(it)
+                        Center {
+                            Container(width = 200.dp, height = 100.dp) {
+                                DrawVector(it)
+                            }
                         }
                     }
                 }
@@ -76,7 +77,8 @@
         DrawVector(
             name = "vectorShape",
             defaultWidth = width,
-            defaultHeight = height
+            defaultHeight = height,
+            scaleFit = ScaleFit.FillMaxDimension
         ) { viewportWidth, viewportHeight ->
             Group(
                 scaleX = 0.75f,
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
index fd5be7d..29b8b46 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/autofill/ExplicitAutofillTypesActivity.kt
@@ -37,7 +37,6 @@
 import androidx.ui.input.ImeAction
 import androidx.ui.input.KeyboardType
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.HeightSpacer
 import androidx.ui.material.MaterialTheme
 
@@ -47,7 +46,7 @@
         super.onCreate(savedInstanceState)
         setContent {
             MaterialTheme {
-                Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                Column {
 
                     val nameState = +state { "Enter name here" }
                     val emailState = +state { "Enter email here" }
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
index 5175929..500c1f6a 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/ModelReadsTest.kt
@@ -263,6 +263,8 @@
             }
         }
         assertTrue(latch.await(1, TimeUnit.SECONDS))
+
+        assertCountDownOnlyWhileEnabled(enabled, model)
     }
 
     @Test
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt b/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
index 7620cfd..763381f 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/TextFieldDelegate.kt
@@ -32,7 +32,6 @@
 import androidx.ui.input.TextInputService
 import androidx.ui.input.TransformedText
 import androidx.ui.input.VisualTransformation
-import androidx.ui.input.identityOffsetMap
 import androidx.ui.text.AnnotatedString
 import androidx.ui.text.Paragraph
 import androidx.ui.text.ParagraphConstraints
@@ -317,7 +316,7 @@
         ): TransformedText {
             val annotatedString = AnnotatedString(value.text)
             return visualTransformation?.filter(annotatedString)
-                    ?: TransformedText(annotatedString, identityOffsetMap)
+                    ?: TransformedText(annotatedString, OffsetMap.identityOffsetMap)
         }
 
         /**
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
index fe2affe..2b5584d 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Wrapper.kt
@@ -20,7 +20,6 @@
 import android.content.res.Configuration
 import android.view.ViewGroup
 import androidx.annotation.CheckResult
-import androidx.annotation.RestrictTo
 import androidx.ui.core.input.FocusManager
 import androidx.ui.input.TextInputService
 import androidx.compose.Ambient
@@ -39,7 +38,6 @@
 import androidx.compose.unaryPlus
 import androidx.ui.autofill.Autofill
 import androidx.ui.autofill.AutofillTree
-import androidx.ui.core.text.AndroidFontResourceLoader
 import androidx.ui.text.font.Font
 import kotlinx.coroutines.Dispatchers
 import kotlin.coroutines.CoroutineContext
@@ -198,7 +196,7 @@
         },
         { children ->
             FontLoaderAmbient.Provider(
-                value = AndroidFontResourceLoader(context),
+                value = composeView.fontLoader,
                 children = children
             )
         },
@@ -242,12 +240,8 @@
 
 val FocusManagerAmbient = Ambient.of<FocusManager>()
 
-internal val TextInputServiceAmbient = Ambient.of<TextInputService?>()
+val TextInputServiceAmbient = Ambient.of<TextInputService?>()
 
-/**
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 val FontLoaderAmbient = Ambient.of<Font.ResourceLoader>()
 
 /**
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 f3676fb..44e8da0 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
@@ -16,6 +16,7 @@
 
 package androidx.ui.core.selection
 
+import androidx.compose.Immutable
 import androidx.ui.core.LayoutCoordinates
 import androidx.ui.core.PxPosition
 import androidx.ui.text.TextRange
@@ -24,6 +25,7 @@
 /**
  * Information about the current Selection.
  */
+@Immutable
 data class Selection(
     /**
      * Information about the start of the selection.
@@ -48,6 +50,7 @@
     /**
      * Contains information about an anchor (start/end) of selection.
      */
+    @Immutable
     data class AnchorInfo(
         /**
          * The coordinates of the graphical position for selection character offset.
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
index 3891e24..ca3c9c1 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/TextSelectionDelegate.kt
@@ -164,7 +164,7 @@
                 isStart = false,
                 areHandlesCrossed = handlesCrossed
             ),
-            direction = textDelegate.getBidiRunDirection(Math.max(endOffset - 1, 0)),
+            direction = textDelegate.getBidiRunDirection(max(endOffset - 1, 0)),
             offset = endOffset,
             layoutCoordinates = if (containsWholeSelectionEnd) layoutCoordinates else null
         ),
@@ -293,7 +293,7 @@
     val line = textDelegate.getLineForOffset(offset)
     val offsetToCheck =
         if (isStart && !areHandlesCrossed || !isStart && areHandlesCrossed) offset
-        else Math.max(offset - 1, 0)
+        else max(offset - 1, 0)
     val bidiRunDirection = textDelegate.getBidiRunDirection(offsetToCheck)
     val paragraphDirection = textDelegate.getParagraphDirection(offset)
 
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
index 9fad49a..3ce6d70 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorAsset.kt
@@ -17,10 +17,12 @@
 package androidx.ui.graphics.vector
 
 import androidx.compose.Composable
+import androidx.ui.core.Alignment
 import androidx.ui.core.Px
 import androidx.ui.graphics.BlendMode
 import androidx.ui.graphics.Brush
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.ScaleFit
 import androidx.ui.graphics.StrokeCap
 import androidx.ui.graphics.StrokeJoin
 import java.util.Stack
@@ -377,7 +379,9 @@
 fun DrawVector(
     vectorImage: VectorAsset,
     tintColor: Color = Color.Transparent,
-    tintBlendMode: BlendMode = DefaultTintBlendMode
+    tintBlendMode: BlendMode = DefaultTintBlendMode,
+    alignment: Alignment = Alignment.Center,
+    fit: ScaleFit = ScaleFit.Fit
 ) {
     DrawVector(
         name = vectorImage.name,
@@ -386,7 +390,9 @@
         defaultWidth = vectorImage.defaultWidth,
         defaultHeight = vectorImage.defaultHeight,
         tintColor = tintColor,
-        tintBlendMode = tintBlendMode
+        tintBlendMode = tintBlendMode,
+        alignment = alignment,
+        scaleFit = fit
     ) { _, _ ->
         RenderVectorGroup(group = vectorImage.root)
     }
diff --git a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
index 088fdc5..111a717 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/graphics/vector/VectorCompose.kt
@@ -27,13 +27,16 @@
 import androidx.ui.core.IntPx
 import androidx.ui.core.IntPxSize
 import androidx.ui.core.Px
+import androidx.ui.core.PxSize
 import androidx.ui.core.ambientDensity
 import androidx.ui.core.withDensity
 import androidx.ui.graphics.BlendMode
 import androidx.ui.graphics.Brush
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.ScaleFit
 import androidx.ui.graphics.StrokeCap
 import androidx.ui.graphics.StrokeJoin
+import androidx.ui.graphics.withSave
 import kotlin.math.ceil
 
 /**
@@ -56,6 +59,7 @@
  * @param[tintColor] Optional color used to tint this vector graphic
  * @param[tintBlendMode] Optional blend mode used with [tintColor], default is [BlendMode.srcIn]
  * @param[alignment] Specifies the placement of the vector within the drawing bounds
+ * @param[scaleFit] Specifies how the vector is to be scaled within the parent bounds
  */
 @Composable
 fun DrawVector(
@@ -66,6 +70,7 @@
     tintColor: Color = DefaultTintColor,
     tintBlendMode: BlendMode = DefaultTintBlendMode,
     alignment: Alignment = DefaultAlignment,
+    scaleFit: ScaleFit = ScaleFit.Fit,
     name: String = "",
     children: @Composable() VectorScope.(viewportWidth: Float, viewportHeight: Float) -> Unit
 ) {
@@ -75,15 +80,16 @@
     val vpWidth = if (viewportWidth == unset) widthPx.value else viewportWidth
     val vpHeight = if (viewportHeight == unset) heightPx.value else viewportHeight
     DrawVector(
-        widthPx,
-        heightPx,
-        vpWidth,
-        vpHeight,
-        tintColor,
-        tintBlendMode,
-        alignment,
-        name,
-        children
+        defaultWidth = widthPx,
+        defaultHeight = heightPx,
+        viewportWidth = vpWidth,
+        viewportHeight = vpHeight,
+        tintColor = tintColor,
+        tintBlendMode = tintBlendMode,
+        alignment = alignment,
+        scaleFit = scaleFit,
+        name = name,
+        children = children
     )
 }
 
@@ -100,6 +106,7 @@
  * @param[tintColor] Optional color used to tint this vector graphic
  * @param[tintBlendMode] Optional blend mode used with [tintColor], default is [BlendMode.srcIn]
  * @param[alignment] Specifies the placement of the vector within the drawing bounds
+ * @param[scaleFit] Specifies how the vector is to be scaled within the parent bounds
  */
 @Composable
 fun DrawVector(
@@ -110,6 +117,7 @@
     tintColor: Color = DefaultTintColor,
     tintBlendMode: BlendMode = DefaultTintBlendMode,
     alignment: Alignment = DefaultAlignment,
+    scaleFit: ScaleFit = ScaleFit.Fit,
     name: String = "",
     children: @Composable() VectorScope.(viewportWidth: Float, viewportHeight: Float) -> Unit
 ) {
@@ -132,19 +140,33 @@
         }
     }
 
+    val vectorWidth = defaultWidth.value
+    val vectorHeight = defaultHeight.value
+    val vectorPxSize = PxSize(Px(vectorWidth), Px(vectorHeight))
+
     Draw { canvas, parentSize ->
+        val parentWidth = parentSize.width.value
+        val parentHeight = parentSize.height.value
+        val scale = scaleFit.scale(vectorPxSize, parentSize)
+
         val alignedPosition = alignment.align(
             IntPxSize(
-                IntPx(ceil(parentSize.width.value - defaultWidth.value).toInt()),
-                IntPx(ceil(parentSize.height.value - defaultHeight.value).toInt())
+                IntPx(ceil(parentWidth - (vectorWidth * scale)).toInt()),
+                IntPx(ceil(parentHeight - (vectorHeight * scale)).toInt())
             )
         )
 
-        val dx = alignedPosition.x.value.toFloat()
-        val dy = alignedPosition.y.value.toFloat()
-        canvas.translate(dx, dy)
-        vector.draw(canvas, tintColor, tintBlendMode)
-        canvas.translate(-dx, -dy)
+        val translateX = alignedPosition.x.value.toFloat()
+        val translateY = alignedPosition.y.value.toFloat()
+
+        // apply the scale to the root of the vector
+        vector.root.scaleX = (vectorWidth / viewportWidth) * scale
+        vector.root.scaleY = (vectorHeight / viewportHeight) * scale
+
+        canvas.withSave {
+            canvas.translate(translateX, translateY)
+            vector.draw(canvas, tintColor, tintBlendMode)
+        }
     }
 }
 
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
index b39758d..6c4c2c8 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/TextFieldDelegateTest.kt
@@ -64,11 +64,6 @@
     private lateinit var layoutCoordinates: LayoutCoordinates
     private lateinit var multiParagraphIntrinsics: MultiParagraphIntrinsics
 
-    private val identityOffsetMap = object : OffsetMap {
-        override fun originalToTransformed(offset: Int): Int = offset
-        override fun transformedToOriginal(offset: Int): Int = offset
-    }
-
     /**
      * Test implementation of offset map which doubles the offset in transformed text.
      */
@@ -100,7 +95,7 @@
             value = InputState(text = "Hello, World", selection = selection),
             selectionColor = selectionColor,
             hasFocus = true,
-            offsetMap = identityOffsetMap
+            offsetMap = OffsetMap.identityOffsetMap
         )
 
         verify(mDelegate, times(1)).paintBackground(
@@ -119,7 +114,7 @@
             textDelegate = mDelegate,
             value = InputState(text = "Hello, World", selection = cursor),
             hasFocus = true,
-            offsetMap = identityOffsetMap,
+            offsetMap = OffsetMap.identityOffsetMap,
             selectionColor = Color.Blue
         )
 
@@ -137,7 +132,7 @@
             textDelegate = mDelegate,
             value = InputState(text = "Hello, World", selection = cursor),
             hasFocus = false,
-            offsetMap = identityOffsetMap,
+            offsetMap = OffsetMap.identityOffsetMap,
             selectionColor = Color.Blue
         )
 
@@ -180,7 +175,7 @@
             position,
             mDelegate,
             processor,
-            identityOffsetMap,
+            OffsetMap.identityOffsetMap,
             onValueChange,
             textInputService,
             dummyInputSessionToken,
@@ -209,7 +204,7 @@
             position,
             mDelegate,
             processor,
-            identityOffsetMap,
+            OffsetMap.identityOffsetMap,
             onValueChange,
             textInputService,
             dummyInputSessionToken,
@@ -268,7 +263,7 @@
             textInputService,
             dummyInputSessionToken,
             true /* hasFocus */,
-            identityOffsetMap
+            OffsetMap.identityOffsetMap
         )
         verify(textInputService).notifyFocusedRect(eq(dummyInputSessionToken), any())
     }
@@ -284,7 +279,7 @@
             textInputService,
             dummyInputSessionToken,
             false /* hasFocus */,
-            identityOffsetMap
+            OffsetMap.identityOffsetMap
         )
         verify(textInputService, never()).notifyFocusedRect(any(), any())
     }
@@ -304,7 +299,7 @@
             textInputService,
             dummyInputSessionToken,
             true /* hasFocus */,
-            identityOffsetMap
+            OffsetMap.identityOffsetMap
         )
         verify(textInputService).notifyFocusedRect(eq(dummyInputSessionToken), any())
     }
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
index 47bcddc..e881c32 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
@@ -33,8 +33,6 @@
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.never
 import com.nhaarman.mockitokotlin2.verify
-import kotlinx.coroutines.ObsoleteCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineContext
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -45,12 +43,13 @@
 //  1. More complex multi-pointer scenarios testing how consumption affects firing events
 //  2. More complex multi-pointer scenarios testing how pointers effect consumption
 
-@ObsoleteCoroutinesApi
+@kotlinx.coroutines.ObsoleteCoroutinesApi
 @RunWith(JUnit4::class)
 class DoubleTapGestureDetectorTest {
 
     private val DoubleTapTimeoutMillis = 100.milliseconds
-    private val testContext = TestCoroutineContext()
+    @Suppress("DEPRECATION")
+    private val testContext = kotlinx.coroutines.test.TestCoroutineContext()
     private val onDoubleTap: (PxPosition) -> Unit = mock()
     private lateinit var mRecognizer: DoubleTapGestureRecognizer
 
diff --git a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
index 3b11a33..01bb32c 100644
--- a/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/LongPressGestureDetectorTest.kt
@@ -35,20 +35,19 @@
 import com.nhaarman.mockitokotlin2.mock
 import com.nhaarman.mockitokotlin2.never
 import com.nhaarman.mockitokotlin2.verify
-import kotlinx.coroutines.ObsoleteCoroutinesApi
-import kotlinx.coroutines.test.TestCoroutineContext
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
 import java.util.concurrent.TimeUnit
 
-@ObsoleteCoroutinesApi
+@kotlinx.coroutines.ObsoleteCoroutinesApi
 @RunWith(JUnit4::class)
 class LongPressGestureDetectorTest {
 
     private val LongPressTimeoutMillis = 100.milliseconds
-    private val testContext = TestCoroutineContext()
+    @Suppress("DEPRECATION")
+    private val testContext = kotlinx.coroutines.test.TestCoroutineContext()
     private val onLongPress: (PxPosition) -> Unit = mock()
     private lateinit var mRecognizer: LongPressGestureRecognizer
 
diff --git a/ui/ui-layout/api/0.1.0-dev03.txt b/ui/ui-layout/api/0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/0.1.0-dev03.txt
+++ b/ui/ui-layout/api/0.1.0-dev03.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/current.txt b/ui/ui-layout/api/current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/current.txt
+++ b/ui/ui-layout/api/current.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-layout/api/public_plus_experimental_0.1.0-dev03.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/public_plus_experimental_current.txt b/ui/ui-layout/api/public_plus_experimental_current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/public_plus_experimental_current.txt
+++ b/ui/ui-layout/api/public_plus_experimental_current.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/restricted_0.1.0-dev03.txt b/ui/ui-layout/api/restricted_0.1.0-dev03.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-layout/api/restricted_0.1.0-dev03.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/api/restricted_current.txt b/ui/ui-layout/api/restricted_current.txt
index 94ebc47..397cdbb 100644
--- a/ui/ui-layout/api/restricted_current.txt
+++ b/ui/ui-layout/api/restricted_current.txt
@@ -126,10 +126,10 @@
 
   public final class FlexKt {
     ctor public FlexKt();
-    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
+    method public static void Column(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.ColumnScope,kotlin.Unit> children);
     method public static void FlexColumn(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
     method public static void FlexRow(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, androidx.ui.layout.LayoutSize crossAxisSize = androidx.ui.layout.LayoutSize.Wrap, kotlin.jvm.functions.Function1<? super androidx.ui.layout.FlexChildren,kotlin.Unit> block);
-    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, androidx.ui.layout.CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
+    method public static void Row(androidx.ui.core.Modifier modifier = Modifier.None, androidx.ui.layout.MainAxisAlignment mainAxisAlignment = androidx.ui.layout.MainAxisAlignment.Start, kotlin.jvm.functions.Function1<? super androidx.ui.layout.RowScope,kotlin.Unit> children);
   }
 
   @androidx.ui.layout.LayoutScopeMarker public abstract sealed class FlexScope {
diff --git a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
index 62861c1..c989ad36 100644
--- a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
+++ b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/ComplexLayoutDemos.kt
@@ -52,7 +52,7 @@
 import androidx.ui.core.VerticalAlignmentLine
 import androidx.ui.core.sp
 import androidx.ui.layout.AlignmentLineOffset
-import androidx.ui.layout.CrossAxisAlignment
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.Wrap
 import androidx.ui.layout.samples.DrawRectangle
 import androidx.ui.layout.samples.SizedRectangle
@@ -387,9 +387,9 @@
 
 @Composable
 fun RowBaselineAlignment() {
-    Row(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(FirstBaseline)) {
-        Text("First text")
-        Column {
+    Row {
+        Text("First text", modifier = Gravity.RelativeToSiblings(FirstBaseline))
+        Column(modifier = Gravity.RelativeToSiblings(FirstBaseline)) {
             SizedRectangle(color = Color.Blue, width = 10.dp, height = 50.dp)
             Padding(30.dp) {
                 Text("Second text", style = TextStyle(fontSize = 45.sp))
diff --git a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
index c46cab9..198ed8c 100644
--- a/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
+++ b/ui/ui-layout/integration-tests/layout-demos/src/main/java/androidx/ui/layout/demos/LayoutActivity.kt
@@ -23,7 +23,6 @@
 import androidx.ui.core.dp
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.HeightSpacer
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.layout.Row
@@ -32,10 +31,12 @@
 import androidx.ui.graphics.Color
 import androidx.ui.text.TextStyle
 import androidx.compose.Composable
+import androidx.ui.core.Modifier
 import androidx.ui.core.setContent
 import androidx.ui.core.sp
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.layout.ExpandedWidth
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.samples.DrawRectangle
 
 class LayoutActivity : Activity() {
@@ -64,10 +65,7 @@
 @Composable
 fun LayoutDemo() {
     val lightGrey = Color(0xFFCFD8DC)
-    Column(
-        mainAxisAlignment = MainAxisAlignment.Start,
-        crossAxisAlignment = CrossAxisAlignment.Start
-    ) {
+    Column(mainAxisAlignment = MainAxisAlignment.Start) {
         Text(text = "Row", style = TextStyle(fontSize = 48.sp))
         ContainerWithBackground(width = ExampleSize, color = lightGrey) {
             Row(ExpandedWidth) {
@@ -97,22 +95,16 @@
         }
         HeightSpacer(height = 24.dp)
         ContainerWithBackground(width = ExampleSize, color = lightGrey) {
-            Row(
-                ExpandedWidth,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Row(ExpandedWidth) {
                 PurpleSquare()
                 CyanSquare()
             }
         }
         HeightSpacer(height = 24.dp)
         ContainerWithBackground(width = ExampleSize, color = lightGrey) {
-            Row(
-                ExpandedWidth,
-                crossAxisAlignment = CrossAxisAlignment.End
-            ) {
-                PurpleSquare()
-                CyanSquare()
+            Row(ExpandedWidth) {
+                PurpleSquare(Gravity.Bottom)
+                CyanSquare(Gravity.Bottom)
             }
         }
         HeightSpacer(height = 24.dp)
@@ -146,22 +138,16 @@
             }
             WidthSpacer(width = 24.dp)
             ContainerWithBackground(height = ExampleSize, color = lightGrey) {
-                Column(
-                    ExpandedHeight,
-                    crossAxisAlignment = CrossAxisAlignment.Start
-                ) {
+                Column(ExpandedHeight) {
                     PurpleSquare()
                     CyanSquare()
                 }
             }
             WidthSpacer(width = 24.dp)
             ContainerWithBackground(height = ExampleSize, color = lightGrey) {
-                Column(
-                    ExpandedHeight,
-                    crossAxisAlignment = CrossAxisAlignment.End
-                ) {
-                    PurpleSquare()
-                    CyanSquare()
+                Column(ExpandedHeight) {
+                    PurpleSquare(Gravity.End)
+                    CyanSquare(Gravity.End)
                 }
             }
         }
@@ -169,15 +155,15 @@
 }
 
 @Composable
-fun PurpleSquare() {
-    Container(width = BigSize, height = BigSize) {
+fun PurpleSquare(modifier: Modifier = Modifier.None) {
+    Container(width = BigSize, height = BigSize, modifier = modifier) {
         DrawRectangle(color = Color(0xFF6200EE))
     }
 }
 
 @Composable
-fun CyanSquare() {
-    Container(width = SmallSize, height = SmallSize) {
+fun CyanSquare(modifier: Modifier = Modifier.None) {
+    Container(width = SmallSize, height = SmallSize, modifier = modifier) {
         DrawRectangle(color = Color(0xFF03DAC6))
     }
 }
diff --git a/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt b/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
index 1063a67..14f1f30 100644
--- a/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
+++ b/ui/ui-layout/integration-tests/samples/src/main/java/androidx/ui/layout/samples/IntrinsicSample.kt
@@ -30,6 +30,7 @@
 import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.DpConstraints
 import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.ExpandedWidth
 import androidx.ui.layout.FlexRow
 import androidx.ui.layout.MaxIntrinsicHeight
 import androidx.ui.layout.MaxIntrinsicWidth
@@ -43,7 +44,7 @@
  * Here [MinIntrinsicWidth] is adding a speculative width measurement pass for the [Column],
  * whose minimum intrinsic width will correspond to the preferred width of the largest
  * [ConstrainedBox]. Then [MinIntrinsicWidth] will measure the [Column] with tight width, the same
- * as the premeasured minimum intrinsic width, which due to [CrossAxisAlignment.Stretch] will force
+ * as the premeasured minimum intrinsic width, which due to [ExpandedWidth] will force
  * the [ConstrainedBox]s to use the same width.
  */
 @Sampled
@@ -51,17 +52,23 @@
 fun SameWidthBoxes() {
     Wrap {
         MinIntrinsicWidth {
-            Column(
-                ExpandedHeight,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(width = 20.dp, height = 10.dp)) {
+            Column(ExpandedHeight) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(width = 20.dp, height = 10.dp),
+                    modifier = ExpandedWidth
+                ) {
                     DrawShape(RectangleShape, Color.Gray)
                 }
-                ConstrainedBox(DpConstraints.tightConstraints(width = 30.dp, height = 10.dp)) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(width = 30.dp, height = 10.dp),
+                    modifier = ExpandedWidth
+                ) {
                     DrawShape(RectangleShape, Color.Blue)
                 }
-                ConstrainedBox(DpConstraints.tightConstraints(width = 10.dp, height = 10.dp)) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(width = 10.dp, height = 10.dp),
+                    modifier = ExpandedWidth
+                ) {
                     DrawShape(RectangleShape, Color.Magenta)
                 }
             }
@@ -106,7 +113,7 @@
  * Here [MaxIntrinsicWidth] is adding a speculative width measurement pass for the [Column],
  * whose maximum intrinsic width will correspond to the preferred width of the largest
  * [ConstrainedBox]. Then [MaxIntrinsicWidth] will measure the [Column] with tight width, the same
- * as the premeasured maximum intrinsic width, which due to [CrossAxisAlignment.Stretch] will force
+ * as the premeasured maximum intrinsic width, which due to [ExpandedWidth] modifiers will force
  * the [ConstrainedBox]s to use the same width.
  */
 @Sampled
@@ -114,19 +121,16 @@
 fun SameWidthTextBoxes() {
     Wrap {
         MaxIntrinsicWidth {
-            Column(
-                ExpandedHeight,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                Wrap {
+            Column(ExpandedHeight) {
+                Container(ExpandedWidth) {
                     DrawShape(RectangleShape, Color.Gray)
                     Text("Short text")
                 }
-                Wrap {
+                Container(ExpandedWidth) {
                     DrawShape(RectangleShape, Color.Blue)
                     Text("Extremely long text giving the width of its siblings")
                 }
-                Wrap {
+                Container(ExpandedWidth) {
                     DrawShape(RectangleShape, Color.Magenta)
                     Text("Medium length text")
                 }
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
index e20dd16..81a145d 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/FlexTest.kt
@@ -553,107 +553,6 @@
 
     // region Cross axis alignment tests in Row
     @Test
-    fun testRow_withStartCrossAxisAlignment() = withDensity(density) {
-        val sizeDp = 50.dp
-        val size = sizeDp.toIntPx()
-
-        val drawLatch = CountDownLatch(2)
-        val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
-        val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
-        show {
-            Align(Alignment.CenterLeft) {
-                Row(crossAxisAlignment = CrossAxisAlignment.Start) {
-                    Container(width = sizeDp, height = sizeDp) {
-                        OnPositioned( coordinates ->
-                            childSize[0] = coordinates.size
-                            childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
-                        OnPositioned( coordinates ->
-                            childSize[1] = coordinates.size
-                            childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-                }
-            }
-        }
-        drawLatch.await(1, TimeUnit.SECONDS)
-
-        val root = findAndroidComposeView()
-        waitForDraw(root)
-
-        assertEquals(PxSize(size, size), childSize[0])
-        assertEquals(
-            PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
-            childSize[1]
-        )
-        assertEquals(
-            PxPosition(0.px, (root.height.px / 2 - size.toPx()).round().toPx()),
-            childPosition[0]
-        )
-        assertEquals(
-            PxPosition(size.toPx(), (root.height.px / 2 - size.toPx()).round().toPx()),
-            childPosition[1]
-        )
-    }
-
-    @Test
-    fun testRow_withEndCrossAxisAlignment() = withDensity(density) {
-        val sizeDp = 50.dp
-        val size = sizeDp.toIntPx()
-
-        val drawLatch = CountDownLatch(2)
-        val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
-        val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
-        show {
-            Align(Alignment.CenterLeft) {
-                Row(crossAxisAlignment = CrossAxisAlignment.End) {
-                    Container(width = sizeDp, height = sizeDp) {
-                        OnPositioned( coordinates ->
-                            childSize[0] = coordinates.size
-                            childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
-                        OnPositioned( coordinates ->
-                            childSize[1] = coordinates.size
-                            childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-                }
-            }
-        }
-        drawLatch.await(1, TimeUnit.SECONDS)
-
-        val root = findAndroidComposeView()
-        waitForDraw(root)
-
-        assertEquals(PxSize(size, size), childSize[0])
-        assertEquals(
-            PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
-            childSize[1]
-        )
-        assertEquals(
-            PxPosition(
-                0.px, ((root.height.px + (sizeDp.toPx() * 2)
-                    .round().toPx()) / 2 - size.toPx()).round().toPx()
-            ),
-            childPosition[0]
-        )
-        assertEquals(
-            PxPosition(size.toPx(), (root.height.px / 2 - size.toPx()).round().toPx()),
-            childPosition[1]
-        )
-    }
-
-    @Test
     fun testRow_withStretchCrossAxisAlignment() = withDensity(density) {
         val sizeDp = 50.dp
         val size = sizeDp.toIntPx()
@@ -663,8 +562,8 @@
         val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
         show {
             Align(Alignment.CenterLeft) {
-                Row(crossAxisAlignment = CrossAxisAlignment.Stretch) {
-                    Container(width = sizeDp, height = sizeDp) {
+                Row {
+                    Container(width = sizeDp, height = sizeDp, modifier = ExpandedHeight) {
                         OnPositioned( coordinates ->
                             childSize[0] = coordinates.size
                             childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -672,7 +571,11 @@
                         })
                     }
 
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
+                    Container(
+                        width = (sizeDp * 2),
+                        height = (sizeDp * 2),
+                        modifier = ExpandedHeight
+                    ) {
                         OnPositioned( coordinates ->
                             childSize[1] = coordinates.size
                             childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -841,108 +744,6 @@
 
     // region Cross axis alignment tests in Column
     @Test
-    fun testColumn_withStartCrossAxisAlignment() = withDensity(density) {
-        val sizeDp = 50.dp
-        val size = sizeDp.toIntPx()
-
-        val drawLatch = CountDownLatch(2)
-        val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
-        val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
-        show {
-            Align(Alignment.TopCenter) {
-                Column(crossAxisAlignment = CrossAxisAlignment.Start) {
-                    Container(width = sizeDp, height = sizeDp) {
-                        OnPositioned( coordinates ->
-                            childSize[0] = coordinates.size
-                            childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
-                        OnPositioned( coordinates ->
-                            childSize[1] = coordinates.size
-                            childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-                }
-            }
-        }
-        drawLatch.await(1, TimeUnit.SECONDS)
-
-        val root = findAndroidComposeView()
-        waitForDraw(root)
-
-        assertEquals(PxSize(size, size), childSize[0])
-        assertEquals(
-            PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
-            childSize[1]
-        )
-        assertEquals(
-            PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), 0.px),
-            childPosition[0]
-        )
-        assertEquals(
-            PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), size.toPx()),
-            childPosition[1]
-        )
-    }
-
-    @Test
-    fun testColumn_withEndCrossAxisAlignment() = withDensity(density) {
-        val sizeDp = 50.dp
-        val size = sizeDp.toIntPx()
-
-        val drawLatch = CountDownLatch(2)
-        val childSize = arrayOf(PxSize(-1.px, -1.px), PxSize(-1.px, -1.px))
-        val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
-        show {
-            Align(Alignment.TopCenter) {
-                Column(crossAxisAlignment = CrossAxisAlignment.End) {
-                    Container(width = sizeDp, height = sizeDp) {
-                        OnPositioned( coordinates ->
-                            childSize[0] = coordinates.size
-                            childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
-                        OnPositioned( coordinates ->
-                            childSize[1] = coordinates.size
-                            childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                            drawLatch.countDown()
-                        })
-                    }
-                }
-            }
-        }
-        drawLatch.await(1, TimeUnit.SECONDS)
-
-        val root = findAndroidComposeView()
-        waitForDraw(root)
-
-        assertEquals(PxSize(size, size), childSize[0])
-        assertEquals(
-            PxSize((sizeDp.toPx() * 2).round(), (sizeDp.toPx() * 2).round()),
-            childSize[1]
-        )
-        assertEquals(
-            PxPosition(
-                (((root.width.px + (sizeDp.toPx() * 2)
-                    .round().toPx()) / 2).round() - size).toPx(),
-                0.px
-            ),
-            childPosition[0]
-        )
-        assertEquals(
-            PxPosition((root.width.px / 2 - size.toPx()).round().toPx(), size.toPx()),
-            childPosition[1]
-        )
-    }
-
-    @Test
     fun testColumn_withStretchCrossAxisAlignment() = withDensity(density) {
         val sizeDp = 50.dp
         val size = sizeDp.toIntPx()
@@ -952,8 +753,8 @@
         val childPosition = arrayOf(PxPosition(-1.px, -1.px), PxPosition(-1.px, -1.px))
         show {
             Align(Alignment.TopCenter) {
-                Column(crossAxisAlignment = CrossAxisAlignment.Stretch) {
-                    Container(width = sizeDp, height = sizeDp) {
+                Column {
+                    Container(width = sizeDp, height = sizeDp, modifier = ExpandedWidth) {
                         OnPositioned( coordinates ->
                             childSize[0] = coordinates.size
                             childPosition[0] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -961,7 +762,9 @@
                         })
                     }
 
-                    Container(width = (sizeDp * 2), height = (sizeDp * 2)) {
+                    Container(
+                        width = (sizeDp * 2), height = (sizeDp * 2), modifier = ExpandedWidth
+                    ) {
                         OnPositioned( coordinates ->
                             childSize[1] = coordinates.size
                             childPosition[1] = coordinates.localToGlobal(PxPosition(0.px, 0.px))
@@ -2652,40 +2455,24 @@
                 ) { }
             }
         }, @Composable {
-            Row(
-                ExpandedWidth,
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Start) {
                 Container(AspectRatio(2f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
             }
         }, @Composable {
-            Row(
-                ExpandedWidth,
-                mainAxisAlignment = MainAxisAlignment.Center,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                Container(AspectRatio(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+            Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.Center) {
+                Container(Gravity.Center wraps AspectRatio(2f)) { }
+                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.Center) { }
             }
         }, @Composable {
-            Row(
-                ExpandedWidth,
-                mainAxisAlignment = MainAxisAlignment.End,
-                crossAxisAlignment = CrossAxisAlignment.End
-            ) {
-                Container(AspectRatio(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+            Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.End) {
+                Container(Gravity.Bottom wraps AspectRatio(2f)) { }
+                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.Bottom) { }
             }
         }, @Composable {
-            Row(
-                ExpandedWidth,
-                mainAxisAlignment = MainAxisAlignment.SpaceAround,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                Container(AspectRatio(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+            Row(ExpandedWidth, mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+                Container(ExpandedHeight wraps AspectRatio(2f)) { }
+                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), ExpandedHeight) { }
             }
         }, @Composable {
             Row(
@@ -2746,44 +2533,65 @@
                 ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Gravity.Bottom) { }
             }
         }, @Composable {
-            Row(
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Row(mainAxisAlignment = MainAxisAlignment.Start) {
                 ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
                 Container(AspectRatio(2f) wraps Flexible(2f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
             }
         }, @Composable {
-            Row(
-                mainAxisAlignment = MainAxisAlignment.Center,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
-                Container(AspectRatio(2f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+            Row(mainAxisAlignment = MainAxisAlignment.Center) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = Flexible(3f) wraps Gravity.Center
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+                    modifier = Flexible(2f) wraps Gravity.Center
+                ) { }
+                Container(
+                    AspectRatio(2f) wraps Flexible(2f) wraps Gravity.Center
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = Gravity.Center
+                ) { }
             }
         }, @Composable {
-            Row(
-                mainAxisAlignment = MainAxisAlignment.End,
-                crossAxisAlignment = CrossAxisAlignment.End
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
-                Container(AspectRatio(2f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+            Row(mainAxisAlignment = MainAxisAlignment.End) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = Flexible(3f) wraps Gravity.Bottom
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+                    modifier = Flexible(2f) wraps Gravity.Bottom
+                ) { }
+                Container(
+                    AspectRatio(2f) wraps Flexible(2f) wraps Gravity.Bottom
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = Gravity.Bottom
+                ) { }
             }
         }, @Composable {
-            Row(
-                mainAxisAlignment = MainAxisAlignment.SpaceAround,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 40.dp), Flexible(2f)) { }
-                Container(AspectRatio(2f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
+            Row(mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = Flexible(3f) wraps ExpandedHeight
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 40.dp),
+                    modifier = Flexible(2f) wraps ExpandedHeight
+                ) { }
+                Container(
+                    AspectRatio(2f) wraps Flexible(2f) wraps ExpandedHeight
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(20.dp, 30.dp),
+                    modifier = ExpandedHeight
+                ) { }
             }
         }, @Composable {
             Row(mainAxisAlignment = MainAxisAlignment.SpaceBetween) {
@@ -2873,40 +2681,24 @@
                 ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
             }
         }, @Composable {
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.Start) {
                 Container(AspectRatio(2f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
             }
         }, @Composable {
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.Center,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                Container(AspectRatio(2f)) { }
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.Center) {
+                Container(Gravity.Center wraps AspectRatio(2f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
             }
         }, @Composable {
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.End,
-                crossAxisAlignment = CrossAxisAlignment.End
-            ) {
-                Container(AspectRatio(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.End) {
+                Container(Gravity.End wraps AspectRatio(2f)) { }
+                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), Gravity.End) { }
             }
         }, @Composable {
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.SpaceAround,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                Container(AspectRatio(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp)) { }
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+                Container(ExpandedWidth wraps AspectRatio(2f)) { }
+                ConstrainedBox(DpConstraints.tightConstraints(50.dp, 40.dp), ExpandedWidth) { }
             }
         }, @Composable {
             Column(
@@ -2967,44 +2759,65 @@
                 ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Gravity.End) { }
             }
         }, @Composable {
-            Column(
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            Column(mainAxisAlignment = MainAxisAlignment.Start) {
                 ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
                 Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
                 ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
             }
         }, @Composable {
-            Column(
-                mainAxisAlignment = MainAxisAlignment.Center,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
-                Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+            Column(mainAxisAlignment = MainAxisAlignment.Center) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = Flexible(3f) wraps Gravity.Center
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+                    modifier = Flexible(2f) wraps Gravity.Center
+                ) { }
+                Container(
+                    AspectRatio(0.5f) wraps Flexible(2f) wraps Gravity.Center
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = Gravity.Center
+                ) { }
             }
         }, @Composable {
-            Column(
-                mainAxisAlignment = MainAxisAlignment.End,
-                crossAxisAlignment = CrossAxisAlignment.End
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
-                Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+            Column(mainAxisAlignment = MainAxisAlignment.End) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = Flexible(3f) wraps Gravity.End
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+                    modifier = Flexible(2f) wraps Gravity.End
+                ) { }
+                Container(
+                    AspectRatio(0.5f) wraps Flexible(2f) wraps Gravity.End
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = Gravity.End
+                ) { }
             }
         }, @Composable {
-            Column(
-                mainAxisAlignment = MainAxisAlignment.SpaceAround,
-                crossAxisAlignment = CrossAxisAlignment.Stretch
-            ) {
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp), Flexible(3f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(40.dp, 30.dp), Flexible(2f)) { }
-                Container(AspectRatio(0.5f) wraps Flexible(2f)) { }
-                ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
+            Column(mainAxisAlignment = MainAxisAlignment.SpaceAround) {
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = Flexible(3f) wraps ExpandedWidth
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(40.dp, 30.dp),
+                    modifier = Flexible(2f) wraps ExpandedWidth
+                ) { }
+                Container(
+                    AspectRatio(0.5f) wraps Flexible(2f) wraps ExpandedWidth
+                ) { }
+                ConstrainedBox(
+                    constraints = DpConstraints.tightConstraints(30.dp, 20.dp),
+                    modifier = ExpandedWidth
+                ) { }
             }
         }, @Composable {
             Column(mainAxisAlignment = MainAxisAlignment.SpaceBetween) {
@@ -3086,10 +2899,7 @@
                 }
             }
         }, @Composable {
-            FlexRow(
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            FlexRow(mainAxisAlignment = MainAxisAlignment.Start) {
                 expanded(flex = 3f) {
                     ConstrainedBox(DpConstraints.tightConstraints(20.dp, 30.dp)) { }
                 }
@@ -3253,10 +3063,7 @@
                 }
             }
         }, @Composable {
-            FlexColumn(
-                mainAxisAlignment = MainAxisAlignment.Start,
-                crossAxisAlignment = CrossAxisAlignment.Start
-            ) {
+            FlexColumn(mainAxisAlignment = MainAxisAlignment.Start) {
                 expanded(flex = 3f) {
                     ConstrainedBox(DpConstraints.tightConstraints(30.dp, 20.dp)) { }
                 }
@@ -3403,32 +3210,34 @@
     }
 
     @Test
-    fun testRow_alignmentUsingAlignmentKey() = withDensity(density) {
+    fun testFlexRow_alignmentUsingAlignmentKey() = withDensity(density) {
         val TestAlignmentLine = HorizontalAlignmentLine(::min)
         val rowSize = Ref<PxSize>()
         val childPosition = arrayOf<Ref<PxPosition>>(Ref(), Ref(), Ref())
         val layoutLatch = CountDownLatch(4)
         show {
             Wrap {
-                Row(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
-                    SaveLayoutInfo(rowSize, Ref(), layoutLatch)
-                    OnChildPositioned({ coordinates ->
-                        childPosition[0].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 10.ipx))
-                    }
-                    OnChildPositioned({ coordinates ->
-                        childPosition[1].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(10.ipx, 10.ipx, mapOf())
-                    }
-                    OnChildPositioned({ coordinates ->
-                        childPosition[2].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 20.ipx))
+                FlexRow(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
+                    inflexible {
+                        SaveLayoutInfo(rowSize, Ref(), layoutLatch)
+                        OnChildPositioned({ coordinates ->
+                            childPosition[0].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 10.ipx))
+                        }
+                        OnChildPositioned({ coordinates ->
+                            childPosition[1].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(10.ipx, 10.ipx, mapOf())
+                        }
+                        OnChildPositioned({ coordinates ->
+                            childPosition[2].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(10.ipx, 30.ipx, mapOf(TestAlignmentLine to 20.ipx))
+                        }
                     }
                 }
             }
@@ -3442,32 +3251,36 @@
     }
 
     @Test
-    fun testColumn_alignmentUsingAlignmentKey() = withDensity(density) {
+    fun testFlexColumn_alignmentUsingAlignmentKey() = withDensity(density) {
         val TestAlignmentLine = VerticalAlignmentLine(::min)
         val columnSize = Ref<PxSize>()
         val childPosition = arrayOf<Ref<PxPosition>>(Ref(), Ref(), Ref())
         val layoutLatch = CountDownLatch(4)
         show {
             Wrap {
-                Column(crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)) {
-                    SaveLayoutInfo(columnSize, Ref(), layoutLatch)
-                    OnChildPositioned({ coordinates ->
-                        childPosition[0].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 10.ipx))
-                    }
-                    OnChildPositioned({ coordinates ->
-                        childPosition[1].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(10.ipx, 10.ipx, mapOf())
-                    }
-                    OnChildPositioned({ coordinates ->
-                        childPosition[2].value = coordinates.localToGlobal(PxPosition(0.px, 0.px))
-                        layoutLatch.countDown()
-                    }) {
-                        FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 20.ipx))
+                FlexColumn(
+                    crossAxisAlignment = CrossAxisAlignment.AlignmentLine(TestAlignmentLine)
+                ) {
+                    inflexible {
+                        SaveLayoutInfo(columnSize, Ref(), layoutLatch)
+                        OnChildPositioned({ coordinates ->
+                            childPosition[0].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 10.ipx))
+                        }
+                        OnChildPositioned({ coordinates ->
+                            childPosition[1].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(10.ipx, 10.ipx, mapOf())
+                        }
+                        OnChildPositioned({ coordinates ->
+                            childPosition[2].value = coordinates.localToGlobal(PxPosition.Origin)
+                            layoutLatch.countDown()
+                        }) {
+                            FixedSizeLayout(30.ipx, 10.ipx, mapOf(TestAlignmentLine to 20.ipx))
+                        }
                     }
                 }
             }
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
index 1deede0..a3d795e3 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Flex.kt
@@ -311,21 +311,18 @@
  *
  * @param mainAxisAlignment The alignment of the layout's children in main axis direction.
  * Default is [MainAxisAlignment.Start].
- * @param crossAxisAlignment The alignment of the layout's children in cross axis direction.
- * Default is [CrossAxisAlignment.Start].
  */
 @Composable
 fun Row(
     modifier: Modifier = Modifier.None,
     mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.Start,
-    crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Start,
     children: @Composable() RowScope.() -> Unit
 ) {
     FlexLayout(
         orientation = LayoutOrientation.Horizontal,
         modifier = modifier,
         mainAxisAlignment = mainAxisAlignment,
-        crossAxisAlignment = crossAxisAlignment,
+        crossAxisAlignment = CrossAxisAlignment.Start,
         crossAxisSize = LayoutSize.Wrap,
         children = { RowScope().children() }
     )
@@ -344,21 +341,18 @@
  *
  * @param mainAxisAlignment The alignment of the layout's children in main axis direction.
  * Default is [MainAxisAlignment.Start].
- * @param crossAxisAlignment The alignment of the layout's children in cross axis direction.
- * Default is [CrossAxisAlignment.Start].
  */
 @Composable
 fun Column(
     modifier: Modifier = Modifier.None,
     mainAxisAlignment: MainAxisAlignment = MainAxisAlignment.Start,
-    crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Start,
     children: @Composable() ColumnScope.() -> Unit
 ) {
     FlexLayout(
         orientation = LayoutOrientation.Vertical,
         modifier = modifier,
         mainAxisAlignment = mainAxisAlignment,
-        crossAxisAlignment = crossAxisAlignment,
+        crossAxisAlignment = CrossAxisAlignment.Start,
         crossAxisSize = LayoutSize.Wrap,
         children = { ColumnScope().children() }
     )
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
index 414ba6f..672fc95 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/AppBarActivity.kt
@@ -24,7 +24,6 @@
 import androidx.ui.core.dp
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.FlexColumn
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.material.RadioGroup
@@ -94,8 +93,7 @@
                 flexible(1f) {
                     Column(
                         ExpandedHeight,
-                        mainAxisAlignment = MainAxisAlignment.SpaceBetween,
-                        crossAxisAlignment = CrossAxisAlignment.Center
+                        mainAxisAlignment = MainAxisAlignment.SpaceBetween
                     ) {
                         DemoText("TopAppBar options")
                         RadioGroup {
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
index 43e54c6..5af9694 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/ButtonActivity.kt
@@ -37,7 +37,6 @@
 import androidx.compose.unaryPlus
 import androidx.ui.layout.Center
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.material.Button
@@ -54,11 +53,7 @@
     override fun materialContent() {
         val onClick: () -> Unit = { Log.e("ButtonDemo", "onClick") }
         Center {
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.SpaceEvenly,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceEvenly) {
                 ContainedButtonSample(onClick)
 
                 OutlinedButtonSample(onClick)
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
index 4ae3b55..37bc67d 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/DividersSpacersActivity.kt
@@ -24,8 +24,8 @@
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.HeightSpacer
 import androidx.ui.layout.Row
 import androidx.ui.layout.WidthSpacer
@@ -77,15 +77,17 @@
         val avatarSize = ItemSize - ItemPadding * 2
         val textStyle = (+MaterialTheme.typography()).body1
         Container(height = ItemSize, padding = EdgeInsets(ItemPadding)) {
-            Row(crossAxisAlignment = CrossAxisAlignment.Center) {
+            Row {
                 if (color != null) {
                     ColoredRect(
                         width = avatarSize,
                         height = avatarSize,
-                        color = color)
+                        color = color,
+                        modifier = Gravity.Center
+                    )
                     WidthSpacer(width = ItemPadding)
                 }
-                Text(text = text, style = textStyle)
+                Text(text = text, style = textStyle, modifier = Gravity.Center)
             }
         }
     }
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
index b294606..bb85e5b 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/FloatingActionButtonActivity.kt
@@ -21,8 +21,8 @@
 import androidx.ui.graphics.imageFromResource
 import androidx.ui.layout.Center
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.material.FloatingActionButton
 
@@ -33,14 +33,18 @@
         val icon = imageFromResource(resources, R.drawable.ic_favorite)
         Center {
             val onClick: () -> Unit = { Log.e("FABDemo", "onClick") }
-            Column(
-                ExpandedHeight,
-                mainAxisAlignment = MainAxisAlignment.SpaceEvenly,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
-                FloatingActionButton(icon = icon, >
-                FloatingActionButton(text = "EXTENDED", >
-                FloatingActionButton(icon = icon, text = "ADD TO FAVS", >
+            Column(ExpandedHeight, mainAxisAlignment = MainAxisAlignment.SpaceEvenly) {
+                FloatingActionButton(icon = icon,  modifier = Gravity.Center)
+                FloatingActionButton(
+                    text = "EXTENDED",
+                    >
+                    modifier = Gravity.Center
+                )
+                FloatingActionButton(
+                    icon = icon, text = "ADD TO FAVS",
+                    >
+                    modifier = Gravity.Center
+                )
             }
         }
     }
diff --git a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
index d4d3b78..5fd2c06 100644
--- a/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
+++ b/ui/ui-material/integration-tests/material-demos/src/main/java/androidx/ui/material/demos/SelectionControlsActivity.kt
@@ -22,7 +22,6 @@
 import androidx.ui.core.dp
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
 import androidx.ui.layout.Padding
 import androidx.ui.material.MaterialTheme
@@ -42,7 +41,7 @@
 
         Surface(color = Color.White) {
             Padding(padding = padding) {
-                Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                Column {
                     Text(text = "Checkbox", style = headerStyle)
                     Padding(padding = padding) {
                         TriStateCheckboxSample()
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
index 3ee7de7..cb1c976 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyAlertDialog.kt
@@ -22,8 +22,8 @@
 import androidx.ui.core.dp
 import androidx.ui.foundation.shape.RectangleShape
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
+import androidx.ui.layout.ExpandedWidth
 import androidx.ui.layout.Spacing
 import androidx.ui.material.AlertDialog
 import androidx.ui.material.Button
@@ -43,12 +43,17 @@
             text = { Text(bodyText) },
             buttons = {
                 val style = TextButtonStyle(RectangleShape).copy(paddings = EdgeInsets(16.dp))
-                Column(crossAxisAlignment = CrossAxisAlignment.Stretch) {
+                Column {
                     Divider(
                         Spacing(left = 12.dp, right = 12.dp),
                         color = (+MaterialTheme.colors()).onSurface.copy(alpha = 0.2f)
                     )
-                    Button(text = buttonText,  style = style)
+                    Button(
+                        text = buttonText,
+                        >
+                        style = style,
+                        modifier = ExpandedWidth
+                    )
                 }
             }
         )
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
index 163762b..93ecb03 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyCards.kt
@@ -28,10 +28,10 @@
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.ExpandedWidth
 import androidx.ui.layout.FixedSpacer
 import androidx.ui.layout.FlexRow
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.HeightSpacer
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.layout.Row
@@ -159,9 +159,17 @@
                             Container(height = 300.dp, expanded = true) {
                                 DrawAnimatedCircle(accountsProportion, colors)
                             }
-                            Column(crossAxisAlignment = CrossAxisAlignment.Center) {
-                                Text(text = "Total", style = (+MaterialTheme.typography()).body1)
-                                Text(text = "$12,132.49", style = (+MaterialTheme.typography()).h3)
+                            Column {
+                                Text(
+                                    text = "Total",
+                                    style = (+MaterialTheme.typography()).body1,
+                                    modifier = Gravity.Center
+                                )
+                                Text(
+                                    text = "$12,132.49",
+                                    style = (+MaterialTheme.typography()).h3,
+                                    modifier = Gravity.Center
+                                )
                             }
                         }
                     }
@@ -210,7 +218,7 @@
         inflexible {
             AccountIndicator(color = color)
             WidthSpacer(width = 8.dp)
-            Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+            Column {
                 Text(text = name, style = (+MaterialTheme.typography()).body1)
                 Text(text = "•••••$number", style = (+MaterialTheme.typography()).subtitle1)
             }
@@ -289,9 +297,17 @@
                     Container(height = 300.dp, expanded = true) {
                         DrawAnimatedCircle(accountsProportion, colors)
                     }
-                    Column(crossAxisAlignment = CrossAxisAlignment.Center) {
-                        Text(text = "Due", style = (+MaterialTheme.typography()).body1)
-                        Text(text = "$1,810.00", style = (+MaterialTheme.typography()).h3)
+                    Column {
+                        Text(
+                            text = "Due",
+                            style = (+MaterialTheme.typography()).body1,
+                            modifier = Gravity.Center
+                        )
+                        Text(
+                            text = "$1,810.00",
+                            style = (+MaterialTheme.typography()).h3,
+                            modifier = Gravity.Center
+                        )
                     }
                 }
             }
diff --git a/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt b/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
index 9fc9fc9..ef10226 100644
--- a/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
+++ b/ui/ui-material/integration-tests/samples/src/main/java/androidx/ui/material/samples/TabSamples.kt
@@ -40,7 +40,6 @@
 import androidx.ui.layout.Center
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
 import androidx.ui.layout.FlexColumn
 import androidx.ui.layout.Padding
@@ -48,6 +47,7 @@
 import androidx.ui.material.TabRow
 import androidx.ui.graphics.Image
 import androidx.ui.layout.ExpandedHeight
+import androidx.ui.layout.Gravity
 import androidx.ui.material.MaterialTheme
 
 @Sampled
@@ -289,14 +289,15 @@
 fun FancyTab(title: String, onClick: () -> Unit, selected: Boolean) {
     MutuallyExclusiveSetItem(selected = selected,  {
         Container(height = 50.dp, padding = EdgeInsets(10.dp)) {
-            Column(
-                ExpandedHeight,
-                crossAxisAlignment = CrossAxisAlignment.Center
-            ) {
+            Column(ExpandedHeight) {
                 val color = if (selected) Color.Red else Color.Gray
-                ColoredRect(height = 10.dp, width = 10.dp, color = color)
+                ColoredRect(height = 10.dp, width = 10.dp, color = color, modifier = Gravity.Center)
                 Padding(5.dp) {
-                    Text(text = title, style = (+MaterialTheme.typography()).body1)
+                    Text(
+                        text = title,
+                        style = (+MaterialTheme.typography()).body1,
+                        modifier = Gravity.Center
+                    )
                 }
             }
         }
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt b/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
index f84da65..4959f59 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/AlertDialog.kt
@@ -25,7 +25,6 @@
 import androidx.ui.foundation.shape.corner.RoundedCornerShape
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
 import androidx.ui.layout.ExpandedWidth
 import androidx.ui.layout.HeightSpacer
@@ -118,7 +117,7 @@
         MaterialTheme(colors = currentColors, typography = currentTypography) {
             Surface(shape = AlertDialogShape) {
                 Container(width = AlertDialogWidth) {
-                    Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                    Column {
                         if (title != null) {
                             Container(
                                 alignment = Alignment.CenterLeft,
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt b/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
index c1b33c1..76f5268 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/DataTable.kt
@@ -38,9 +38,9 @@
 import androidx.ui.graphics.Image
 import androidx.ui.layout.Column
 import androidx.ui.layout.Container
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.EdgeInsets
 import androidx.ui.layout.Expanded
+import androidx.ui.layout.Gravity
 import androidx.ui.layout.MainAxisAlignment
 import androidx.ui.layout.Row
 import androidx.ui.layout.Table
@@ -483,48 +483,49 @@
         Column {
             table()
             Container(height = dataRowHeight, padding = cellSpacing) {
-                Row(
-                    Expanded,
-                    mainAxisAlignment = MainAxisAlignment.End,
-                    crossAxisAlignment = CrossAxisAlignment.Center
-                ) {
+                Row(Expanded, mainAxisAlignment = MainAxisAlignment.End) {
                     val pages = (rows.size - 1) / pagination.rowsPerPage + 1
                     val startRow = pagination.rowsPerPage * pagination.page
                     val endRow = (startRow + pagination.rowsPerPage).coerceAtMost(rows.size)
+                    val modifier = Gravity.Center
 
                     // TODO(calintat): Replace this with a dropdown menu whose items are taken
                     //  from availableRowsPerPage (filtered to those that are in the range
                     //  0 until rows.size). When an item is selected, it should invoke
                     //  onRowsPerPageChange with the appropriate value.
-                    Text(text = "Rows per page: ${pagination.rowsPerPage}")
+                    Text(text = "Rows per page: ${pagination.rowsPerPage}", modifier = modifier)
 
                     WidthSpacer(width = 32.dp)
 
-                    Text(text = "${startRow + 1}-$endRow of ${rows.size}")
+                    Text(text = "${startRow + 1}-$endRow of ${rows.size}", modifier = modifier)
 
                     WidthSpacer(width = 32.dp)
 
                     // TODO(calintat): Replace this with an image button with chevron_left icon.
-                    Ripple(bounded = false) {
-                        Clickable(>
-                            val newPage = pagination.page - 1
-                            if (newPage >= 0)
-                                pagination.onPageChange.invoke(newPage)
-                        }) {
-                            Text(text = "Prev")
+                    Container(modifier = modifier) {
+                        Ripple(bounded = false) {
+                            Clickable(>
+                                val newPage = pagination.page - 1
+                                if (newPage >= 0)
+                                    pagination.onPageChange.invoke(newPage)
+                            }) {
+                                Text(text = "Prev")
+                            }
                         }
                     }
 
                     WidthSpacer(width = 24.dp)
 
                     // TODO(calintat): Replace this with an image button with chevron_right icon.
-                    Ripple(bounded = false) {
-                        Clickable(>
-                            val newPage = pagination.page + 1
-                            if (newPage < pages)
-                                pagination.onPageChange.invoke(newPage)
-                        }) {
-                            Text(text = "Next")
+                    Container(modifier = modifier) {
+                        Ripple(bounded = false) {
+                            Clickable(>
+                                val newPage = pagination.page + 1
+                                if (newPage < pages)
+                                    pagination.onPageChange.invoke(newPage)
+                            }) {
+                                Text(text = "Next")
+                            }
                         }
                     }
                 }
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt b/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
index 8a84047..b049f8d 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/ListItem.kt
@@ -260,7 +260,7 @@
     ) {
         val minHeight = if (icon == null) MinHeight else MinHeightWithIcon
         ConstrainedBox(constraints = DpConstraints(minHeight = minHeight)) {
-            FlexRow(crossAxisAlignment = CrossAxisAlignment.Start) {
+            FlexRow {
                 inflexible {
                     if (icon != null) {
                         Container(
@@ -357,7 +357,7 @@
         trailing: @Composable() (() -> Unit)?
     ) {
         ConstrainedBox(constraints = DpConstraints(minHeight = MinHeight)) {
-            FlexRow(crossAxisAlignment = CrossAxisAlignment.Start) {
+            FlexRow {
                 inflexible {
                     if (icon != null) {
                         Container(
diff --git a/ui/ui-platform/api/0.1.0-dev03.txt b/ui/ui-platform/api/0.1.0-dev03.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/0.1.0-dev03.txt
+++ b/ui/ui-platform/api/0.1.0-dev03.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/current.txt b/ui/ui-platform/api/current.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/current.txt
+++ b/ui/ui-platform/api/current.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-platform/api/public_plus_experimental_0.1.0-dev03.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/public_plus_experimental_current.txt b/ui/ui-platform/api/public_plus_experimental_current.txt
index 994ceff..7cdc759 100644
--- a/ui/ui-platform/api/public_plus_experimental_current.txt
+++ b/ui/ui-platform/api/public_plus_experimental_current.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
diff --git a/ui/ui-platform/api/restricted_0.1.0-dev03.txt b/ui/ui-platform/api/restricted_0.1.0-dev03.txt
index 6e0e953..7cdc759 100644
--- a/ui/ui-platform/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-platform/api/restricted_0.1.0-dev03.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
@@ -439,15 +443,6 @@
 
 }
 
-package androidx.ui.core.text {
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class AndroidFontResourceLoader implements androidx.ui.text.font.Font.ResourceLoader {
-    ctor public AndroidFontResourceLoader(android.content.Context context);
-    method public android.graphics.Typeface load(androidx.ui.text.font.Font font);
-  }
-
-}
-
 package androidx.ui.input {
 
   public final class InputStateKt {
diff --git a/ui/ui-platform/api/restricted_current.txt b/ui/ui-platform/api/restricted_current.txt
index 6e0e953..7cdc759 100644
--- a/ui/ui-platform/api/restricted_current.txt
+++ b/ui/ui-platform/api/restricted_current.txt
@@ -23,9 +23,11 @@
     method public kotlin.jvm.functions.Function0<kotlin.Unit> getConfigurationChangeObserver();
     method public androidx.ui.core.Constraints getConstraints();
     method public androidx.ui.core.Density getDensity();
+    method public androidx.ui.text.font.Font.ResourceLoader getFontLoader();
     method public long getMeasureIteration();
     method public androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? getRef();
     method public androidx.ui.core.LayoutNode getRoot();
+    method public androidx.ui.input.TextInputService getTextInputService();
     method public void onAttach(androidx.ui.core.ComponentNode node);
     method public void onDetach(androidx.ui.core.ComponentNode node);
     method public void onEndLayout(androidx.ui.core.LayoutNode layoutNode);
@@ -46,9 +48,11 @@
     property public final kotlin.jvm.functions.Function0<kotlin.Unit> configurationChangeObserver;
     property public final androidx.ui.core.Constraints constraints;
     property public androidx.ui.core.Density density;
+    property public final androidx.ui.text.font.Font.ResourceLoader fontLoader;
     property public long measureIteration;
     property public final androidx.ui.core.Ref<androidx.ui.core.AndroidComposeView>? ref;
     property public final androidx.ui.core.LayoutNode root;
+    property public final androidx.ui.input.TextInputService textInputService;
   }
 
   public final class AndroidOwnerKt {
@@ -439,15 +443,6 @@
 
 }
 
-package androidx.ui.core.text {
-
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class AndroidFontResourceLoader implements androidx.ui.text.font.Font.ResourceLoader {
-    ctor public AndroidFontResourceLoader(android.content.Context context);
-    method public android.graphics.Typeface load(androidx.ui.text.font.Font font);
-  }
-
-}
-
 package androidx.ui.input {
 
   public final class InputStateKt {
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
index 4d41ff0..5f4ea2b 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/AndroidOwner.kt
@@ -31,19 +31,6 @@
 import android.view.inputmethod.EditorInfo
 import android.view.inputmethod.InputConnection
 import androidx.annotation.RequiresApi
-import androidx.annotation.RestrictTo
-import androidx.ui.input.TextInputServiceAndroid
-import androidx.ui.core.pointerinput.PointerInputEventProcessor
-import androidx.ui.core.pointerinput.toPointerInputEvent
-import androidx.ui.engine.geometry.Outline
-import androidx.ui.input.TextInputService
-import androidx.ui.graphics.Canvas
-import androidx.ui.graphics.Path
-import androidx.ui.engine.geometry.Rect
-import androidx.ui.engine.geometry.RRect
-import androidx.ui.engine.geometry.Shape
-import kotlin.math.roundToInt
-import java.util.TreeSet
 import androidx.compose.trace
 import androidx.ui.autofill.AndroidAutofill
 import androidx.ui.autofill.Autofill
@@ -53,6 +40,20 @@
 import androidx.ui.autofill.registerCallback
 import androidx.ui.autofill.unregisterCallback
 import androidx.ui.core.NodeStagesModelObserver.Stage
+import androidx.ui.core.pointerinput.PointerInputEventProcessor
+import androidx.ui.core.pointerinput.toPointerInputEvent
+import androidx.ui.core.text.AndroidFontResourceLoader
+import androidx.ui.engine.geometry.Outline
+import androidx.ui.engine.geometry.RRect
+import androidx.ui.engine.geometry.Rect
+import androidx.ui.engine.geometry.Shape
+import androidx.ui.graphics.Canvas
+import androidx.ui.graphics.Path
+import androidx.ui.input.TextInputServiceAndroid
+import androidx.ui.input.TextInputService
+import androidx.ui.text.font.Font
+import java.util.TreeSet
+import kotlin.math.roundToInt
 
 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
 class AndroidComposeView constructor(context: Context) :
@@ -580,10 +581,10 @@
 
     private val textInputServiceAndroid = TextInputServiceAndroid(this)
 
-    /** @hide */
-    @RestrictTo(RestrictTo.Scope.LIBRARY)
     val textInputService = TextInputService(textInputServiceAndroid)
 
+    val fontLoader: Font.ResourceLoader = AndroidFontResourceLoader(context)
+
     override fun onCheckIsTextEditor(): Boolean = textInputServiceAndroid.isEditorFocused()
 
     override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? =
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt b/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
index c5126a7..c26427e 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/text/AndroidFontResourceLoader.kt
@@ -18,17 +18,13 @@
 
 import android.content.Context
 import android.graphics.Typeface
-import androidx.annotation.RestrictTo
 import androidx.core.content.res.ResourcesCompat
 import androidx.ui.text.font.Font
 
 /**
  * Android implementation for [Font.ResourceLoader]
- *
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-class AndroidFontResourceLoader(private val context: Context) : Font.ResourceLoader {
+internal class AndroidFontResourceLoader(private val context: Context) : Font.ResourceLoader {
     override fun load(font: Font): Typeface {
         val resId = context.resources.getIdentifier(
             font.name.substringBefore("."),
diff --git a/ui/ui-text/api/0.1.0-dev03.txt b/ui/ui-text/api/0.1.0-dev03.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/0.1.0-dev03.txt
+++ b/ui/ui-text/api/0.1.0-dev03.txt
@@ -1,6 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
+
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
     enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
+
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
+
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
     enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
   public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
+
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
+
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -52,10 +184,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -322,8 +450,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
+  public final class TextSpan {
+    ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+    ctor public TextSpan();
+    method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+    method public androidx.ui.text.TextStyle? getStyle();
+    method public String? getText();
+  }
+
   public final class TextSpanKt {
     ctor public TextSpanKt();
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -365,7 +502,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -472,7 +609,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/api/api_lint.ignore b/ui/ui-text/api/api_lint.ignore
index 8d871e2..9671a85 100644
--- a/ui/ui-text/api/api_lint.ignore
+++ b/ui/ui-text/api/api_lint.ignore
@@ -45,6 +45,8 @@
     Missing `build()` method in androidx.ui.text.AnnotatedString.Builder
 
 
+MissingNullability: androidx.ui.input.OffsetMap#Companion:
+    Missing nullability on field `Companion` in class `class androidx.ui.input.OffsetMap`
 MissingNullability: androidx.ui.text.Locale#Companion:
     Missing nullability on field `Companion` in class `class androidx.ui.text.Locale`
 MissingNullability: androidx.ui.text.LocaleList#Companion:
diff --git a/ui/ui-text/api/current.txt b/ui/ui-text/api/current.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/current.txt
+++ b/ui/ui-text/api/current.txt
@@ -1,6 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
+
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
     enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
+
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
+
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
     enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
   public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
+
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
+
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -52,10 +184,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -322,8 +450,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
+  public final class TextSpan {
+    ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+    ctor public TextSpan();
+    method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+    method public androidx.ui.text.TextStyle? getStyle();
+    method public String? getText();
+  }
+
   public final class TextSpanKt {
     ctor public TextSpanKt();
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -365,7 +502,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -472,7 +609,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt b/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
+++ b/ui/ui-text/api/public_plus_experimental_0.1.0-dev03.txt
@@ -1,6 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
+
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
     enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
+
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
+
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
     enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
   public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
+
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
+
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -52,10 +184,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -322,8 +450,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
+  public final class TextSpan {
+    ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+    ctor public TextSpan();
+    method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+    method public androidx.ui.text.TextStyle? getStyle();
+    method public String? getText();
+  }
+
   public final class TextSpanKt {
     ctor public TextSpanKt();
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -365,7 +502,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -472,7 +609,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/api/public_plus_experimental_current.txt b/ui/ui-text/api/public_plus_experimental_current.txt
index 68935db..eaa847e 100644
--- a/ui/ui-text/api/public_plus_experimental_current.txt
+++ b/ui/ui-text/api/public_plus_experimental_current.txt
@@ -1,6 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
+
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
     enum_constant public static final androidx.ui.input.ImeAction Go;
@@ -12,6 +61,26 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
+
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
+
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
     enum_constant public static final androidx.ui.input.KeyboardType Email;
@@ -23,9 +92,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
   public final class PasswordVisualTransformation implements androidx.ui.input.VisualTransformation {
@@ -35,8 +118,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
+
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
+
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -52,10 +184,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -322,8 +450,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
+  public final class TextSpan {
+    ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
+    ctor public TextSpan();
+    method public java.util.List<androidx.ui.text.TextSpan> getChildren();
+    method public androidx.ui.text.TextStyle? getStyle();
+    method public String? getText();
+  }
+
   public final class TextSpanKt {
     ctor public TextSpanKt();
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -365,7 +502,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -472,7 +609,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/api/restricted_0.1.0-dev03.txt b/ui/ui-text/api/restricted_0.1.0-dev03.txt
index 311a121..5157e30 100644
--- a/ui/ui-text/api/restricted_0.1.0-dev03.txt
+++ b/ui/ui-text/api/restricted_0.1.0-dev03.txt
@@ -1,13 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
 
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
 
-
-
-
-
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
@@ -20,7 +62,25 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
 
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
 
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
@@ -33,10 +93,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
 
@@ -47,13 +120,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
 
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
 
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -69,10 +186,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -340,18 +453,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class TextSpan {
+  public final class TextSpan {
     ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
     ctor public TextSpan();
     method public java.util.List<androidx.ui.text.TextSpan> getChildren();
     method public androidx.ui.text.TextStyle? getStyle();
     method public String? getText();
-    method public boolean visitTextSpan(kotlin.jvm.functions.Function1<? super androidx.ui.text.TextSpan,java.lang.Boolean> visitor);
   }
 
   public final class TextSpanKt {
     ctor public TextSpanKt();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -393,7 +505,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -500,7 +612,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/api/restricted_current.txt b/ui/ui-text/api/restricted_current.txt
index 311a121..5157e30 100644
--- a/ui/ui-text/api/restricted_current.txt
+++ b/ui/ui-text/api/restricted_current.txt
@@ -1,13 +1,55 @@
 // Signature format: 3.0
 package androidx.ui.input {
 
+  public final class BackspaceKeyEditOp implements androidx.ui.input.EditOperation {
+    ctor public BackspaceKeyEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class CommitTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public CommitTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.CommitTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public final class DeleteSurroundingTextInCodePointsEditOp implements androidx.ui.input.EditOperation {
+    ctor public DeleteSurroundingTextInCodePointsEditOp(int beforeLength, int afterLength);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.DeleteSurroundingTextInCodePointsEditOp copy(int beforeLength, int afterLength);
+    method public int getAfterLength();
+    method public int getBeforeLength();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
+
+  public interface EditOperation {
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
 
+  public final class EditingBuffer {
+    ctor public EditingBuffer(String initialText, androidx.ui.text.TextRange initialSelection);
+    field public static final int NOWHERE = -1; // 0xffffffff
+  }
 
-
-
-
-
+  public final class FinishComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public FinishComposingTextEditOp();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
   public enum ImeAction {
     enum_constant public static final androidx.ui.input.ImeAction Done;
@@ -20,7 +62,25 @@
     enum_constant public static final androidx.ui.input.ImeAction Unspecified;
   }
 
+  public interface InputEventListener {
+    method public void onEditOperations(java.util.List<? extends androidx.ui.input.EditOperation> editOps);
+    method public void onImeAction(androidx.ui.input.ImeAction imeAction);
+  }
 
+  public final class InputState {
+    ctor public InputState(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    ctor public InputState();
+    method public String component1();
+    method public androidx.ui.text.TextRange component2();
+    method public androidx.ui.text.TextRange? component3();
+    method public androidx.ui.input.InputState copy(String text, androidx.ui.text.TextRange selection, androidx.ui.text.TextRange? composition);
+    method public androidx.ui.text.TextRange? getComposition();
+    method public String getSelectedText();
+    method public androidx.ui.text.TextRange getSelection();
+    method public String getText();
+    method public String getTextAfterSelection(int maxChars);
+    method public String getTextBeforeSelection(int maxChars);
+  }
 
   public enum KeyboardType {
     enum_constant public static final androidx.ui.input.KeyboardType Ascii;
@@ -33,10 +93,23 @@
     enum_constant public static final androidx.ui.input.KeyboardType Uri;
   }
 
+  public final class MoveCursorEditOp implements androidx.ui.input.EditOperation {
+    ctor public MoveCursorEditOp(int amount);
+    method public int component1();
+    method public androidx.ui.input.MoveCursorEditOp copy(int amount);
+    method public int getAmount();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
   public interface OffsetMap {
     method public int originalToTransformed(int offset);
     method public int transformedToOriginal(int offset);
+    field public static final androidx.ui.input.OffsetMap.Companion! Companion;
+  }
+
+  public static final class OffsetMap.Companion {
+    method public androidx.ui.input.OffsetMap getIdentityOffsetMap();
+    property public final androidx.ui.input.OffsetMap identityOffsetMap;
   }
 
 
@@ -47,13 +120,57 @@
     method public char getMask();
   }
 
+  public interface PlatformTextInputService {
+    method public void notifyFocusedRect(androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard();
+    method public void startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput();
+  }
 
+  public final class SetComposingRegionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingRegionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingRegionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public final class SetComposingTextEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetComposingTextEditOp(String text, int newCursorPosition);
+    method public String component1();
+    method public int component2();
+    method public androidx.ui.input.SetComposingTextEditOp copy(String text, int newCursorPosition);
+    method public int getNewCursorPosition();
+    method public String getText();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public final class SetSelectionEditOp implements androidx.ui.input.EditOperation {
+    ctor public SetSelectionEditOp(int start, int end);
+    method public int component1();
+    method public int component2();
+    method public androidx.ui.input.SetSelectionEditOp copy(int start, int end);
+    method public int getEnd();
+    method public int getStart();
+    method public void process(androidx.ui.input.EditingBuffer buffer);
+  }
 
+  public class TextInputService {
+    ctor public TextInputService(androidx.ui.input.PlatformTextInputService platformTextInputService);
+    method public void notifyFocusedRect(int token, androidx.ui.engine.geometry.Rect rect);
+    method public void onStateUpdated(int token, androidx.ui.input.InputState model);
+    method public void showSoftwareKeyboard(int token);
+    method public int startInput(androidx.ui.input.InputState initModel, androidx.ui.input.KeyboardType keyboardType, androidx.ui.input.ImeAction imeAction, kotlin.jvm.functions.Function1<? super java.util.List<? extends androidx.ui.input.EditOperation>,kotlin.Unit> onEditCommand, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed);
+    method public void stopInput(int token);
+  }
 
   public final class TextInputServiceKt {
     ctor public TextInputServiceKt();
+    field public static final int INVALID_SESSION = -1; // 0xffffffff
+    field public static final int NO_SESSION = 0; // 0x0
   }
 
   public final class TransformedText {
@@ -69,10 +186,6 @@
     method public androidx.ui.input.TransformedText filter(androidx.ui.text.AnnotatedString text);
   }
 
-  public final class VisualTransformationKt {
-    ctor public VisualTransformationKt();
-  }
-
 }
 
 package androidx.ui.text {
@@ -340,18 +453,17 @@
     method public static String substring(CharSequence, androidx.ui.text.TextRange range);
   }
 
-  @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public final class TextSpan {
+  public final class TextSpan {
     ctor public TextSpan(androidx.ui.text.TextStyle? style, String? text, java.util.List<androidx.ui.text.TextSpan> children);
     ctor public TextSpan();
     method public java.util.List<androidx.ui.text.TextSpan> getChildren();
     method public androidx.ui.text.TextStyle? getStyle();
     method public String? getText();
-    method public boolean visitTextSpan(kotlin.jvm.functions.Function1<? super androidx.ui.text.TextSpan,java.lang.Boolean> visitor);
   }
 
   public final class TextSpanKt {
     ctor public TextSpanKt();
-    method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP) public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
+    method public static androidx.ui.text.AnnotatedString toAnnotatedString(androidx.ui.text.TextSpan);
   }
 
   public final class TextStyle {
@@ -393,7 +505,7 @@
 
   public final class TextStyleKt {
     ctor public TextStyleKt();
-    method public static androidx.ui.text.TextStyle? lerp(androidx.ui.text.TextStyle? start = null, androidx.ui.text.TextStyle? stop = null, float fraction);
+    method public static androidx.ui.text.TextStyle lerp(androidx.ui.text.TextStyle start, androidx.ui.text.TextStyle stop, float fraction);
   }
 
 }
@@ -500,7 +612,7 @@
 
   public final class FontWeightKt {
     ctor public FontWeightKt();
-    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight? start, androidx.ui.text.font.FontWeight? stop, float fraction);
+    method public static androidx.ui.text.font.FontWeight lerp(androidx.ui.text.font.FontWeight start, androidx.ui.text.font.FontWeight stop, float fraction);
   }
 
 }
diff --git a/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt b/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
index 52c5388..e25e640 100644
--- a/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
+++ b/ui/ui-text/integration-tests/samples/src/main/java/androidx/ui/text/samples/VisualTransformationSamples.kt
@@ -19,7 +19,6 @@
 import androidx.annotation.Sampled
 import androidx.ui.input.OffsetMap
 import androidx.ui.input.TransformedText
-import androidx.ui.input.identityOffsetMap
 import androidx.ui.text.AnnotatedString
 
 @Sampled
@@ -28,10 +27,10 @@
         AnnotatedString("*".repeat(text.text.length)),
 
         /**
-         * identityOffsetMap is a predefined [OffsetMap] that can be used for the transformation
-         * that does not change the character count.
+         * [OffsetMap.identityOffsetMap] is a predefined [OffsetMap] that can be used for the
+         * transformation that does not change the character count.
          */
-        identityOffsetMap
+        OffsetMap.identityOffsetMap
     )
 }
 
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
index c55e8dc..7d0f2b1 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputField.kt
@@ -23,7 +23,6 @@
 import androidx.ui.input.ImeAction
 import androidx.ui.input.KeyboardType
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.text.TextStyle
@@ -52,10 +51,7 @@
 @Composable
 fun InputFieldDemo() {
     VerticalScroller {
-        Column(
-            ExpandedHeight,
-            crossAxisAlignment = CrossAxisAlignment.Start
-        ) {
+        Column(ExpandedHeight) {
             TagLine(tag = "simple editing")
             EditLine()
             TagLine(tag = "simple editing2")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
index 8e3ef59..0cf4ff6 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldFocusTransition.kt
@@ -24,7 +24,6 @@
 import androidx.ui.core.TextField
 import androidx.ui.core.sp
 import androidx.ui.foundation.VerticalScroller
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.graphics.Color
 import androidx.ui.input.ImeAction
 import androidx.ui.layout.Column
@@ -33,7 +32,7 @@
 @Composable
 fun TextFieldFocusTransition() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TextFieldWithFocusId("Focus 1", "Focus 2")
             TextFieldWithFocusId("Focus 2", "Focus 3")
             TextFieldWithFocusId("Focus 3", "Focus 4")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
index f33a865..eef0d12 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeInputFieldTrickyUseCase.kt
@@ -22,7 +22,6 @@
 import androidx.ui.core.TextField
 import androidx.ui.core.sp
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.input.KeyboardType
 import androidx.ui.text.TextStyle
@@ -30,7 +29,7 @@
 @Composable
 fun InputFieldTrickyUseCase() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TagLine(tag = "don't set if non number is added")
             RejectNonDigits()
 
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
index 124c2ef..41d4b7f 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeMultiParagraph.kt
@@ -21,7 +21,6 @@
 import androidx.ui.core.sp
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.text.AnnotatedString
 import androidx.ui.text.ParagraphStyle
 import androidx.ui.text.TextStyle
@@ -35,7 +34,7 @@
 @Composable
 fun MultiParagraphDemo() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TagLine(tag = "multiple paragraphs basic")
             TextDemoParagraph()
             TagLine(tag = "multiple paragraphs TextAlign")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
index b9ebe14..4ef4b51 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeText.kt
@@ -28,7 +28,6 @@
 import androidx.ui.graphics.Color
 import androidx.ui.graphics.lerp
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.Row
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.text.ParagraphStyle
@@ -65,7 +64,7 @@
 @Composable
 fun TextDemo() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TagLine(tag = "color, fontSize, fontWeight and fontStyle")
             TextDemoBasic()
             TagLine(tag = "color, fontSize, fontWeight, fontFamily, fontStyle, letterSpacing, " +
@@ -369,10 +368,7 @@
     for (i in 1..10) {
         text = "$text$displayText "
     }
-    Column(
-        ExpandedHeight,
-        crossAxisAlignment = CrossAxisAlignment.Start
-    ) {
+    Column(ExpandedHeight) {
         SecondTagLine(tag = "textAlign = TextAlign.Left")
         Text(paragraphStyle = ParagraphStyle(textAlign = TextAlign.Left)) {
             Span(text = displayText, style = TextStyle(fontSize = fontSize8))
@@ -441,10 +437,7 @@
     val textStyle =
         TextStyle(fontSize = fontSize8, color = Color(0xFFFF0000))
 
-    Column(
-        ExpandedHeight,
-        crossAxisAlignment = CrossAxisAlignment.Start
-    ) {
+    Column(ExpandedHeight) {
         Text {
             Span(text = text, style = textStyle)
         }
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
index 4c815f4..8104626 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelection.kt
@@ -27,7 +27,6 @@
 import androidx.ui.foundation.text.SelectionContainer
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.ExpandedHeight
 import androidx.ui.layout.ExpandedWidth
 import androidx.ui.layout.Row
@@ -39,7 +38,7 @@
 @Composable
 fun TextSelectionDemo() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TagLine(tag = "selection")
             TextDemoSelection()
             TagLine(tag = "selection with string input")
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
index 42c5fe7..9400fb1 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeTextSelectionSample.kt
@@ -33,7 +33,6 @@
 import androidx.ui.foundation.text.SelectionContainer
 import androidx.ui.graphics.Color
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.layout.FlexRow
 import androidx.ui.layout.Padding
 import androidx.ui.text.AnnotatedString
@@ -90,7 +89,7 @@
              selection.value = it }
         ) {
             Padding(12.dp) {
-                Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+                Column {
                     Basics()
                     AddTextElement()
                     langContent.forEach {
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
index 763c5f4..8f7e43a 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/ComposeVariousInputField.kt
@@ -31,7 +31,6 @@
 import androidx.ui.input.ImeAction
 import androidx.ui.input.KeyboardType
 import androidx.ui.layout.Column
-import androidx.ui.layout.CrossAxisAlignment
 import androidx.ui.foundation.VerticalScroller
 import androidx.ui.text.AnnotatedString
 import androidx.ui.text.LocaleList
@@ -173,7 +172,7 @@
 @Composable
 fun VariousInputFieldDemo() {
     VerticalScroller {
-        Column(crossAxisAlignment = CrossAxisAlignment.Start) {
+        Column {
             TagLine(tag = "Capitalization")
             VariousEditLine(
                 keyboardType = KeyboardType.Ascii,
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt b/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
index bf88c34..2e66b46 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/EditOperation.kt
@@ -16,20 +16,17 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
 import java.text.BreakIterator
 import java.util.Objects
+import kotlin.math.max
+import kotlin.math.min
 
 /**
  * A base class of all EditOperations
  *
  * An EditOperation is a representation of platform IME API call. For example, in Android,
  * InputConnection#commitText API call is translated to CommitTextEditOp object.
- *
- * @hide
  */
-@RestrictTo(LIBRARY)
 interface EditOperation {
 
     /**
@@ -41,11 +38,8 @@
 /**
  * An edit operation represent commitText callback from InputMethod.
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#commitText(java.lang.CharSequence,%20int)>
  */
-@RestrictTo(LIBRARY)
 data class CommitTextEditOp(
     /**
      * The text to commit. We ignore any styles in the original API.
@@ -87,11 +81,8 @@
 /**
  * An edit operation represents setComposingRegion callback from InputMethod.
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%2520int)
-
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingRegion(int,%2520int)>
  */
-@RestrictTo(LIBRARY)
 data class SetComposingRegionEditOp(
     /**
      * The inclusive start offset of the composing region.
@@ -126,11 +117,8 @@
 /**
  * An edit operation represents setComposingText callback from InputMethod
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setComposingText(java.lang.CharSequence,%2520int)>
  */
-@RestrictTo(LIBRARY)
 data class SetComposingTextEditOp(
     /**
      * The composing text.
@@ -178,11 +166,8 @@
 /**
  * An edit operation represents deleteSurroundingText callback from InputMethod
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingText(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingText(int,%2520int)>
  */
-@RestrictTo(LIBRARY)
 data class DeleteSurroundingTextEditOp(
     /**
      * The number of characters in UTF-16 before the cursor to be deleted.
@@ -196,11 +181,11 @@
     override fun process(buffer: EditingBuffer) {
         buffer.delete(
             buffer.selectionEnd,
-            Math.min(buffer.selectionEnd + afterLength, buffer.length)
+            min(buffer.selectionEnd + afterLength, buffer.length)
         )
 
         buffer.delete(
-            Math.max(0, buffer.selectionStart - beforeLength),
+            max(0, buffer.selectionStart - beforeLength),
             buffer.selectionStart
         )
     }
@@ -208,11 +193,8 @@
 /**
  * An edit operation represents deleteSurroundingTextInCodePoitns callback from InputMethod
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingTextInCodePoints(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#deleteSurroundingTextInCodePoints(int,%2520int)>
  */
-@RestrictTo(LIBRARY)
 data class DeleteSurroundingTextInCodePointsEditOp(
     /**
      * The number of characters in Unicode code points before the cursor to be deleted.
@@ -261,11 +243,8 @@
 /**
  * An edit operation represents setSelection callback from InputMethod
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setSelection(int,%2520int)
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#setSelection(int,%2520int)>
  */
-@RestrictTo(LIBRARY)
 data class SetSelectionEditOp(
     /**
      * The inclusive start offset of the selection region.
@@ -291,11 +270,8 @@
 /**
  * An edit operation represents finishComposingText callback from InputMEthod
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#finishComposingText()
- *
- * @hide
+ * @see <https://developer.android.com/reference/android/view/inputmethod/InputConnection.html#finishComposingText()>
  */
-@RestrictTo(LIBRARY)
 class FinishComposingTextEditOp : EditOperation {
 
     override fun process(buffer: EditingBuffer) {
@@ -314,10 +290,7 @@
  * If there is composition, delete the text in the composition range.
  * If there is no composition but there is selection, delete whole selected range.
  * If there is no composition and selection, perform backspace key event at the cursor position.
- *
- * @hide
  */
-@RestrictTo(LIBRARY)
 class BackspaceKeyEditOp : EditOperation {
 
     override fun process(buffer: EditingBuffer) {
@@ -355,10 +328,7 @@
  *
  * If there is selection, cancel the selection first and move the cursor to the selection start
  * position. Then perform the cursor movement.
- *
- * @hide
  */
-@RestrictTo(LIBRARY)
 data class MoveCursorEditOp(
     /**
      * The amount of cursor movement.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt b/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
index 0a290b1..833ff11 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/EditingBuffer.kt
@@ -16,8 +16,6 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
 import androidx.ui.text.TextRange
 import java.lang.IllegalArgumentException
 
@@ -25,10 +23,7 @@
  * The editing buffer
  *
  * This class manages the all editing relate states, editing buffers, selection, styles, etc.
- *
- * @hide
  */
-@RestrictTo(LIBRARY)
 class EditingBuffer(
     /**
      * The initial text of this editing buffer
@@ -53,13 +48,13 @@
     /**
      * The inclusive selection start offset
      */
-    var selectionStart = initialSelection.min
+    internal var selectionStart = initialSelection.min
         private set
 
     /**
      * The exclusive selection end offset
      */
-    var selectionEnd = initialSelection.max
+    internal var selectionEnd = initialSelection.max
         private set
 
     /**
@@ -67,7 +62,7 @@
      *
      * If there is no composing text, returns -1
      */
-    var compositionStart = NOWHERE
+    internal var compositionStart = NOWHERE
         private set
 
     /**
@@ -75,18 +70,18 @@
      *
      * If there is no composing text, returns -1
      */
-    var compositionEnd = NOWHERE
+    internal var compositionEnd = NOWHERE
         private set
 
     /**
      * Helper function that returns true if the editing buffer has composition text
      */
-    fun hasComposition(): Boolean = compositionStart != NOWHERE
+    internal fun hasComposition(): Boolean = compositionStart != NOWHERE
 
     /**
      * Helper accessor for cursor offset
      */
-    var cursor: Int
+    internal var cursor: Int
         /**
          * Return the cursor offset.
          *
@@ -104,12 +99,12 @@
     /**
      * [] operator for the character at the index.
      */
-    operator fun get(index: Int): Char = gapBuffer[index]
+    internal operator fun get(index: Int): Char = gapBuffer[index]
 
     /**
      * Returns the length of the buffer.
      */
-    val length: Int get() = gapBuffer.length
+    internal val length: Int get() = gapBuffer.length
 
     init {
         val start = initialSelection.min
@@ -137,7 +132,7 @@
      * @throws IndexOutOfBoundsException if start or end offset is outside of current buffer
      * @throws IllegalArgumentException if start is larger than end. (reversed range)
      */
-    fun replace(start: Int, end: Int, text: String) {
+    internal fun replace(start: Int, end: Int, text: String) {
 
         if (start < 0 || start > gapBuffer.length) {
             throw IndexOutOfBoundsException(
@@ -176,7 +171,7 @@
      * Different from replace method, this doesn't move cursor location to the end of modified text.
      * Instead, preserve the selection with adjusting the deleted text.
      */
-    fun delete(start: Int, end: Int) {
+    internal fun delete(start: Int, end: Int) {
         val deleteRange = TextRange(start, end)
         if (deleteRange.intersects(TextRange(selectionStart, selectionEnd))) {
             // Currently only target for deleteSurroundingText/deleteSurroundingTextInCodePoints.
@@ -279,7 +274,7 @@
      * @throws IndexOutOfBoundsException if start or end offset is outside of current buffer.
      * @throws IllegalArgumentException if start is larger than end. (reversed range)
      */
-    fun setSelection(start: Int, end: Int) {
+    internal fun setSelection(start: Int, end: Int) {
         if (start < 0 || start > gapBuffer.length) {
             throw IndexOutOfBoundsException(
                 "start ($start) offset is outside of text region ${gapBuffer.length}")
@@ -309,7 +304,7 @@
      * @throws IllegalArgumentException if start is larger than or equal to end. (reversed or
      *                                  collapsed range)
      */
-    fun setComposition(start: Int, end: Int) {
+    internal fun setComposition(start: Int, end: Int) {
         if (start < 0 || start > gapBuffer.length) {
             throw IndexOutOfBoundsException(
                 "start ($start) offset is outside of text region ${gapBuffer.length}")
@@ -329,7 +324,7 @@
     /**
      * Removes the ongoing composition text and reset the composition range.
      */
-    fun cancelComposition() {
+    internal fun cancelComposition() {
         replace(compositionStart, compositionEnd, "")
         compositionStart = NOWHERE
         compositionEnd = NOWHERE
@@ -338,7 +333,7 @@
     /**
      * Commits the ongoing composition text and reset the composition range.
      */
-    fun commitComposition() {
+    internal fun commitComposition() {
         compositionStart = NOWHERE
         compositionEnd = NOWHERE
     }
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt b/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
index e18c421..73b815d 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/GapBuffer.kt
@@ -18,6 +18,8 @@
 
 import android.util.Log
 import androidx.annotation.RestrictTo
+import kotlin.math.max
+import kotlin.math.min
 
 /**
  * The gap buffer implementation
@@ -235,26 +237,30 @@
      * @param end an exclusive end offset for replacement
      * @param text a text to replace
      */
-    fun replace(start: Int, end: Int, buf: String) {
+    fun replace(start: Int, end: Int, text: String) {
         val buffer = buffer
         if (buffer == null) { // First time to create gap buffer
-            val charArray = CharArray(Math.max(BUF_SIZE, buf.length + 2 * SURROUNDING_SIZE))
+            val charArray = CharArray(max(BUF_SIZE, text.length + 2 * SURROUNDING_SIZE))
 
             // Convert surrounding text into buffer.
-            val leftCopyCount = Math.min(start, SURROUNDING_SIZE)
-            val rightCopyCount = Math.min(text.length - end, SURROUNDING_SIZE)
+            val leftCopyCount = min(start, SURROUNDING_SIZE)
+            val rightCopyCount = min(this.text.length - end, SURROUNDING_SIZE)
 
             // Copy left surrounding
-            text.toCharArray(charArray, 0, start - leftCopyCount, start)
+            this.text.toCharArray(charArray, 0, start - leftCopyCount, start)
 
             // Copy right surrounding
-            text.toCharArray(charArray, charArray.size - rightCopyCount, end, end + rightCopyCount)
+            this.text.toCharArray(charArray,
+                charArray.size - rightCopyCount,
+                end,
+                end + rightCopyCount
+            )
 
             // Copy given text into buffer
-            buf.toCharArray(charArray, leftCopyCount)
+            text.toCharArray(charArray, leftCopyCount)
 
             this.buffer = GapBuffer(charArray,
-                leftCopyCount + buf.length, // gap start
+                leftCopyCount + text.length, // gap start
                 charArray.size - rightCopyCount) // gap end
             bufStart = start - leftCopyCount
             bufEnd = end + rightCopyCount
@@ -267,14 +273,14 @@
         if (bufferStart < 0 || bufferEnd > buffer.length()) {
             // Text modification outside of gap buffer has requested. Flush the buffer and try it
             // again.
-            text = toString()
+            this.text = toString()
             this.buffer = null
             bufStart = NOWHERE
             bufEnd = NOWHERE
-            return replace(start, end, buf)
+            return replace(start, end, text)
         }
 
-        buffer.replace(bufferStart, bufferEnd, buf)
+        buffer.replace(bufferStart, bufferEnd, text)
     }
 
     /**
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt b/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
index 67f2ee9..1f19c4e 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/ImeAction.kt
@@ -19,48 +19,48 @@
 /**
  * Enums used for indicating IME action.
  *
- * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_MASK_ACTION
+ * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_MASK_ACTION>
  */
 enum class ImeAction {
     /**
      * An IME action used to represent that any IME action is associated.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_UNSPECIFIED
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_UNSPECIFIED>
      */
     Unspecified,
 
     /**
      * An IME action used to represent that no IME action is available in editor.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_NONE
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_NONE>
      */
     NoAction,
 
     /**
      * An IME action used to represent that the "enter" key works as "go" action.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_GO
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_GO>
      */
     Go,
 
     /**
      * An IME action used to represent that the "enter" key works as "search" action.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEARCH
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEARCH>
      */
     Search,
 
     /**
      * An IME action used to represent that the "enter" key works as "send" action.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEND
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_SEND>
      */
     Send,
 
     /**
      * An IME action used to represent that the "enter" key works as "previous" action.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_PREVIOUS
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_PREVIOUS>
      */
     Previous,
 
@@ -74,7 +74,7 @@
     /**
      * An IME action used to represent that the "enter" key works as "done" action.
      *
-     * @see https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_DONE
+     * @see <https://developer.android.com/reference/android/view/inputmethod/EditorInfo.html#IME_ACTION_DONE>
      */
     Done
 }
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt b/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
index 1c8d5db..b43beb1 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/InputEventListener.kt
@@ -16,14 +16,9 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
-import androidx.annotation.RestrictTo.Scope.LIBRARY
 /**
  * An interface of listening IME events.
- *
- * @hide
  */
-@RestrictTo(LIBRARY)
 interface InputEventListener {
     /**
      * Called when IME sends some input events.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt b/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
index 1581d26..ab3327c 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/InputState.kt
@@ -16,9 +16,10 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
 import androidx.ui.text.TextRange
 import androidx.ui.text.substring
+import kotlin.math.max
+import kotlin.math.min
 
 /**
  * Stores an input state for IME
@@ -26,9 +27,7 @@
  * IME can request editor state with calling getTextBeforeCursor, getSelectedText, etc.
  * This class stores a snapshot of the input state of the edit buffer and provide utility functions
  * for answering these information retrieval requests.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 data class InputState(
     /**
      * A text visible to IME
@@ -53,13 +52,13 @@
      * Helper function for getting text before selection range.
      */
     fun getTextBeforeSelection(maxChars: Int): String =
-        text.substring(Math.max(0, selection.min - maxChars), selection.min)
+        text.substring(max(0, selection.min - maxChars), selection.min)
 
     /**
      * Helper function for getting text after selection range.
      */
     fun getTextAfterSelection(maxChars: Int): String =
-        text.substring(selection.max, Math.min(selection.max + maxChars, text.length))
+        text.substring(selection.max, min(selection.max + maxChars, text.length))
 
     /**
      * Helper function for getting text currently selected.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt b/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
index af4e201..968a0d6 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/TextInputService.kt
@@ -16,7 +16,6 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
 import androidx.ui.engine.geometry.Rect
 
 /**
@@ -30,26 +29,19 @@
 
 /**
  * A special session token which represents there is no active input session.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 const val NO_SESSION: InputSessionToken = 0
 
 /**
  * A special session token which represents the session couldn't be established.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 const val INVALID_SESSION: InputSessionToken = -1
 
 /**
  * Provide a communication with platform text input service.
- *
- * Open for testing purpose.
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
-open class TextInputService(val platformTextInputService: PlatformTextInputService) {
+// Open for testing purposes.
+open class TextInputService(private val platformTextInputService: PlatformTextInputService) {
 
     private var nextSessionToken: Int = 1
     private var currentSessionToken: InputSessionToken = NO_SESSION
@@ -113,10 +105,8 @@
 }
 
 /**
- * An interface for text input service.
- * @hide
+ * Platform specific text input service.
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY)
 interface PlatformTextInputService {
     /**
      * Start text input session for given client.
diff --git a/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt b/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
index d514202..4504c34 100644
--- a/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/input/VisualTransformation.kt
@@ -16,7 +16,6 @@
 
 package androidx.ui.input
 
-import androidx.annotation.RestrictTo
 import androidx.ui.text.AnnotatedString
 
 /**
@@ -47,6 +46,16 @@
      * @see VisualTransformation
      */
     fun transformedToOriginal(offset: Int): Int
+
+    companion object {
+        /**
+         * The offset map used for identity mapping.
+         */
+        val identityOffsetMap = object : OffsetMap {
+            override fun originalToTransformed(offset: Int): Int = offset
+            override fun transformedToOriginal(offset: Int): Int = offset
+        }
+    }
 }
 
 /**
@@ -108,18 +117,7 @@
     override fun filter(text: AnnotatedString): TransformedText {
         return TransformedText(
             AnnotatedString(Character.toString(mask).repeat(text.text.length)),
-            identityOffsetMap
+            OffsetMap.identityOffsetMap
         )
     }
 }
-
-/**
- * The offset map used for identity mapping.
- *
- * @hide
- */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
-val identityOffsetMap = object : OffsetMap {
-    override fun originalToTransformed(offset: Int): Int = offset
-    override fun transformedToOriginal(offset: Int): Int = offset
-}
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt b/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
index 6516fb9..a415d9e 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/Locale.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text
 
+import androidx.compose.Immutable
 import androidx.ui.text.platform.PlatformLocale
 import androidx.ui.text.platform.platformLocaleDelegate
 
@@ -28,6 +29,7 @@
  *
  * @see [TextStyle]
  */
+@Immutable
 class Locale internal constructor(internal val platformLocale: PlatformLocale) {
     companion object {
         /**
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt b/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
index 5d0f6b8..70cceb8 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/LocaleList.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text
 
+import androidx.compose.Immutable
 import androidx.ui.text.platform.platformLocaleDelegate
 
 /**
@@ -23,6 +24,7 @@
  *
  * @see [TextStyle]
  */
+@Immutable
 data class LocaleList constructor(val localeList: List<Locale>) : Collection<Locale> {
     companion object {
         /**
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt b/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
index bc3d9b20..b6245a3 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/ParagraphStyle.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text
 
+import androidx.compose.Immutable
 import androidx.ui.core.Sp
 import androidx.ui.text.style.TextAlign
 import androidx.ui.text.style.TextDirectionAlgorithm
@@ -40,6 +41,7 @@
  * @see [Paragraph]
  * @see [AnnotatedString]
  */
+@Immutable
 data class ParagraphStyle constructor(
     val textAlign: TextAlign? = null,
     val textDirectionAlgorithm: TextDirectionAlgorithm? = null,
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
index f717759..7fc3a4d 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextSpan.kt
@@ -16,8 +16,6 @@
 
 package androidx.ui.text
 
-import androidx.annotation.RestrictTo
-
 /**
  * A [TextSpan] object can be styled using its [style] property.
  * The style will be applied to the [text] and the [children].
@@ -31,10 +29,7 @@
  *
  * @param children Additional spans to include as children. If both [text] and [children] are
  *   non-null, the text will precede the children. The list must not contain any nulls.
- *
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 class TextSpan(
     val style: TextStyle? = null,
     val text: String? = null,
@@ -45,7 +40,7 @@
      * Walks this text span and its descendants in pre-order and calls [visitor]
      * for each span that has text.
      */
-    fun visitTextSpan(visitor: (span: TextSpan) -> Boolean): Boolean {
+    internal fun visitTextSpan(visitor: (span: TextSpan) -> Boolean): Boolean {
         if (text != null) {
             if (!visitor(this)) {
                 return false
@@ -87,9 +82,7 @@
 
 /**
  * Convert a [TextSpan] into an [AnnotatedString].
- * @hide
  */
-@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 fun TextSpan.toAnnotatedString(): AnnotatedString {
     return with(AnnotatedString.Builder()) {
         annotatedStringVisitor(this)
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
index ace6fbf..9636396 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextStyle.kt
@@ -16,10 +16,12 @@
 
 package androidx.ui.text
 
+import androidx.compose.Immutable
 import androidx.ui.core.Em
 import androidx.ui.core.Sp
 import androidx.ui.core.em
 import androidx.ui.core.isInherit
+import androidx.ui.core.lerp
 import androidx.ui.core.sp
 import androidx.ui.graphics.Color
 import androidx.ui.graphics.Shadow
@@ -64,6 +66,7 @@
  *
  *  @see [AnnotatedString]
  */
+@Immutable
 data class TextStyle(
     val color: Color? = null,
     val fontSize: Sp = Sp.Inherit,
@@ -113,22 +116,6 @@
     }
 }
 
-private fun lerpColor(a: Color?, b: Color?, t: Float): Color? {
-    if (a == null && b == null) {
-        return null
-    }
-    val start = a ?: b!!.copy(alpha = 0f)
-    val end = b ?: a!!.copy(alpha = 0f)
-    return lerp(start, end, t)
-}
-
-private fun lerpFloat(a: Float?, b: Float?, t: Float, default: Float = 0f): Float? {
-    if (a == null && b == null) return null
-    val start = a ?: default
-    val end = b ?: default
-    return lerp(start, end, t)
-}
-
 /**
  * @param a An sp value. Maybe [Sp.Inherit]
  * @param b An sp value. Maybe [Sp.Inherit]
@@ -140,14 +127,7 @@
     return androidx.ui.core.lerp(start, end, t)
 }
 
-private fun lerpEm(a: Em?, b: Em?, t: Float, default: Em = 0f.em): Em? {
-    if (a == null && b == null) return null
-    val start = a ?: default
-    val end = b ?: default
-    return androidx.ui.core.lerp(start, end, t)
-}
-
-private fun <T> lerpDiscrete(a: T?, b: T?, t: Float): T? = if (t < 0.5) a else b
+private fun <T> lerpDiscrete(a: T, b: T, t: Float): T = if (t < 0.5) a else b
 
 /**
  * Interpolate between two text styles.
@@ -162,56 +142,25 @@
  * between [start] and [stop]. The interpolation can be extrapolated beyond 0.0 and
  * 1.0, so negative values and values greater than 1.0 are valid.
  */
-fun lerp(start: TextStyle? = null, stop: TextStyle? = null, fraction: Float): TextStyle? {
-    val aIsNull = start == null
-    val bIsNull = stop == null
-
-    if (aIsNull && bIsNull) return null
-
-    if (start == null) {
-        val newB = stop?.copy() ?: TextStyle()
-        return if (fraction < 0.5) {
-            TextStyle(
-                color = lerpColor(null, newB.color, fraction),
-                fontWeight = lerp(null, newB.fontWeight, fraction)
-            )
-        } else {
-            newB.copy(
-                color = lerpColor(null, newB.color, fraction),
-                fontWeight = lerp(null, newB.fontWeight, fraction)
-            )
-        }
-    }
-
-    if (stop == null) {
-        return if (fraction < 0.5) {
-            start.copy(
-                color = lerpColor(start.color, null, fraction),
-                fontWeight = lerp(start.fontWeight, null, fraction)
-            )
-        } else {
-            TextStyle(
-                color = lerpColor(start.color, null, fraction),
-                fontWeight = lerp(start.fontWeight, null, fraction)
-            )
-        }
-    }
-
+fun lerp(start: TextStyle, stop: TextStyle, fraction: Float): TextStyle {
     return TextStyle(
-        color = lerpColor(start.color, stop.color, fraction),
+        color = lerp(start.color ?: Color.Black, stop.color ?: Color.Black, fraction),
         fontFamily = lerpDiscrete(
             start.fontFamily,
             stop.fontFamily,
             fraction
         ),
         fontSize = lerpSp(start.fontSize, stop.fontSize, fraction),
-        fontSizeScale = lerpFloat(
-            start.fontSizeScale,
-            stop.fontSizeScale,
-            fraction,
-            1f
+        fontSizeScale = lerp(
+            start.fontSizeScale ?: 1.0f,
+            stop.fontSizeScale ?: 1.0f,
+            fraction
         ),
-        fontWeight = lerp(start.fontWeight, stop.fontWeight, fraction),
+        fontWeight = lerp(
+            start.fontWeight ?: FontWeight.Normal,
+            stop.fontWeight ?: FontWeight.Normal,
+            fraction
+        ),
         fontStyle = lerpDiscrete(
             start.fontStyle,
             stop.fontStyle,
@@ -227,9 +176,9 @@
             stop.fontFeatureSettings,
             fraction
         ),
-        letterSpacing = lerpEm(
-            start.letterSpacing,
-            stop.letterSpacing,
+        letterSpacing = lerp(
+            start.letterSpacing ?: 0.em,
+            stop.letterSpacing ?: 0.em,
             fraction
         ),
         baselineShift = lerp(
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt b/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
index f40df88..c98da42 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/font/FontFamily.kt
@@ -16,6 +16,8 @@
 
 package androidx.ui.text.font
 
+import androidx.compose.Immutable
+
 /**
  * Defines a font family. It can be constructed via a generic font family such as serif, sans-serif
  * (i.e. FontFamily("sans-serif"). It can also be constructed by a set of custom fonts.
@@ -23,6 +25,7 @@
  * @sample androidx.ui.text.samples.FontFamilySansSerifSample
  * @sample androidx.ui.text.samples.CustomFontFamilySample
  */
+@Immutable
 data class FontFamily private constructor(val genericFamily: String?, val fonts: List<Font>) :
     List<Font> by fonts {
 
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt b/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
index c2e9a2d..2bc452c 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/font/FontWeight.kt
@@ -15,6 +15,7 @@
  */
 package androidx.ui.text.font
 
+import androidx.compose.Immutable
 import androidx.ui.lerp
 
 /**
@@ -23,6 +24,7 @@
  * @see [Font]
  * @see [FontFamily]
  */
+@Immutable
 /* inline */ data class FontWeight private constructor(
     /**
      * Can be in the range of [1,1000]
@@ -108,12 +110,8 @@
  * Values for [fraction] are usually obtained from an [Animation<Float>], such as
  * an `AnimationController`.
  */
-fun lerp(start: FontWeight?, stop: FontWeight?, fraction: Float): FontWeight {
-    val index = lerp(
-        start?.index ?: FontWeight.Normal.index,
-        stop?.index ?: FontWeight.Normal.index,
-        fraction
-    ).coerceIn(0, FontWeight.values.size - 1)
+fun lerp(start: FontWeight, stop: FontWeight, fraction: Float): FontWeight {
+    val index = lerp(start.index, stop.index, fraction).coerceIn(0, FontWeight.values.size - 1)
 
     return FontWeight.values[index]
 }
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
index edd2aa5..8f4c742 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/BaselineShift.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text.style
 
+import androidx.compose.Immutable
 import androidx.ui.lerp
 
 /**
@@ -26,6 +27,7 @@
  *
  * @param multiplier shift the baseline by multiplier * (baseline - ascent)
  */
+@Immutable
 /*inline*/ data class BaselineShift constructor(
     val multiplier: Float
 ) {
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
index be5f466..fa73392 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextDecoration.kt
@@ -15,9 +15,12 @@
  */
 package androidx.ui.text.style
 
+import androidx.compose.Immutable
+
 /**
  * Defines a horizontal line to be drawn on the text.
  */
+@Immutable
 data class TextDecoration internal constructor(val mask: Int) {
 
     companion object {
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
index c4cd690..0283448 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextGeometricTransform.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text.style
 
+import androidx.compose.Immutable
 import androidx.ui.lerp
 
 /**
@@ -25,6 +26,7 @@
  * @param skewX The shear of the text on the horizontal direction. A pixel at (x, y), where y is
  * the distance above baseline, will be transformed to (x + y * skewX, y).
  */
+@Immutable
 data class TextGeometricTransform(
     val scaleX: Float? = null,
     val skewX: Float? = null
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt b/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
index 7e301e8..ff42d41 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/style/TextIndent.kt
@@ -16,6 +16,7 @@
 
 package androidx.ui.text.style
 
+import androidx.compose.Immutable
 import androidx.ui.core.Sp
 import androidx.ui.core.lerp
 import androidx.ui.core.sp
@@ -26,6 +27,7 @@
  * @param firstLine the amount of indentation applied to the first line.
  * @param restLine the amount of indentation applied to every line except the first line.
  */
+@Immutable
 data class TextIndent(
     val firstLine: Sp = 0.sp,
     val restLine: Sp = 0.sp
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
index 28ccbeb..d5ab64e 100644
--- a/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
+++ b/ui/ui-text/src/test/java/androidx/ui/text/TextStyleTest.kt
@@ -431,81 +431,6 @@
     }
 
     @Test
-    fun `lerp with both Null Textstyles`() {
-        val newTextStyle = lerp(fraction = 1.0f)
-
-        assertThat(newTextStyle).isEqualTo(null)
-    }
-
-    @Test
-    fun `lerp color with a is Null and t is smaller than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.3f
-        val textStyle = TextStyle(color = color)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.color).isEqualTo(
-            lerp(
-                start = color.copy(alpha = 0f),
-                stop = color,
-                fraction = t
-            )
-        )
-    }
-
-    @Test
-    fun `lerp color with a is Null and t is larger than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.8f
-        val textStyle = TextStyle(color = color)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.color).isEqualTo(
-            lerp(
-                start = color.copy(alpha = 0f),
-                stop = color,
-                fraction = t
-            )
-        )
-    }
-
-    @Test
-    fun `lerp color with b is Null and t is smaller than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.3f
-        val textStyle = TextStyle(color = color)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.color).isEqualTo(
-            lerp(
-                start = color,
-                stop = color.copy(alpha = 0f),
-                fraction = t
-            )
-        )
-    }
-
-    @Test
-    fun `lerp color with b is Null and t is larger than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.8f
-        val textStyle = TextStyle(color = color)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.color).isEqualTo(
-            lerp(
-                start = color,
-                stop = color.copy(alpha = 0f),
-                fraction = t
-            )
-        )
-    }
-
-    @Test
     fun `lerp color with a and b are not Null`() {
         val color1 = Color(0xFF00FF00)
         val color2 = Color(0x00FFFF00)
@@ -515,51 +440,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.color).isEqualTo(lerp(start = color1, stop = color2, fraction = t))
-    }
-
-    @Test
-    fun `lerp fontFamily with a is Null and t is smaller than half`() {
-        val fontFamily = FontFamily(genericFamily = "sans-serif")
-        val t = 0.3f
-        val textStyle = TextStyle(fontFamily = fontFamily)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFamily).isNull()
-    }
-
-    @Test
-    fun `lerp fontFamily with a is Null and t is larger than half`() {
-        val fontFamily = FontFamily(genericFamily = "sans-serif")
-        val t = 0.7f
-        val textStyle = TextStyle(fontFamily = fontFamily)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily)
-    }
-
-    @Test
-    fun `lerp fontFamily with b is Null and t is smaller than half`() {
-        val fontFamily = FontFamily(genericFamily = "sans-serif")
-        val t = 0.3f
-        val textStyle = TextStyle(fontFamily = fontFamily)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily)
-    }
-
-    @Test
-    fun `lerp fontFamily with b is Null and t is larger than half`() {
-        val fontFamily = FontFamily(genericFamily = "sans-serif")
-        val t = 0.7f
-        val textStyle = TextStyle(fontFamily = fontFamily)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFamily).isNull()
+        assertThat(newTextStyle.color).isEqualTo(lerp(start = color1, stop = color2, fraction = t))
     }
 
     @Test
@@ -572,7 +453,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily1)
+        assertThat(newTextStyle.fontFamily).isEqualTo(fontFamily1)
     }
 
     @Test
@@ -585,53 +466,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontFamily).isEqualTo(fontFamily2)
-    }
-
-    @Test
-    fun `lerp fontSize with a is Null and t is smaller than half`() {
-        val fontSize = 8.sp
-        val t = 0.3f
-        val textStyle = TextStyle(fontSize = fontSize)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle).isNotNull()
-        assertThat(newTextStyle!!.fontSize.isInherit()).isTrue()
-    }
-
-    @Test
-    fun `lerp fontSize with a is Null and t is larger than half`() {
-        val fontSize = 8.sp
-        val t = 0.8f
-        val textStyle = TextStyle(fontSize = fontSize)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSize).isEqualTo(fontSize)
-    }
-
-    @Test
-    fun `lerp fontSize with b is Null and t is smaller than half`() {
-        val fontSize = 8.sp
-        val t = 0.3f
-        val textStyle = TextStyle(fontSize = fontSize)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSize).isEqualTo(fontSize)
-    }
-
-    @Test
-    fun `lerp fontSize with b is Null and t is larger than half`() {
-        val fontSize = 8.sp
-        val t = 0.8f
-        val textStyle = TextStyle(fontSize = fontSize)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle).isNotNull()
-        assertThat(newTextStyle!!.fontSize.isInherit()).isTrue()
+        assertThat(newTextStyle.fontFamily).isEqualTo(fontFamily2)
     }
 
     @Test
@@ -645,7 +480,7 @@
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
         // a + (b - a) * t = 8.0f + (16.0f  - 8.0f) * 0.8f = 14.4f
-        assertThat(newTextStyle?.fontSize).isEqualTo(14.4.sp)
+        assertThat(newTextStyle.fontSize).isEqualTo(14.4.sp)
     }
 
     @Test
@@ -659,90 +494,7 @@
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
         // a + (b - a) * t = 2.0f + (4.0f  - 2.0f) * 0.8f = 3.6f
-        assertThat(newTextStyle?.fontSizeScale).isEqualTo(3.6f)
-    }
-
-    @Test
-    fun `lerp fontSizeScale with a not Null and b is Null`() {
-        val fontSizeScale = 2.0f
-        val t = 0.8f
-        val textStyle1 = TextStyle(fontSizeScale = fontSizeScale)
-        val textStyle2 = TextStyle()
-
-        val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
-        // b is Null and is considered 1.0f
-        // a + (b - a) * t = 2.0f + (1.0f  - 2.0f) * 0.8f = 1.2f
-        assertThat(newTextStyle?.fontSizeScale).isEqualTo(1.2f)
-    }
-
-    @Test
-    fun `lerp fontSizeScale with a is Null and b not Null`() {
-        val fontSizeScale = 2.0f
-        val t = 0.8f
-        val textStyle1 = TextStyle()
-        val textStyle2 = TextStyle(fontSizeScale = fontSizeScale)
-
-        val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
-        // a is Null and is considered 1.0f
-        // a + (b - a) * t = 1.0f + (2.0f  - 1.0f) * 0.8f = 1.8f
-        assertThat(newTextStyle?.fontSizeScale).isEqualTo(1.8f)
-    }
-
-    @Test
-    fun `lerp fontSizeScale with a and b are Null`() {
-        val t = 0.8f
-        val textStyle1 = TextStyle()
-        val textStyle2 = TextStyle()
-
-        val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
-
-        assertThat(newTextStyle?.fontSizeScale).isNull()
-    }
-
-    @Test
-    fun `lerp fontWeight with a is Null and t is smaller than half`() {
-        val fontWeight = FontWeight.W700
-        val t = 0.3f
-        val textStyle = TextStyle(fontWeight = fontWeight)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(null, fontWeight, t))
-    }
-
-    @Test
-    fun `lerp fontWeight with a is Null and t is larger than half`() {
-        val fontWeight = FontWeight.W700
-        val t = 0.8f
-        val textStyle = TextStyle(fontWeight = fontWeight)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(null, fontWeight, t))
-    }
-
-    @Test
-    fun `lerp fontWeight with b is Null and t is smaller than half`() {
-        val fontWeight = FontWeight.W700
-        val t = 0.3f
-        val textStyle = TextStyle(fontWeight = fontWeight)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight, null, t))
-    }
-
-    @Test
-    fun `lerp fontWeight with b is Null and t is larger than half`() {
-        val fontWeight = FontWeight.W700
-        val t = 0.8f
-        val textStyle = TextStyle(fontWeight = fontWeight)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight, null, t))
+        assertThat(newTextStyle.fontSizeScale).isEqualTo(3.6f)
     }
 
     @Test
@@ -755,51 +507,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontWeight).isEqualTo(lerp(fontWeight1, fontWeight2, t))
-    }
-
-    @Test
-    fun `lerp fontStyle with a is Null and t is smaller than half`() {
-        val fontStyle = FontStyle.Italic
-        val t = 0.3f
-        val textStyle = TextStyle(fontStyle = fontStyle)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontStyle).isNull()
-    }
-
-    @Test
-    fun `lerp fontStyle with a is Null and t is larger than half`() {
-        val fontStyle = FontStyle.Italic
-        val t = 0.8f
-        val textStyle = TextStyle(fontStyle = fontStyle)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle)
-    }
-
-    @Test
-    fun `lerp fontStyle with b is Null and t is smaller than half`() {
-        val fontStyle = FontStyle.Italic
-        val t = 0.3f
-        val textStyle = TextStyle(fontStyle = fontStyle)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle)
-    }
-
-    @Test
-    fun `lerp fontStyle with b is Null and t is larger than half`() {
-        val fontStyle = FontStyle.Italic
-        val t = 0.8f
-        val textStyle = TextStyle(fontStyle = fontStyle)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontStyle).isNull()
+        assertThat(newTextStyle.fontWeight).isEqualTo(lerp(fontWeight1, fontWeight2, t))
     }
 
     @Test
@@ -813,7 +521,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle1)
+        assertThat(newTextStyle.fontStyle).isEqualTo(fontStyle1)
     }
 
     @Test
@@ -827,51 +535,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontStyle).isEqualTo(fontStyle2)
-    }
-
-    @Test
-    fun `lerp fontSynthesis with a is Null and t is smaller than half`() {
-        val fontSynthesis = FontSynthesis.Style
-        val t = 0.3f
-        val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSynthesis).isNull()
-    }
-
-    @Test
-    fun `lerp fontSynthesis with a is Null and t is larger than half`() {
-        val fontSynthesis = FontSynthesis.Style
-        val t = 0.8f
-        val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis)
-    }
-
-    @Test
-    fun `lerp fontSynthesis with b is Null and t is smaller than half`() {
-        val fontSynthesis = FontSynthesis.Style
-        val t = 0.3f
-        val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis)
-    }
-
-    @Test
-    fun `lerp fontSynthesis with b is Null and t is larger than half`() {
-        val fontSynthesis = FontSynthesis.Style
-        val t = 0.8f
-        val textStyle = TextStyle(fontSynthesis = fontSynthesis)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontSynthesis).isNull()
+        assertThat(newTextStyle.fontStyle).isEqualTo(fontStyle2)
     }
 
     @Test
@@ -886,7 +550,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis1)
+        assertThat(newTextStyle.fontSynthesis).isEqualTo(fontSynthesis1)
     }
 
     @Test
@@ -901,51 +565,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontSynthesis).isEqualTo(fontSynthesis2)
-    }
-
-    @Test
-    fun `lerp fontFeatureSettings with a is Null and t is smaller than half`() {
-        val fontFeatureSettings = "\"kern\" 0"
-        val t = 0.3f
-        val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFeatureSettings).isNull()
-    }
-
-    @Test
-    fun `lerp fontFeatureSettings with a is Null and t is larger than half`() {
-        val fontFeatureSettings = "\"kern\" 0"
-        val t = 0.8f
-        val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings)
-    }
-
-    @Test
-    fun `lerp fontFeatureSettings with b is Null and t is smaller than half`() {
-        val fontFeatureSettings = "\"kern\" 0"
-        val t = 0.3f
-        val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings)
-    }
-
-    @Test
-    fun `lerp fontFeatureSettings with b is Null and t is larger than half`() {
-        val fontFeatureSettings = "\"kern\" 0"
-        val t = 0.8f
-        val textStyle = TextStyle(fontFeatureSettings = fontFeatureSettings)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.fontFeatureSettings).isNull()
+        assertThat(newTextStyle.fontSynthesis).isEqualTo(fontSynthesis2)
     }
 
     @Test
@@ -960,7 +580,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings1)
+        assertThat(newTextStyle.fontFeatureSettings).isEqualTo(fontFeatureSettings1)
     }
 
     @Test
@@ -975,51 +595,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.fontFeatureSettings).isEqualTo(fontFeatureSettings2)
-    }
-
-    @Test
-    fun `lerp letterSpacing with a is Null and t is smaller than half`() {
-        val letterSpacing = 2.em
-        val t = 0.3f
-        val textStyle = TextStyle(letterSpacing = letterSpacing)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.letterSpacing).isNull()
-    }
-
-    @Test
-    fun `lerp letterSpacing with a is Null and t is larger than half`() {
-        val letterSpacing = 2.em
-        val t = 0.8f
-        val textStyle = TextStyle(letterSpacing = letterSpacing)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.letterSpacing).isEqualTo(letterSpacing)
-    }
-
-    @Test
-    fun `lerp letterSpacing with b is Null and t is smaller than half`() {
-        val letterSpacing = 2.em
-        val t = 0.3f
-        val textStyle = TextStyle(letterSpacing = letterSpacing)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.letterSpacing).isEqualTo(letterSpacing)
-    }
-
-    @Test
-    fun `lerp letterSpacing with b is Null and t is larger than half`() {
-        val letterSpacing = 2.em
-        val t = 0.8f
-        val textStyle = TextStyle(letterSpacing = letterSpacing)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.letterSpacing).isNull()
+        assertThat(newTextStyle.fontFeatureSettings).isEqualTo(fontFeatureSettings2)
     }
 
     @Test
@@ -1032,55 +608,11 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.baselineShift)
+        assertThat(newTextStyle.baselineShift)
             .isEqualTo(lerp(baselineShift1, baselineShift2, t))
     }
 
     @Test
-    fun `lerp textGeometricTransform with a is Null and t is smaller than half`() {
-        val textTransform = TextGeometricTransform(scaleX = 1.5f)
-        val t = 0.3f
-        val textStyle = TextStyle(textGeometricTransform = textTransform)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.textGeometricTransform).isNull()
-    }
-
-    @Test
-    fun `lerp textGeometricTransform with a is Null and t is larger than half`() {
-        val textTransform = TextGeometricTransform(scaleX = 1.5f)
-        val t = 0.7f
-        val textStyle = TextStyle(textGeometricTransform = textTransform)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.textGeometricTransform).isEqualTo(textTransform)
-    }
-
-    @Test
-    fun `lerp textGeometricTransform with b is Null and t is smaller than half`() {
-        val textTransform = TextGeometricTransform(scaleX = 1.5f)
-        val t = 0.3f
-        val textStyle = TextStyle(textGeometricTransform = textTransform)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.textGeometricTransform).isEqualTo(textTransform)
-    }
-
-    @Test
-    fun `lerp textGeometricTransform with b is Null and t is larger than half`() {
-        val textTransform = TextGeometricTransform(scaleX = 1.5f)
-        val t = 0.7f
-        val textStyle = TextStyle(textGeometricTransform = textTransform)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.textGeometricTransform).isNull()
-    }
-
-    @Test
     fun `lerp textGeometricTransform with a and b are not Null`() {
         val textTransform1 =
             TextGeometricTransform(scaleX = 1.5f, skewX = 0.1f)
@@ -1092,55 +624,11 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.textGeometricTransform)
+        assertThat(newTextStyle.textGeometricTransform)
             .isEqualTo(lerp(textTransform1, textTransform2, t))
     }
 
     @Test
-    fun `lerp locale with a is Null and t is smaller than half`() {
-        val localeList = LocaleList("en-US")
-        val t = 0.2f
-        val textStyle = TextStyle(localeList = localeList)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.localeList).isNull()
-    }
-
-    @Test
-    fun `lerp locale with a is Null and t is larger than half`() {
-        val localeList = LocaleList("en-US")
-        val t = 0.8f
-        val textStyle = TextStyle(localeList = localeList)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.localeList).isEqualTo(localeList)
-    }
-
-    @Test
-    fun `lerp locale with b is Null and t is smaller than half`() {
-        val localeList = LocaleList("en-US")
-        val t = 0.2f
-        val textStyle = TextStyle(localeList = localeList)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.localeList).isEqualTo(localeList)
-    }
-
-    @Test
-    fun `lerp locale with b is Null and t is larger than half`() {
-        val localeList = LocaleList("en-US")
-        val t = 0.8f
-        val textStyle = TextStyle(localeList = localeList)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.localeList).isNull()
-    }
-
-    @Test
     fun `lerp locale with a and b are not Null and t is smaller than half`() {
         val localeList1 = LocaleList("en-US")
         val localeList2 = LocaleList("ja-JP")
@@ -1150,7 +638,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.localeList).isEqualTo(localeList1)
+        assertThat(newTextStyle.localeList).isEqualTo(localeList1)
     }
 
     @Test
@@ -1163,50 +651,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.localeList).isEqualTo(localeList2)
-    }
-
-    @Test
-    fun `lerp background with a is Null and t is smaller than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.2f
-        val textStyle = TextStyle(background = color)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.background).isNull()
-    }
-
-    @Test
-    fun `lerp background with a is Null and t is larger than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.8f
-        val textStyle = TextStyle(background = color)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.background).isEqualTo(color)
-    }
-
-    @Test
-    fun `lerp background with b is Null and t is smaller than half`() {
-        val color = Color(0xFF00FF00)
-        val t = 0.2f
-        val textStyle = TextStyle(background = color)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.background).isEqualTo(color)
-    }
-
-    @Test
-    fun `lerp background with b is Null and t is larger than half`() {
-        val t = 0.8f
-        val textStyle = TextStyle(background = Color(0xFF00FF00))
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.background).isNull()
+        assertThat(newTextStyle.localeList).isEqualTo(localeList2)
     }
 
     @Test
@@ -1219,7 +664,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.background).isEqualTo(color1)
+        assertThat(newTextStyle.background).isEqualTo(color1)
     }
 
     @Test
@@ -1232,51 +677,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.background).isEqualTo(color2)
-    }
-
-    @Test
-    fun `lerp decoration with a is Null and t is smaller than half`() {
-        val decoration = TextDecoration.LineThrough
-        val t = 0.2f
-        val textStyle = TextStyle(decoration = decoration)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.decoration).isNull()
-    }
-
-    @Test
-    fun `lerp decoration with a is Null and t is larger than half`() {
-        val decoration = TextDecoration.LineThrough
-        val t = 0.8f
-        val textStyle = TextStyle(decoration = decoration)
-
-        val newTextStyle = lerp(stop = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.decoration).isEqualTo(decoration)
-    }
-
-    @Test
-    fun `lerp decoration with b is Null and t is smaller than half`() {
-        val decoration = TextDecoration.LineThrough
-        val t = 0.2f
-        val textStyle = TextStyle(decoration = decoration)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.decoration).isEqualTo(decoration)
-    }
-
-    @Test
-    fun `lerp decoration with b is Null and t is larger than half`() {
-        val decoration = TextDecoration.LineThrough
-        val t = 0.8f
-        val textStyle = TextStyle(decoration = decoration)
-
-        val newTextStyle = lerp(start = textStyle, fraction = t)
-
-        assertThat(newTextStyle?.decoration).isNull()
+        assertThat(newTextStyle.background).isEqualTo(color2)
     }
 
     @Test
@@ -1289,7 +690,7 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.decoration).isEqualTo(decoration1)
+        assertThat(newTextStyle.decoration).isEqualTo(decoration1)
     }
 
     @Test
@@ -1302,6 +703,6 @@
 
         val newTextStyle = lerp(start = textStyle1, stop = textStyle2, fraction = t)
 
-        assertThat(newTextStyle?.decoration).isEqualTo(decoration2)
+        assertThat(newTextStyle.decoration).isEqualTo(decoration2)
     }
 }
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
index dc6d21b..b0d0b6d 100644
--- a/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
+++ b/ui/ui-text/src/test/java/androidx/ui/text/font/FontWeightTest.kt
@@ -22,32 +22,6 @@
 
 @RunWith(JUnit4::class)
 class FontWeightTest {
-
-    @Test
-    fun `lerp with null parameters`() {
-        assertThat(lerp(null, null, 0.0f)).isEqualTo(
-            FontWeight.Normal
-        )
-    }
-
-    @Test
-    fun `lerp with one null parameter should use normal for null value`() {
-        assertThat(
-            lerp(
-                FontWeight.W200,
-                null,
-                0.5f
-            )
-        ).isEqualTo(FontWeight.W300)
-        assertThat(
-            lerp(
-                null,
-                FontWeight.W200,
-                0.5f
-            )
-        ).isEqualTo(FontWeight.W300)
-    }
-
     @Test
     fun `lerp at start returns start value`() {
         assertThat(
diff --git a/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt b/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt
new file mode 100644
index 0000000..a300883
--- /dev/null
+++ b/work/workmanager-lint/src/main/java/androidx/work/lint/RemoveWorkManagerInitializerDetector.kt
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+@file:Suppress("UnstableApiUsage")
+
+package androidx.work.lint
+
+import com.android.SdkConstants.ANDROID_URI
+import com.android.SdkConstants.ATTR_NAME
+import com.android.SdkConstants.TOOLS_URI
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Context
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.XmlContext
+import com.android.tools.lint.detector.api.XmlScanner
+import org.jetbrains.uast.UClass
+import org.w3c.dom.Element
+import org.w3c.dom.Node
+import org.w3c.dom.NodeList
+import java.util.EnumSet
+
+class RemoveWorkManagerInitializerDetector : Detector(), SourceCodeScanner, XmlScanner {
+    private var removedDefaultInitializer = false
+    private var location: Location? = null
+    private var applicationImplementsConfigurationProvider = false
+
+    companion object {
+
+        private const val DESCRIPTION = "Remove androidx.work.impl.WorkManagerInitializer from " +
+                "your AndroidManifest.xml when using on-demand initialization."
+
+        val ISSUE = Issue.create(
+            id = "RemoveWorkManagerInitializer",
+            briefDescription = DESCRIPTION,
+            explanation = """
+                If an `android.app.Application` implements `androidx.work.Configuration.Provider`,
+                the default `androidx.work.impl.WorkManagerInitializer` needs to be removed from the
+                AndroidManifest.xml file.
+            """,
+            androidSpecific = true,
+            category = Category.CORRECTNESS,
+            severity = Severity.FATAL,
+            implementation = Implementation(
+                RemoveWorkManagerInitializerDetector::class.java,
+                EnumSet.of(Scope.JAVA_FILE, Scope.MANIFEST)
+            )
+        )
+
+        private const val ATTR_NODE = "node"
+
+        fun NodeList?.find(fn: (node: Node) -> Boolean): Node? {
+            if (this == null) {
+                return null
+            } else {
+                for (i in 0 until this.length) {
+                    val node = this.item(i)
+                    if (fn(node)) {
+                        return node
+                    }
+                }
+                return null
+            }
+        }
+    }
+
+    override fun getApplicableElements() = listOf("application")
+
+    override fun applicableSuperClasses() = listOf("androidx.work.Configuration.Provider")
+
+    override fun visitElement(context: XmlContext, element: Element) {
+        val providers = element.getElementsByTagName("provider")
+        val provider = providers.find { node ->
+            val name = node.attributes.getNamedItemNS(ANDROID_URI, ATTR_NAME)?.textContent
+            name == "androidx.work.impl.WorkManagerInitializer"
+        }
+        if (provider != null) {
+            location = context.getLocation(provider)
+            val remove = provider.attributes.getNamedItemNS(TOOLS_URI, ATTR_NODE)
+            if (remove?.textContent == "remove") {
+                removedDefaultInitializer = true
+            }
+        }
+    }
+
+    override fun visitClass(context: JavaContext, declaration: UClass) {
+        if (context.evaluator.inheritsFrom(
+                declaration.javaPsi,
+                "android.app.Application",
+                false
+            )
+        ) {
+            applicationImplementsConfigurationProvider = true
+        }
+    }
+
+    override fun afterCheckRootProject(context: Context) {
+        val location = location ?: Location.create(context.file)
+        if (applicationImplementsConfigurationProvider) {
+            if (!removedDefaultInitializer) {
+                context.report(
+                    issue = ISSUE,
+                    location = location,
+                    message = DESCRIPTION
+                )
+            }
+        }
+    }
+}
diff --git a/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt b/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
index 8e69bab..fb3e9e5 100644
--- a/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
+++ b/work/workmanager-lint/src/main/java/androidx/work/lint/WorkManagerIssueRegistry.kt
@@ -26,6 +26,7 @@
     override val minApi: Int = CURRENT_API
     override val issues: List<Issue> = listOf(
         BadConfigurationProviderIssueDetector.ISSUE,
-        PeriodicEnqueueIssueDetector.ISSUE
+        PeriodicEnqueueIssueDetector.ISSUE,
+        RemoveWorkManagerInitializerDetector.ISSUE
     )
 }
diff --git a/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt b/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt
new file mode 100644
index 0000000..99f532a
--- /dev/null
+++ b/work/workmanager-lint/src/test/java/androidx/work/lint/RemoveWorkManagerInitializerDetectorTest.kt
@@ -0,0 +1,224 @@
+/*
+ * 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.work.lint
+
+import androidx.work.lint.Stubs.ANDROID_APPLICATION
+import androidx.work.lint.Stubs.WORK_MANAGER_CONFIGURATION_PROVIDER
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest.kotlin
+import com.android.tools.lint.checks.infrastructure.TestFiles.manifest
+import com.android.tools.lint.checks.infrastructure.TestLintTask.lint
+import org.junit.Test
+
+class RemoveWorkManagerInitializerDetectorTest {
+    @Test
+    fun testNoWarningsWhenDefaultInitializerIsRemoved() {
+        val customApplication = kotlin(
+            "com/example/App.kt",
+            """
+            package com.example
+
+            import android.app.Application
+            import androidx.work.Configuration
+
+            class App: Application(), Configuration.Provider {
+                override fun onCreate() {
+
+                }
+
+                override fun getWorkManagerConfiguration(): Configuration = TODO()
+            }
+            """
+        ).indented().within("src")
+
+        val manifestWithNoInitializer = manifest(
+            """
+               <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:tools="http://schemas.android.com/tools"
+                  package="com.example">
+                  <application>
+                        <provider
+                          android:name="androidx.work.impl.WorkManagerInitializer"
+                          android:authorities="com.example.workmanager-init"
+                          tools:node="remove"/>
+
+                  </application>
+                </manifest>
+        """
+        ).indented()
+
+        lint().files(
+            // Manifest file
+            manifestWithNoInitializer,
+            // Source files
+            ANDROID_APPLICATION,
+            WORK_MANAGER_CONFIGURATION_PROVIDER,
+            customApplication
+        )
+            .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testNoWarningsWhenNotUsingOnDemandInitialization() {
+        val customApplication = kotlin(
+            "com/example/App.kt",
+            """
+            package com.example
+
+            import android.app.Application
+            import androidx.work.Configuration
+
+            class App: Application() {
+                override fun onCreate() {
+
+                }
+            }
+            """
+        ).indented().within("src")
+
+        val manifestWithInitializer = manifest(
+            """
+               <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:tools="http://schemas.android.com/tools"
+                  package="com.example">
+                  <application>
+                        <provider
+                          android:name="androidx.work.impl.WorkManagerInitializer"
+                          android:authorities="com.example.workmanager-init"/>
+
+                  </application>
+                </manifest>
+        """
+        ).indented()
+
+        lint().files(
+            // Manifest file
+            manifestWithInitializer,
+            // Source files
+            ANDROID_APPLICATION,
+            WORK_MANAGER_CONFIGURATION_PROVIDER,
+            customApplication
+        )
+            .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun failWhenUsingDefaultManifestMergeStrategy() {
+        val customApplication = kotlin(
+            "com/example/App.kt",
+            """
+            package com.example
+
+            import android.app.Application
+            import androidx.work.Configuration
+
+            class App: Application(), Configuration.Provider {
+                override fun onCreate() {
+
+                }
+
+                override fun getWorkManagerConfiguration(): Configuration = TODO()
+            }
+            """
+        ).indented().within("src")
+
+        val emptyManifest = manifest(
+            """
+               <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:tools="http://schemas.android.com/tools"
+                  package="com.example">
+                  <application />
+                </manifest>
+        """
+        ).indented()
+
+        /* ktlint-disable max-line-length */
+        lint().files(
+            // Manifest file
+            emptyManifest,
+            // Source files
+            ANDROID_APPLICATION,
+            WORK_MANAGER_CONFIGURATION_PROVIDER,
+            customApplication
+        )
+            .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+            .run()
+            .expect("""
+                project0: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]
+                1 errors, 0 warnings
+            """.trimIndent())
+        /* ktlint-enable max-line-length */
+    }
+
+    @Test
+    fun failWhenManifestHasDefaultInitializer() {
+        val customApplication = kotlin(
+            "com/example/App.kt",
+            """
+            package com.example
+
+            import android.app.Application
+            import androidx.work.Configuration
+
+            class App: Application(), Configuration.Provider {
+                override fun onCreate() {
+
+                }
+
+                override fun getWorkManagerConfiguration(): Configuration = TODO()
+            }
+            """
+        ).indented().within("src")
+
+        val manifestWithInitializer = manifest(
+            """
+               <manifest xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:tools="http://schemas.android.com/tools"
+                  package="com.example">
+                  <application>
+                        <provider
+                          android:name="androidx.work.impl.WorkManagerInitializer"
+                          android:authorities="com.example.workmanager-init"/>
+
+                  </application>
+                </manifest>
+        """
+        ).indented()
+
+        /* ktlint-disable max-line-length */
+        lint().files(
+            // Manifest file
+            manifestWithInitializer,
+            // Source files
+            ANDROID_APPLICATION,
+            WORK_MANAGER_CONFIGURATION_PROVIDER,
+            customApplication
+        )
+            .issues(RemoveWorkManagerInitializerDetector.ISSUE)
+            .run()
+            .expect("""
+                AndroidManifest.xml:5: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]
+                         <provider
+                         ^
+                1 errors, 0 warnings
+            """.trimIndent())
+        /* ktlint-enable max-line-length */
+    }
+}