Merge "Fix Lint warnings in fragment" into androidx-master-dev
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
index 30cedff..aafa7bf 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -45,7 +45,6 @@
       <option name="myAdditionalJavadocTags" value="hide" />
     </inspection_tool>
     <inspection_tool class="KDocUnresolvedReference" enabled="true" level="ERROR" enabled_by_default="true" />
-    <inspection_tool class="LongLine" enabled="true" level="WARNING" enabled_by_default="true" />
     <inspection_tool class="MissingDeprecatedAnnotation" enabled="true" level="ERROR" enabled_by_default="true" />
     <inspection_tool class="NullableProblems" enabled="true" level="ERROR" enabled_by_default="true">
       <option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
@@ -69,7 +68,6 @@
     </inspection_tool>
     <inspection_tool class="RawTypeCanBeGeneric" enabled="true" level="ERROR" enabled_by_default="true" />
     <inspection_tool class="RawUseOfParameterizedType" enabled="true" level="ERROR" enabled_by_default="true" />
-    <inspection_tool class="Reformat" enabled="true" level="WARNING" enabled_by_default="true" />
     <inspection_tool class="RemoveEmptyParenthesesFromAnnotationEntry" enabled="true" level="WEAK WARNING" enabled_by_default="true">
       <scope name="Compose" level="WEAK WARNING" enabled="false" />
     </inspection_tool>
diff --git a/activity/activity/build.gradle b/activity/activity/build.gradle
index 36959fc..b6edf7e 100644
--- a/activity/activity/build.gradle
+++ b/activity/activity/build.gradle
@@ -18,7 +18,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     api(project(":lifecycle:lifecycle-runtime"))
     api(project(":lifecycle:lifecycle-viewmodel"))
     api("androidx.savedstate:savedstate:1.0.0-rc01")
diff --git a/activity/activity/lint-baseline.xml b/activity/activity/lint-baseline.xml
deleted file mode 100644
index 591c093..0000000
--- a/activity/activity/lint-baseline.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  Copyright 2019 The Android Open Source Project
-
-  Licensed under the Apache License, Version 2.0 (the "License");
-  you may not use this file except in compliance with the License.
-  You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
-  -->
-
-<issues format="5" by="lint 3.5.0-beta04" client="gradle" variant="debug" version="3.5.0-beta04">
-
-    <issue
-        id="LambdaLast"
-        message="Functional interface parameters (such as parameter 1, &quot;owner&quot;, in androidx.activity.OnBackPressedDispatcher.addCallback) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions"
-        errorLine1="            @NonNull OnBackPressedCallback onBackPressedCallback) {"
-        errorLine2="            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
-        <location
-            file="src/main/java/androidx/activity/OnBackPressedDispatcher.java"
-            line="144"
-            column="13"/>
-    </issue>
-
-</issues>
diff --git a/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.java b/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.java
index 71e5dce..e842248 100644
--- a/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.java
+++ b/activity/activity/src/main/java/androidx/activity/OnBackPressedDispatcher.java
@@ -16,6 +16,8 @@
 
 package androidx.activity;
 
+import android.annotation.SuppressLint;
+
 import androidx.annotation.MainThread;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -139,6 +141,7 @@
      *
      * @see #onBackPressed()
      */
+    @SuppressLint("LambdaLast")
     @MainThread
     public void addCallback(@NonNull LifecycleOwner owner,
             @NonNull OnBackPressedCallback onBackPressedCallback) {
diff --git a/ads/ads-identifier-provider/build.gradle b/ads/ads-identifier-provider/build.gradle
index 535bbde..78b4ade 100644
--- a/ads/ads-identifier-provider/build.gradle
+++ b/ads/ads-identifier-provider/build.gradle
@@ -27,7 +27,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation(AUTO_VALUE_ANNOTATIONS)
     annotationProcessor(AUTO_VALUE)
 
diff --git a/ads/ads-identifier/build.gradle b/ads/ads-identifier/build.gradle
index 3ab81a6..3eca9f2 100644
--- a/ads/ads-identifier/build.gradle
+++ b/ads/ads-identifier/build.gradle
@@ -27,7 +27,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation(AUTO_VALUE_ANNOTATIONS)
     annotationProcessor(AUTO_VALUE)
     api(GUAVA_LISTENABLE_FUTURE)
diff --git a/animation/build.gradle b/animation/build.gradle
index 1d1800e..65781d0 100644
--- a/animation/build.gradle
+++ b/animation/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT, libs.exclude_for_espresso)
diff --git a/animation/integration-tests/testapp/build.gradle b/animation/integration-tests/testapp/build.gradle
index a9992a4..82a6fe05 100644
--- a/animation/integration-tests/testapp/build.gradle
+++ b/animation/integration-tests/testapp/build.gradle
@@ -23,7 +23,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation(project(":animation"))
     implementation(project(":animation:testing"))
 
diff --git a/animation/testing/build.gradle b/animation/testing/build.gradle
index ad98a4c..f33191e 100644
--- a/animation/testing/build.gradle
+++ b/animation/testing/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     implementation("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation(project(":animation"))
     implementation(ANDROIDX_TEST_EXT_JUNIT)
     implementation(ANDROIDX_TEST_CORE)
diff --git a/annotation/annotation/README.md b/annotation/annotation/README.md
index b7f5912..e65290d 100644
--- a/annotation/annotation/README.md
+++ b/annotation/annotation/README.md
@@ -7,7 +7,7 @@
 
 [Release notes](https://developer.android.com/jetpack/androidx/releases/annotation)
 
-[Browse source](https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/annotations/)
+[Browse source](https://android.googlesource.com/platform/frameworks/support/+/androidx-master-dev/annotation/annotation/)
 
 [Reference documentation](https://developer.android.com/reference/androidx/classes.html)
 
diff --git a/appcompat/build.gradle b/appcompat/build.gradle
index e18e0bd9..5ce2ab6 100644
--- a/appcompat/build.gradle
+++ b/appcompat/build.gradle
@@ -12,7 +12,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
 
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.cursoradapter:cursoradapter:1.0.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
diff --git a/asynclayoutinflater/build.gradle b/asynclayoutinflater/build.gradle
index 3dcd2f0..2c12378 100644
--- a/asynclayoutinflater/build.gradle
+++ b/asynclayoutinflater/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
 }
 
 androidx {
diff --git a/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/ParameterizedBenchmark.kt b/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/ParameterizedBenchmark.kt
index 050c32d..09a21f4 100644
--- a/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/ParameterizedBenchmark.kt
+++ b/benchmark/benchmark/src/androidTest/java/androidx/benchmark/benchmark/ParameterizedBenchmark.kt
@@ -23,14 +23,18 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
 
 @LargeTest
 @RunWith(Parameterized::class)
-class ParameterizedBenchmark(@Suppress("unused") private val input: Int) {
+class ParameterizedBenchmark(
+    @Suppress("unused") private val input: Int,
+    @Suppress("unused") private val stringInput: String
+) {
     companion object {
         @JvmStatic
-        @Parameterized.Parameters
-        fun data(): Collection<Array<Int>> = List(2) { arrayOf(it) }
+        @Parameters(name = "size={0},str:{1}")
+        fun data(): Collection<Array<Any>> = List(2) { arrayOf(it, "$it=:") }
     }
 
     @get:Rule
diff --git a/benchmark/common/build.gradle b/benchmark/common/build.gradle
index 488d327..a6d74c9 100644
--- a/benchmark/common/build.gradle
+++ b/benchmark/common/build.gradle
@@ -32,6 +32,7 @@
 
     androidTestImplementation(ANDROIDX_TEST_RULES)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(KOTLIN_TEST_COMMON)
 }
 
 androidx {
diff --git a/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt b/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
index d48f976..5783636 100644
--- a/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
+++ b/benchmark/common/src/androidTest/java/androidx/benchmark/ResultWriterTest.kt
@@ -24,6 +24,7 @@
 import org.junit.rules.TemporaryFolder
 import org.junit.runner.RunWith
 import org.junit.runners.JUnit4
+import kotlin.test.assertTrue
 
 @SmallTest
 @RunWith(JUnit4::class)
@@ -90,6 +91,7 @@
                 "benchmarks": [
                     {
                         "name": "MethodA",
+                        "params": {},
                         "className": "package.Class1",
                         "totalRunTimeNs": 900000000,
                         "metrics": {
@@ -110,6 +112,7 @@
                     },
                     {
                         "name": "MethodB",
+                        "params": {},
                         "className": "package.Class2",
                         "totalRunTimeNs": 900000000,
                         "metrics": {
@@ -134,4 +137,61 @@
             tempFile.readText()
         )
     }
+
+    @Test
+    fun validateJsonWithParams() {
+        val reportWithParams = BenchmarkState.Report(
+            testName = "MethodWithParams[number=2,primeNumber=true]",
+            className = "package.Class",
+            totalRunTimeNs = 900000000,
+            data = listOf(100, 101, 102),
+            repeatIterations = 100000,
+            thermalThrottleSleepSeconds = 90000000,
+            warmupIterations = 8000
+        )
+
+        val tempFile = tempFolder.newFile()
+        ResultWriter.writeReport(tempFile, listOf(reportWithParams))
+        val reportText = tempFile.readText()
+
+        assertTrue {
+            reportText.contains(
+                """
+                |            "name": "MethodWithParams[number=2,primeNumber=true]",
+                |            "params": {
+                |                "number": "2",
+                |                "primeNumber": "true"
+                |            },
+                """.trimMargin()
+            )
+        }
+    }
+
+    @Test
+    fun validateJsonWithInvalidParams() {
+        val reportWithInvalidParams = BenchmarkState.Report(
+            testName = "MethodWithParams[number=2,=true,]",
+            className = "package.Class",
+            totalRunTimeNs = 900000000,
+            data = listOf(100, 101, 102),
+            repeatIterations = 100000,
+            thermalThrottleSleepSeconds = 90000000,
+            warmupIterations = 8000
+        )
+
+        val tempFile = tempFolder.newFile()
+        ResultWriter.writeReport(tempFile, listOf(reportWithInvalidParams))
+        val reportText = tempFile.readText()
+
+        assertTrue {
+            reportText.contains(
+                """
+                |            "name": "MethodWithParams[number=2,=true,]",
+                |            "params": {
+                |                "number": "2"
+                |            },
+                """.trimMargin()
+            )
+        }
+    }
 }
diff --git a/benchmark/common/src/main/java/androidx/benchmark/IsolationActivity.kt b/benchmark/common/src/main/java/androidx/benchmark/IsolationActivity.kt
index 18fe7c7..bf34af0 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/IsolationActivity.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/IsolationActivity.kt
@@ -19,6 +19,7 @@
 import android.annotation.SuppressLint
 import android.app.Activity
 import android.app.Application
+import android.app.KeyguardManager
 import android.content.Context
 import android.content.Intent
 import android.os.Build
@@ -26,6 +27,7 @@
 import android.os.PowerManager
 import android.os.Process
 import android.util.Log
+import android.view.WindowManager
 import android.widget.TextView
 import androidx.annotation.AnyThread
 import androidx.annotation.RestrictTo
@@ -60,21 +62,24 @@
         if (firstInit) {
             if (!CpuInfo.locked && isSustainedPerformanceModeSupported()) {
                 sustainedPerformanceModeInUse = true
-                application.registerActivityLifecycleCallbacks(sustainedPerfCallbacks)
+            }
+            application.registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
 
-                // trigger the one missed lifecycle event, from registering the callbacks late
-                sustainedPerfCallbacks.onActivityCreated(this, savedInstanceState)
+            // trigger the one missed lifecycle event, from registering the callbacks late
+            activityLifecycleCallbacks.onActivityCreated(this, savedInstanceState)
 
-                // Keep at least one core busy. Together with a single threaded benchmark, this makes
-                // the process get multi-threaded setSustainedPerformanceMode.
+            if (sustainedPerformanceModeInUse) {
+                // Keep at least one core busy. Together with a single threaded benchmark, this
+                // makes the process get multi-threaded setSustainedPerformanceMode.
                 //
-                // We want to keep to the relatively lower clocks of the multi-threaded benchmark mode
-                // to avoid any benchmarks running at higher clocks than any others.
+                // We want to keep to the relatively lower clocks of the multi-threaded benchmark
+                // mode to avoid any benchmarks running at higher clocks than any others.
                 //
                 // Note, thread names have 15 char max in Systrace
                 thread(name = "BenchSpinThread") {
                     Process.setThreadPriority(Process.THREAD_PRIORITY_LOWEST)
-                    while (true) {}
+                    while (true) {
+                    }
                 }
             }
             firstInit = false
@@ -159,11 +164,32 @@
                 false
             }
 
-        private val sustainedPerfCallbacks = object : Application.ActivityLifecycleCallbacks {
+        private val activityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks {
             @SuppressLint("NewApi") // window API guarded by [isSustainedPerformanceModeSupported]
             override fun onActivityCreated(activity: Activity, bundle: Bundle?) {
-                activity.window.setSustainedPerformanceMode(true)
+                if (sustainedPerformanceModeInUse) {
+                    activity.window.setSustainedPerformanceMode(true)
+                }
+
+                // Forcibly wake the device, and keep the screen on to prevent benchmark failures.
+                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
+                    val keyguardManager =
+                        activity.getSystemService(KEYGUARD_SERVICE) as KeyguardManager
+                    keyguardManager.requestDismissKeyguard(activity, null)
+                    activity.setShowWhenLocked(true)
+                    activity.setTurnScreenOn(true)
+                    activity.window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
+                } else {
+                    @Suppress("DEPRECATION")
+                    activity.window.addFlags(
+                        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+                                or WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
+                                or WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+                                or WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                    )
+                }
             }
+
             override fun onActivityDestroyed(activity: Activity) {}
             override fun onActivitySaveInstanceState(activity: Activity, bundle: Bundle) {}
             override fun onActivityStarted(activity: Activity) {}
diff --git a/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt b/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
index 6b6ca2e..d71d75b 100644
--- a/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
+++ b/benchmark/common/src/main/java/androidx/benchmark/ResultWriter.kt
@@ -23,6 +23,7 @@
 import androidx.annotation.VisibleForTesting
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
+import java.io.IOException
 
 internal object ResultWriter {
     @VisibleForTesting
@@ -50,7 +51,21 @@
         file.run {
             if (!exists()) {
                 parentFile?.mkdirs()
-                createNewFile()
+                try {
+                    createNewFile()
+                } catch (exception: IOException) {
+                    throw IOException(
+                        """
+                            Failed to create file for benchmark report. Make sure the
+                            instrumentation argument additionalOutputDir is set to a writable
+                            directory on device. If using a version of Android Gradle Plugin that
+                            doesn't support additionalOutputDir, ensure your app's manifest file
+                            enables legacy storage behavior by adding the application attribute:
+                            android:requestLegacyExternalStorage="true"
+                        """.trimIndent(),
+                        exception
+                    )
+                }
             }
 
             val writer = JsonWriter(bufferedWriter())
@@ -91,16 +106,41 @@
     private fun JsonWriter.reportObject(report: BenchmarkState.Report): JsonWriter {
         beginObject()
             .name("name").value(report.testName)
+            .name("params").paramsObject(report)
             .name("className").value(report.className)
             .name("totalRunTimeNs").value(report.totalRunTimeNs)
             .name("metrics").metricsObject(report)
             .name("warmupIterations").value(report.warmupIterations)
             .name("repeatIterations").value(report.repeatIterations)
             .name("thermalThrottleSleepSeconds").value(report.thermalThrottleSleepSeconds)
-
         return endObject()
     }
 
+    private fun JsonWriter.paramsObject(report: BenchmarkState.Report): JsonWriter {
+        beginObject()
+        getParams(report.testName).forEach { name(it.key).value(it.value) }
+        return endObject()
+    }
+
+    private fun getParams(testName: String): Map<String, String> {
+        val parameterStrStart = testName.indexOf('[')
+        val parameterStrEnd = testName.lastIndexOf(']')
+
+        val params = HashMap<String, String>()
+        if (parameterStrStart >= 0 && parameterStrEnd >= 0) {
+            val paramListString = testName.substring(parameterStrStart + 1, parameterStrEnd)
+            paramListString.split(",").forEach { paramString ->
+                val separatorIndex = paramString.indexOfFirst { it == ':' || it == '=' }
+                if (separatorIndex in 1 until paramString.length - 1) {
+                    val key = paramString.substring(0, separatorIndex)
+                    val value = paramString.substring(separatorIndex + 1)
+                    params[key] = value
+                }
+            }
+        }
+        return params
+    }
+
     private fun JsonWriter.metricsObject(report: BenchmarkState.Report): JsonWriter {
         beginObject()
 
diff --git a/biometric/build.gradle b/biometric/build.gradle
index e1dbcfe..e423137 100644
--- a/biometric/build.gradle
+++ b/biometric/build.gradle
@@ -10,7 +10,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.appcompat:appcompat:1.1.0-rc01")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc02")
     api("androidx.fragment:fragment:1.1.0-rc01")
 }
 
diff --git a/browser/build.gradle b/browser/build.gradle
index 5dd3789..06018de 100644
--- a/browser/build.gradle
+++ b/browser/build.gradle
@@ -17,7 +17,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     api("androidx.annotation:annotation:1.1.0")
 
     implementation("androidx.collection:collection:1.1.0")
diff --git a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
index 1102279..810d38b 100644
--- a/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
+++ b/buildSrc/src/main/kotlin/androidx/build/PublishDocsRules.kt
@@ -51,7 +51,7 @@
             .addStubs("car/stubs/android.car.jar")
     prebuilts(LibraryGroups.CARDVIEW, "1.0.0")
     prebuilts(LibraryGroups.COLLECTION, "1.1.0")
-    prebuilts(LibraryGroups.CONCURRENT, "1.0.0-beta01")
+    prebuilts(LibraryGroups.CONCURRENT, "1.0.0-rc01")
     prebuilts(LibraryGroups.CONTENTPAGER, "1.0.0")
     prebuilts(LibraryGroups.COORDINATORLAYOUT, "1.1.0-beta01")
     prebuilts(LibraryGroups.CORE, "core", "1.2.0-alpha02")
@@ -79,11 +79,11 @@
     ignore(LibraryGroups.LOADER.group, "loader-ktx")
     prebuilts(LibraryGroups.LOADER, "1.1.0-rc01")
     prebuilts(LibraryGroups.LOCALBROADCASTMANAGER, "1.1.0-alpha01")
-    prebuilts(LibraryGroups.MEDIA, "media", "1.1.0")
+    prebuilts(LibraryGroups.MEDIA, "media", "1.1.0-rc01")
     ignore(LibraryGroups.MEDIA2.group, "media2-exoplayer")
     prebuilts(LibraryGroups.MEDIA2, "media2-widget", "1.0.0-beta01")
     prebuilts(LibraryGroups.MEDIA2, "1.0.0-rc01")
-    prebuilts(LibraryGroups.MEDIAROUTER, "1.1.0")
+    prebuilts(LibraryGroups.MEDIAROUTER, "1.1.0-rc01")
     ignore(LibraryGroups.NAVIGATION.group, "navigation-testing")
     ignore(LibraryGroups.NAVIGATION.group, "navigation-safe-args-generator")
     ignore(LibraryGroups.NAVIGATION.group, "navigation-safe-args-gradle-plugin")
diff --git a/camera/camera-camera2/build.gradle b/camera/camera-camera2/build.gradle
index b13de44..2a15464 100644
--- a/camera/camera-camera2/build.gradle
+++ b/camera/camera-camera2/build.gradle
@@ -27,7 +27,7 @@
 dependencies {
     api(project(":camera:camera-core"))
 
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation("androidx.annotation:annotation:1.0.0")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(GUAVA_LISTENABLE_FUTURE)
diff --git a/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java b/camera/camera-camera2/src/androidTest/java/androidx/camera/camera2/ImageAnalysisTest.java
index b552085..67292a2 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
@@ -84,8 +84,9 @@
     @Rule
     public GrantPermissionRule mRuntimePermissionRule = GrantPermissionRule.grant(
             Manifest.permission.CAMERA);
+
     @Before
-    public void setUp()  {
+    public void setUp() {
         assumeTrue(CameraUtil.deviceHasCamera());
         mAnalysisResults = new HashSet<>();
         mAnalysisResultsSemaphore = new Semaphore(/*permits=*/ 0);
@@ -168,11 +169,23 @@
     }
 
     @Test
-    public void analyzerAnalyzesImages_whenCameraIsOpen()
+    public void analyzesImages_withAcquireLatest_whenCameraIsOpen()
+            throws InterruptedException, CameraInfoUnavailableException {
+        analyzerAnalyzesImagesWithMode(ImageReaderMode.ACQUIRE_LATEST_IMAGE);
+    }
+
+    @Test
+    public void analyzesImages_withAcquireNext_whenCameraIsOpen()
+            throws InterruptedException, CameraInfoUnavailableException {
+        analyzerAnalyzesImagesWithMode(ImageReaderMode.ACQUIRE_NEXT_IMAGE);
+    }
+
+    private void analyzerAnalyzesImagesWithMode(ImageReaderMode imageReaderMode)
             throws InterruptedException, CameraInfoUnavailableException {
         final int imageFormat = ImageFormat.YUV_420_888;
         ImageAnalysisConfig config =
-                new ImageAnalysisConfig.Builder().setCallbackHandler(mHandler).build();
+                new ImageAnalysisConfig.Builder().setImageReaderMode(
+                        imageReaderMode).setCallbackHandler(mHandler).build();
         ImageAnalysis useCase = new ImageAnalysis(config);
         Map<String, Size> suggestedResolutionMap = new HashMap<>();
         suggestedResolutionMap.put(mCameraId, DEFAULT_RESOLUTION);
@@ -180,6 +193,8 @@
         CameraUtil.openCameraWithUseCase(mCameraId, mCamera, useCase);
         useCase.setAnalyzer(mAnalyzer);
 
+        mAnalysisResultsSemaphore.tryAcquire(5, TimeUnit.SECONDS);
+
         int sensorRotation = CameraX.getCameraInfo(mCameraId).getSensorRotationDegrees();
         // The frames should have properties which match the configuration.
         for (ImageProperties properties : mAnalysisResults) {
diff --git a/camera/camera-core/build.gradle b/camera/camera-core/build.gradle
index b111e0d..d792fc0 100644
--- a/camera/camera-core/build.gradle
+++ b/camera/camera-core/build.gradle
@@ -29,7 +29,7 @@
     api("androidx.lifecycle:lifecycle-common:2.0.0")
     implementation("androidx.exifinterface:exifinterface:1.0.0")
     implementation("androidx.annotation:annotation:1.0.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(ARCH_LIFECYCLE_LIVEDATA)
 
diff --git a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisNonBlockingCallback.java b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisNonBlockingCallback.java
index dfd5e51..1d226f4 100644
--- a/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisNonBlockingCallback.java
+++ b/camera/camera-core/src/main/java/androidx/camera/core/ImageAnalysisNonBlockingCallback.java
@@ -138,7 +138,7 @@
     }
 
     synchronized void finishImage(ImageProxy imageProxy) {
-        imageProxy.close();
         mFinishedImageTimestamp.set(imageProxy.getTimestamp());
+        imageProxy.close();
     }
 }
diff --git a/camera/camera-testing/build.gradle b/camera/camera-testing/build.gradle
index 2be49b7..396ab3c 100644
--- a/camera/camera-testing/build.gradle
+++ b/camera/camera-testing/build.gradle
@@ -30,7 +30,7 @@
     implementation("androidx.annotation:annotation:1.0.0")
     implementation(GUAVA_LISTENABLE_FUTURE)
     implementation(project(":camera:camera-core"))
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha03")
     implementation(JUNIT)
 }
diff --git a/car/core/api/1.0.0-alpha8.txt b/car/core/api/1.0.0-alpha8.txt
index d3d8be7..bf6878c 100644
--- a/car/core/api/1.0.0-alpha8.txt
+++ b/car/core/api/1.0.0-alpha8.txt
@@ -295,7 +295,7 @@
     method public androidx.car.widget.CarMenuItem.Builder setDisplayBehavior(androidx.car.widget.CarMenuItem.DisplayBehavior);
     method public androidx.car.widget.CarMenuItem.Builder setEnabled(boolean);
     method public androidx.car.widget.CarMenuItem.Builder setIcon(android.graphics.drawable.Drawable);
-    method public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
+    method @Deprecated public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
     method public androidx.car.widget.CarMenuItem.Builder setOnClickListener(androidx.car.widget.CarMenuItem.OnClickListener);
     method public androidx.car.widget.CarMenuItem.Builder setStyle(@StyleRes int);
     method public androidx.car.widget.CarMenuItem.Builder setTitle(CharSequence);
diff --git a/car/core/api/current.txt b/car/core/api/current.txt
index d3d8be7..bf6878c 100644
--- a/car/core/api/current.txt
+++ b/car/core/api/current.txt
@@ -295,7 +295,7 @@
     method public androidx.car.widget.CarMenuItem.Builder setDisplayBehavior(androidx.car.widget.CarMenuItem.DisplayBehavior);
     method public androidx.car.widget.CarMenuItem.Builder setEnabled(boolean);
     method public androidx.car.widget.CarMenuItem.Builder setIcon(android.graphics.drawable.Drawable);
-    method public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
+    method @Deprecated public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
     method public androidx.car.widget.CarMenuItem.Builder setOnClickListener(androidx.car.widget.CarMenuItem.OnClickListener);
     method public androidx.car.widget.CarMenuItem.Builder setStyle(@StyleRes int);
     method public androidx.car.widget.CarMenuItem.Builder setTitle(CharSequence);
diff --git a/car/core/api/restricted_1.0.0-alpha8.txt b/car/core/api/restricted_1.0.0-alpha8.txt
index c177433..b4d0539 100644
--- a/car/core/api/restricted_1.0.0-alpha8.txt
+++ b/car/core/api/restricted_1.0.0-alpha8.txt
@@ -318,7 +318,7 @@
     method public androidx.car.widget.CarMenuItem.Builder setDisplayBehavior(androidx.car.widget.CarMenuItem.DisplayBehavior);
     method public androidx.car.widget.CarMenuItem.Builder setEnabled(boolean);
     method public androidx.car.widget.CarMenuItem.Builder setIcon(android.graphics.drawable.Drawable);
-    method public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
+    method @Deprecated public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
     method public androidx.car.widget.CarMenuItem.Builder setOnClickListener(androidx.car.widget.CarMenuItem.OnClickListener);
     method public androidx.car.widget.CarMenuItem.Builder setStyle(@StyleRes int);
     method public androidx.car.widget.CarMenuItem.Builder setTitle(CharSequence);
diff --git a/car/core/api/restricted_current.txt b/car/core/api/restricted_current.txt
index c177433..b4d0539 100644
--- a/car/core/api/restricted_current.txt
+++ b/car/core/api/restricted_current.txt
@@ -318,7 +318,7 @@
     method public androidx.car.widget.CarMenuItem.Builder setDisplayBehavior(androidx.car.widget.CarMenuItem.DisplayBehavior);
     method public androidx.car.widget.CarMenuItem.Builder setEnabled(boolean);
     method public androidx.car.widget.CarMenuItem.Builder setIcon(android.graphics.drawable.Drawable);
-    method public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
+    method @Deprecated public androidx.car.widget.CarMenuItem.Builder setIcon(android.content.Context, @DrawableRes int);
     method public androidx.car.widget.CarMenuItem.Builder setOnClickListener(androidx.car.widget.CarMenuItem.OnClickListener);
     method public androidx.car.widget.CarMenuItem.Builder setStyle(@StyleRes int);
     method public androidx.car.widget.CarMenuItem.Builder setTitle(CharSequence);
diff --git a/car/core/src/androidTest/java/androidx/car/widget/CarToolbarTest.java b/car/core/src/androidTest/java/androidx/car/widget/CarToolbarTest.java
index 2ce3e70..81f524c 100644
--- a/car/core/src/androidTest/java/androidx/car/widget/CarToolbarTest.java
+++ b/car/core/src/androidTest/java/androidx/car/widget/CarToolbarTest.java
@@ -336,7 +336,7 @@
                 .Builder()
                 .setTitle(actionItemText)
                 .setDisplayBehavior(CarMenuItem.DisplayBehavior.ALWAYS) // Action item
-                .setIcon(mActivity, android.R.drawable.sym_def_app_icon)
+                .setIcon(mActivity.getDrawable(android.R.drawable.sym_def_app_icon))
                 .build();
 
         mActivityRule.runOnUiThread(() ->
diff --git a/car/core/src/main/java/androidx/car/widget/CarMenuItem.java b/car/core/src/main/java/androidx/car/widget/CarMenuItem.java
index 42d20b8..400a2e0 100644
--- a/car/core/src/main/java/androidx/car/widget/CarMenuItem.java
+++ b/car/core/src/main/java/androidx/car/widget/CarMenuItem.java
@@ -265,7 +265,10 @@
          * @param context Context to load the drawable resource with.
          * @param iconResId Resource id of icon of the {@code CarMenuItem}.
          * @return This {@code Builder} object to allow call chaining.
+         *
+         * @deprecated Use {@link #setIcon(Drawable)} instead.
          */
+        @Deprecated
         @NonNull
         public Builder setIcon(@NonNull Context context, @DrawableRes int iconResId) {
             mIconDrawable = context.getDrawable(iconResId);
diff --git a/car/moderator/build.gradle b/car/moderator/build.gradle
index bd7370d..4d19dbd 100644
--- a/car/moderator/build.gradle
+++ b/car/moderator/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
index a019068..f5aca24 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxModelCodeGenTests.kt
@@ -27,6 +27,7 @@
 import androidx.compose.composer
 import androidx.compose.runWithCurrent
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.robolectric.Robolectric
@@ -64,6 +65,7 @@
     }
 
     @Test
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testCGModelView_PersonModel(): Unit = ensureSetup {
         val tvNameId = 384
         val tvAgeId = 385
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTypeResolutionTests.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTypeResolutionTests.kt
index 1974f9d..e4bb666 100644
--- a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTypeResolutionTests.kt
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/KtxTypeResolutionTests.kt
@@ -160,10 +160,10 @@
 
 
             @Composable fun test(
-                @Children children: @Composable() () -> Unit,
+                children: @Composable() () -> Unit,
                 value: Int,
                 x: Int,
-                @Children children2: @Composable() () -> Unit,
+                children2: @Composable() () -> Unit,
                 value2: Int
             ) {
                 <LinearLayout>
diff --git a/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/analysis/ChildrenAnnotationTest.kt b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/analysis/ChildrenAnnotationTest.kt
new file mode 100644
index 0000000..dedcd26
--- /dev/null
+++ b/compose/compose-compiler-hosted/integration-tests/src/test/java/androidx/compose/plugins/kotlin/analysis/ChildrenAnnotationTest.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.compose.plugins.kotlin.analysis
+
+import androidx.compose.plugins.kotlin.AbstractComposeDiagnosticsTest
+
+class ChildrenAnnotationTest : AbstractComposeDiagnosticsTest() {
+
+    fun testReportChildrenOnWrongParameter() {
+        doTest("""
+            import androidx.compose.*;
+
+            @Composable fun MyWidget(<!CHILDREN_MUST_BE_LAST!>@Children children: ()->Unit<!>, value: Int) {
+                System.out.println(""+children+value)
+            }
+        """)
+    }
+}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ChildAnnotationChecker.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ChildAnnotationChecker.kt
new file mode 100644
index 0000000..c618a31
--- /dev/null
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ChildAnnotationChecker.kt
@@ -0,0 +1,57 @@
+/*
+ * 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.compose.plugins.kotlin
+
+import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
+import org.jetbrains.kotlin.descriptors.FunctionDescriptor
+import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
+import org.jetbrains.kotlin.psi.KtDeclaration
+import org.jetbrains.kotlin.psi.KtElement
+import androidx.compose.plugins.kotlin.analysis.ComposeErrors
+import org.jetbrains.kotlin.container.StorageComponentContainer
+import org.jetbrains.kotlin.container.useInstance
+import org.jetbrains.kotlin.descriptors.ModuleDescriptor
+import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor
+import org.jetbrains.kotlin.resolve.TargetPlatform
+import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker
+import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext
+import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
+
+open class ChildAnnotationChecker() : DeclarationChecker, StorageComponentContainerContributor {
+    override fun check(
+        declaration: KtDeclaration,
+        descriptor: DeclarationDescriptor,
+        context: DeclarationCheckerContext
+    ) {
+        if(descriptor is FunctionDescriptor) {
+            descriptor.valueParameters.forEachIndexed { index, param ->
+                if(param.hasChildrenAnnotation() && index != descriptor.valueParameters.lastIndex) {
+                    context.trace.report(ComposeErrors.CHILDREN_MUST_BE_LAST.on(param.findPsi() as KtElement))
+                }
+            }
+        }
+    }
+
+    override fun registerModuleComponents(
+        container: StorageComponentContainer,
+        platform: TargetPlatform,
+        moduleDescriptor: ModuleDescriptor
+    ) {
+        if (platform != JvmPlatform) return
+        container.useInstance(this)
+    }
+}
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposePlugin.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposePlugin.kt
index e046b68c..bab14b9 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposePlugin.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ComposePlugin.kt
@@ -111,6 +111,10 @@
             )
             StorageComponentContainerContributor.registerExtension(
                 project,
+                ChildAnnotationChecker()
+            )
+            StorageComponentContainerContributor.registerExtension(
+                project,
                 UnionAnnotationCheckerProvider()
             )
             KtxParsingExtension.registerExtension(project,
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ResolvedKtxElementCall.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ResolvedKtxElementCall.kt
index d5e819f..ed88c3c 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ResolvedKtxElementCall.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/ResolvedKtxElementCall.kt
@@ -238,13 +238,13 @@
         collector: MutableMap<String, MutableList<AttributeMeta>>
     ) {
         callDescriptor?.let {
-            it.valueParameters.forEach { param ->
+            it.valueParameters.forEachIndexed { index, param ->
                 collector.multiPut(
                     AttributeMeta(
                         name = param.name.asString(),
                         type = param.type,
                         descriptor = param,
-                        isChildren = param.hasChildrenAnnotation()
+                        isChildren = param.hasChildrenAnnotation() || it.valueParameters.size-1 == index
                     )
                 )
             }
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeDefaultErrorMessages.kt b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeDefaultErrorMessages.kt
index 68acda7..ced33ab 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeDefaultErrorMessages.kt
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeDefaultErrorMessages.kt
@@ -157,5 +157,10 @@
             "Ambiguous targets. {0}",
             Renderers.AMBIGUOUS_CALLS
         )
+        MAP.put(
+            ComposeErrors.CHILDREN_MUST_BE_LAST,
+            "Children annotation must only occur on last parameter.  This annotation is deprecated (move children to " +
+                    "be last parameter, make it @Composable, and remove the @Children annotation.)."
+        )
     }
 }
\ No newline at end of file
diff --git a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
index 467ab57..a9b2802 100644
--- a/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
+++ b/compose/compose-compiler-hosted/src/main/java/androidx/compose/plugins/kotlin/analysis/ComposeErrors.java
@@ -94,6 +94,8 @@
             MISSING_REQUIRED_CHILDREN = DiagnosticFactory1.create(ERROR);
     DiagnosticFactory2<KtExpression, Collection<KotlinType>, Collection<KotlinType>>
             ILLEGAL_ASSIGN_TO_UNIONTYPE = DiagnosticFactory2.create(ERROR);
+    DiagnosticFactory0<KtElement>
+            CHILDREN_MUST_BE_LAST = DiagnosticFactory0.create(ERROR);
 
     @SuppressWarnings("UnusedDeclaration")
     Object INITIALIZER = new Object() {
diff --git a/compose/compose-runtime/build.gradle b/compose/compose-runtime/build.gradle
index 6f7a33a..52f9ae6 100644
--- a/compose/compose-runtime/build.gradle
+++ b/compose/compose-runtime/build.gradle
@@ -15,6 +15,7 @@
  */
 
 
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
 import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
 
 import static androidx.build.dependencies.DependenciesKt.*
@@ -25,15 +26,30 @@
 plugins {
     id("AndroidXPlugin")
     id("com.android.library")
-    id("kotlin-android")
+    id("kotlin-multiplatform")
 }
 
-dependencies {
-    implementation "androidx.annotation:annotation:1.0.0"
-    implementation(KOTLIN_COMPOSE_STDLIB)
-    implementation(KOTLIN_COMPOSE_REFLECT)
-    testImplementation(JUNIT)
-    testImplementation(ROBOLECTRIC)
+kotlin {
+    android()
+
+    sourceSets {
+        commonMain.dependencies {
+            implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$KOTLIN_VERSION"
+        }
+        commonTest.dependencies {
+            // TODO https://youtrack.jetbrains.com/issue/KT-29343
+            implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$KOTLIN_VERSION"
+            implementation(kotlin("test-annotations-common"))
+        }
+        androidMain.dependencies {
+            implementation "androidx.annotation:annotation:1.0.0"
+            implementation(KOTLIN_COMPOSE_STDLIB)
+            implementation(KOTLIN_COMPOSE_REFLECT)
+        }
+        androidTest.dependencies {
+        }
+
+    }
 }
 
 android {
@@ -51,6 +67,11 @@
             testCoverageEnabled = false
         }
     }
+    sourceSets {
+        main {
+            manifest.srcFile 'src/androidMain/AndroidManifest.xml'
+        }
+    }
 }
 
 androidx {
diff --git a/compose/compose-runtime/compose-runtime-benchmark/build.gradle b/compose/compose-runtime/compose-runtime-benchmark/build.gradle
index dcb32f6..22c1201 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/build.gradle
+++ b/compose/compose-runtime/compose-runtime-benchmark/build.gradle
@@ -30,6 +30,10 @@
 android {
     defaultConfig {
         minSdkVersion 21
+
+        // Work-around for setting the testBuildType to "release" for benchmark projects causes gradle import get
+        // confused.
+        testBuildType = "debug"
     }
     lintOptions {
         disable("SyntheticAccessor")
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
index 4bba238..e48051b 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/AndroidManifest.xml
@@ -18,8 +18,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     package="androidx.compose.benchmark">
-    <!-- Important: disable debuggable for accurate performance results -->
+    <!--
+      ~ Important: disable debuggable for accurate performance results
+      ~ requestLegacyExternalStorage to enable legacy JSON reporting when targeting Q
+      -->
     <application
+        android:requestLegacyExternalStorage="true"
         android:debuggable="false"
         tools:replace="android:debuggable">
         <activity
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
index 8d72e02..29fd820 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/ComposeBenchmarkBase.kt
@@ -37,17 +37,17 @@
     val activityRule = ActivityTestRule(ComposeActivity::class.java)
 
     fun measureCompose(block: @Composable() () -> Unit) {
+        val activity = activityRule.activity
         benchmarkRule.measureRepeated {
-            val activity = activityRule.activity
-
             activity.setContent {
                 block()
             }
 
             runWithTimingDisabled {
-                activity.disposeComposition()
+                activity.setContent { }
             }
         }
+        activity.disposeComposition()
     }
 
     fun measureRecompose(block: RecomposeReceiver.() -> Unit) {
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
index 6525704..da720b8 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/dbmonster/DbMonster.kt
@@ -73,7 +73,7 @@
 }
 
 @Composable
-fun Table(@Children children: @Composable() () -> Unit) {
+fun Table(children: @Composable() () -> Unit) {
     Column { children() }
 }
 
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/deeptree/DeepTree.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/deeptree/DeepTree.kt
index 7712cee..c7667bc 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/deeptree/DeepTree.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/deeptree/DeepTree.kt
@@ -36,7 +36,7 @@
 }
 
 @Composable
-fun Stack(vertical: Boolean, @Children children: @Composable() () -> Unit) {
+fun Stack(vertical: Boolean, children: @Composable() () -> Unit) {
     if (vertical) {
         Column { children() }
     } else {
@@ -45,7 +45,7 @@
 }
 
 @Composable
-fun Container(@Children children: @Composable() () -> Unit) {
+fun Container(children: @Composable() () -> Unit) {
     // non-layout node component. just adds depth to the composition hierarchy.
     children()
 }
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_Widgets.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_Widgets.kt
index 20e1b98..eda5f71 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_Widgets.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/realworld4/RealWorld4_Widgets.kt
@@ -28,7 +28,7 @@
 import androidx.ui.foundation.ColoredRect
 import androidx.ui.core.dp
 import androidx.ui.core.toRect
-import androidx.ui.core.vectorgraphics.SolidColor
+import androidx.ui.graphics.vectorgraphics.SolidColor
 import androidx.ui.painting.Paint
 import androidx.ui.graphics.Color
 import androidx.ui.layout.FlexColumn
diff --git a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/siblings/SiblingManagement.kt b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/siblings/SiblingManagement.kt
index 6b1d4b7..f91235e 100644
--- a/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/siblings/SiblingManagement.kt
+++ b/compose/compose-runtime/compose-runtime-benchmark/src/androidTest/java/androidx/compose/benchmark/siblings/SiblingManagement.kt
@@ -31,7 +31,7 @@
 import kotlin.random.Random
 
 @Composable
-fun Stack(@Children children: @Composable() () -> Unit) {
+fun Stack(children: @Composable() () -> Unit) {
     Column {
         children()
     }
diff --git a/compose/compose-runtime/integration-tests/android-tests/build.gradle b/compose/compose-runtime/integration-tests/android-tests/build.gradle
new file mode 100644
index 0000000..e733507
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/android-tests/build.gradle
@@ -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.
+ */
+
+
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+dependencies {
+    androidTestImplementation(project(":compose:compose-runtime"))
+    androidTestImplementation(project(":compose:compose-runtime:integration-tests"))
+
+    androidTestImplementation(KOTLIN_COMPOSE_STDLIB)
+    androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
+    androidTestImplementation(ANDROIDX_TEST_RULES)
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 18
+    }
+}
diff --git a/compose/compose-runtime/integration-tests/android-tests/src/androidTest/AndroidManifest.xml b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..bb550d8
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest
+        package="androidx.compose.integrationtests.androidtests" xmlns:android="http://schemas.android.com/apk/res/android">
+    <application>
+        <activity
+            android:name="androidx.compose.TestActivity"/>
+        <activity
+            android:name="androidx.compose.ComposeIntoTestActivity"/>
+        <activity
+            android:name="androidx.compose.DisposeTests$DisposeTestActivity"/>
+    </application>
+</manifest>
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ComposeIntoTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeIntoTests.kt
similarity index 68%
rename from compose/compose-runtime/src/test/java/androidx/compose/ComposeIntoTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeIntoTests.kt
index 14d1805..00dc77a 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/ComposeIntoTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeIntoTests.kt
@@ -17,28 +17,32 @@
 package androidx.compose
 
 import android.app.Activity
-import android.os.Bundle
-import junit.framework.TestCase
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import org.junit.Assert.assertEquals
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.robolectric.Robolectric
-import org.robolectric.annotation.Config
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
-class ComposeIntoTests : TestCase() {
+@RunWith(AndroidJUnit4::class)
+class ComposeIntoTests {
+
+    @get:Rule
+    val activityRule = ActivityTestRule(ComposeIntoTestActivity::class.java)
 
     @Test
+    @SmallTest
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testMultipleSetContentCalls() {
-        val controller = Robolectric.buildActivity(ComposeIntoTestActivity::class.java)
-        val activity = controller.create().get() as ComposeIntoTestActivity
+        val activity = activityRule.activity
+        activity.run()
+
         assertEquals(1, activity.initializationCount)
         assertEquals(1, activity.commitCount)
         activity.run()
+
         // if we call setContent multiple times, we want to ensure that it doesn't tear
         // down the whole hierarchy, so onActive should only get called once.
         assertEquals(1, activity.initializationCount)
@@ -46,13 +50,10 @@
     }
 }
 
-private class ComposeIntoTestActivity : Activity() {
+class ComposeIntoTestActivity : Activity() {
     var initializationCount = 0
     var commitCount = 0
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        run()
-    }
+
     fun run() {
         setViewContent {
             +onActive { initializationCount++ }
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ComposeModelTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeModelTests.kt
similarity index 90%
rename from compose/compose-runtime/src/test/java/androidx/compose/ComposeModelTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeModelTests.kt
index ea060c3..cfd4457 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/ComposeModelTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposeModelTests.kt
@@ -17,10 +17,7 @@
 package androidx.compose
 
 import android.app.Activity
-import android.os.Bundle
-import android.view.Choreographer
 import android.view.ViewGroup
-import android.widget.LinearLayout
 import android.widget.TextView
 import androidx.compose.frames.AbstractRecord
 import androidx.compose.frames.Framed
@@ -29,13 +26,16 @@
 import androidx.compose.frames._readable
 import androidx.compose.frames._writable
 import androidx.compose.frames.currentFrame
-import junit.framework.TestCase
-import org.junit.Before
+import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.robolectric.Robolectric
-import org.robolectric.RuntimeEnvironment
-import org.robolectric.annotation.Config
 
 val PRESIDENT_NAME_1 = "George Washington"
 val PRESIDENT_AGE_1 = 57
@@ -120,21 +120,15 @@
     }
 }
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
-class ModelViewTests : TestCase() {
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ModelViewTests {
 
-    @Before
-    fun beforeTest() {
-        val scheduler = RuntimeEnvironment.getMasterScheduler()
-        scheduler.pause()
-    }
+    @get:Rule
+    val activityRule = ActivityTestRule(TestActivity::class.java)
 
     @Test
+    @UiThreadTest
     fun testModelView_Simple(): Unit = FrameManager.isolated {
         val tvId = 67
         compose {
@@ -150,6 +144,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testModelView_Simple_Recompose(): Unit = FrameManager.isolated {
         val tvId = 71
         compose {
@@ -168,6 +163,8 @@
     }
 
     @Test
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
+    @UiThreadTest
     fun testModelView_PersonModel(): Unit = FrameManager.isolated {
         val tvIdName = 90
         val tvIdAge = 91
@@ -204,6 +201,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testModelView_RecomposeScopeCleanup(): Unit = FrameManager.isolated {
         val washington = Person(
             PRESIDENT_NAME_1,
@@ -249,6 +247,7 @@
 
     // b/122548164
     @Test
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testObserverEntering(): Unit = FrameManager.isolated {
         val president = Person(
             PRESIDENT_NAME_1,
@@ -297,6 +296,7 @@
     }
 
     @Test
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testModelUpdatesNextFrameVisibility(): Unit = FrameManager.isolated {
         val president = Person(
             PRESIDENT_NAME_1,
@@ -344,7 +344,7 @@
             president.name = PRESIDENT_NAME_16
             // check that changes aren't there yet
             assertEquals(PRESIDENT_NAME_1, (activity.findViewById(tvName) as TextView).text)
-            Choreographer.getInstance().postFrameCallback {
+            Choreographer.postFrameCallback {
                 // after one frame we should see changes
                 assertEquals(PRESIDENT_NAME_16, (activity.findViewById(tvName) as TextView).text)
             }
@@ -358,15 +358,13 @@
     }
 
     fun compose(block: ViewComposition.() -> Unit) =
-        CompositionModelTest(block)
+        CompositionModelTest(block, activityRule.activity)
 
-    class CompositionModelTest(val composable: ViewComposition.() -> Unit) {
+    class CompositionModelTest(val composable: ViewComposition.() -> Unit, val activity: Activity) {
         var savedContext: CompositionContext? = null
         inner class ActiveTest(val activity: Activity) {
             private var firstCompose = true
             private fun compose() {
-                val scheduler = RuntimeEnvironment.getMasterScheduler()
-                scheduler.advanceToLastPostedRunnable()
                 if (firstCompose) {
                     val composer = composer.composer
                     composer.startRoot()
@@ -392,8 +390,6 @@
         }
 
         fun then(block: (activity: Activity) -> Unit): ActiveTest {
-            val controller = Robolectric.buildActivity(FrameTestActivity::class.java)
-            val activity = controller.create().get()
             val cc = Compose.createCompositionContext(
                 activity,
                 activity.root,
@@ -412,13 +408,3 @@
 }
 
 private val Activity.root get() = findViewById(ComposerComposeTestCase.ROOT_ID) as ViewGroup
-
-private class FrameTestActivity : Activity() {
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        setContentView(LinearLayout(this).apply {
-            id =
-                ComposerComposeTestCase.ROOT_ID
-        })
-    }
-}
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ComposerComposeTestCase.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposerComposeTestCase.kt
similarity index 63%
rename from compose/compose-runtime/src/test/java/androidx/compose/ComposerComposeTestCase.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposerComposeTestCase.kt
index 90dbe54..6339325 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/ComposerComposeTestCase.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposerComposeTestCase.kt
@@ -17,30 +17,19 @@
 package androidx.compose
 
 import android.app.Activity
-import android.os.Bundle
 import android.view.ViewGroup
-import android.widget.LinearLayout
-import junit.framework.TestCase
-import org.junit.runner.RunWith
-import org.robolectric.Robolectric
-import org.robolectric.annotation.Config
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
-abstract class ComposerComposeTestCase : TestCase() {
-    fun compose(composable: (ViewComposition) -> Unit) =
+abstract class ComposerComposeTestCase {
+
+    fun compose(activity: Activity, composable: (ViewComposition) -> Unit) =
         ComposeTest(
-            Root(composable)
+            Root(composable),
+            activity
         )
 
-    class ComposeTest(val component: Component) {
+    class ComposeTest(val component: Component, val activity: Activity) {
+
         fun then(fn: (CompositionContext, Component, ViewGroup, Activity) -> Unit) {
-            val controller = Robolectric.buildActivity(TestActivity::class.java)
-            val activity = controller.create().get()
             val root = activity.findViewById(ROOT_ID) as ViewGroup
             val cc = Compose.createCompositionContext(root.context, root, component, null)
                 cc.compose()
@@ -52,15 +41,6 @@
         override fun compose() = composable(composer)
     }
 
-    private class TestActivity : Activity() {
-        override fun onCreate(savedInstanceState: Bundle?) {
-            super.onCreate(savedInstanceState)
-            setContentView(LinearLayout(this).apply { id =
-                ROOT_ID
-            })
-        }
-    }
-
     companion object {
         val ROOT_ID = 18284847
     }
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ComposerExtensions.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposerExtensions.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/ComposerExtensions.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ComposerExtensions.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/CompositionTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/CompositionTests.kt
similarity index 99%
rename from compose/compose-runtime/src/test/java/androidx/compose/CompositionTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/CompositionTests.kt
index 32fdd69..cd26098 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/CompositionTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/CompositionTests.kt
@@ -43,9 +43,11 @@
 import androidx.compose.mock.text
 import androidx.compose.mock.update
 import androidx.compose.mock.validate
+import androidx.test.filters.SmallTest
 import junit.framework.TestCase
 import org.junit.Assert
 
+@SmallTest
 class CompositionTests : TestCase() {
     fun testComposeAModel() {
         val model = testModel()
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/EffectsTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/EffectsTests.kt
similarity index 94%
rename from compose/compose-runtime/src/test/java/androidx/compose/EffectsTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/EffectsTests.kt
index f3655ef..a8c8971 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/EffectsTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/EffectsTests.kt
@@ -17,38 +17,30 @@
 package androidx.compose
 
 import android.app.Activity
-import android.os.Bundle
 import android.view.ViewGroup
 import android.widget.Button
-import android.widget.LinearLayout
 import android.widget.TextView
-import junit.framework.TestCase
+import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
 import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
+import junit.framework.TestCase.assertTrue
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.robolectric.Robolectric
-import org.robolectric.RuntimeEnvironment
-import org.robolectric.annotation.Config
 
-private class EffectTestActivity : Activity() {
-    override fun onCreate(savedInstanceState: Bundle?) {
-        super.onCreate(savedInstanceState)
-        setContentView(LinearLayout(this).apply {
-            id =
-                ComposerComposeTestCase.ROOT_ID
-        })
-    }
-}
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class EffectsTests {
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
-class EffectsTests : TestCase() {
+    @get:Rule
+    val activityRule = ActivityTestRule(TestActivity::class.java)
 
     @Test
+    @UiThreadTest
     fun testMemoization1() {
         var inc = 0
 
@@ -62,6 +54,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testMemoization2() {
         var calculations = 0
         var compositions = 0
@@ -97,6 +90,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testState1() {
         val tv1Id = 100
         var inc = 0
@@ -127,6 +121,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testState2() {
         val tv1Id = 100
         val tv2Id = 200
@@ -173,6 +168,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit1() {
         var mount = true
 
@@ -233,6 +229,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit2() {
         var mount = true
 
@@ -308,6 +305,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit3() {
         var x = 0
 
@@ -338,6 +336,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit31() {
         var a = 0
         var b = 0
@@ -379,6 +378,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit4() {
         var x = 0
         var key = 123
@@ -421,6 +421,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testPreCommit5() {
         var a = 0
         var b = 0
@@ -484,6 +485,7 @@
     }
 
     @Test
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testOnCommit1() {
         var mount = true
 
@@ -514,10 +516,6 @@
             log("Unmountable:end")
         }
 
-        val scheduler = RuntimeEnvironment.getMasterScheduler()
-
-        scheduler.pause()
-
         compose {
             with(composer) {
                 log("compose:start")
@@ -531,7 +529,6 @@
                 log("compose:end")
             }
         }.then { _ ->
-            scheduler.unPause()
             assertArrayEquals(
                 listOf(
                     "compose:start",
@@ -545,9 +542,7 @@
                 logHistory
             )
             mount = false
-            scheduler.pause()
         }.then { _ ->
-            scheduler.unPause()
             assertArrayEquals(
                 listOf(
                     "compose:start",
@@ -569,6 +564,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testAmbient1() {
         val tv1Id = 100
 
@@ -615,6 +611,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testAmbient2() {
 
         val MyAmbient = Ambient.of<Double>("Hello") { throw Exception("not set") }
@@ -676,6 +673,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testUpdatedComposition() {
         val tv1Id = 100
         var inc = 0
@@ -696,7 +694,8 @@
         }
     }
 
-    class CompositionTest(val composable: () -> Unit) {
+    class CompositionTest(val composable: () -> Unit, val activity: Activity) {
+
         inner class ActiveTest(
             val activity: Activity,
             val cc: CompositionContext,
@@ -717,8 +716,6 @@
         }
 
         fun then(block: (activity: Activity) -> Unit): ActiveTest {
-            val controller = Robolectric.buildActivity(EffectTestActivity::class.java)
-            val activity = controller.create().get()
             val root = activity.root
             val component = Root(composable)
             val cc = Compose.createCompositionContext(root.context, root, component, null)
@@ -726,7 +723,7 @@
         }
     }
 
-    fun compose(composable: () -> Unit) = CompositionTest(composable)
+    fun compose(composable: () -> Unit) = CompositionTest(composable, activityRule.activity)
 }
 
 private val Activity.root get() = findViewById(ComposerComposeTestCase.ROOT_ID) as ViewGroup
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ObserverMapTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ObserverMapTests.kt
similarity index 94%
rename from compose/compose-runtime/src/test/java/androidx/compose/ObserverMapTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ObserverMapTests.kt
index f33e5f4..7c6cf81 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/ObserverMapTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ObserverMapTests.kt
@@ -16,18 +16,12 @@
 
 package androidx.compose
 
+import androidx.test.filters.SmallTest
 import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
-import org.junit.runner.RunWith
-import org.robolectric.annotation.Config
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
+@SmallTest
 class ObserverMapTests {
 
     private val node1 = 1
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/RecomposerTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/RecomposerTests.kt
similarity index 91%
rename from compose/compose-runtime/src/test/java/androidx/compose/RecomposerTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/RecomposerTests.kt
index e03abca..b19ebed 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/RecomposerTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/RecomposerTests.kt
@@ -21,21 +21,33 @@
 import android.widget.LinearLayout
 import android.widget.TextView
 import androidx.compose.frames.currentFrame
+import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
 import junit.framework.TestCase
+import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertFalse
+import junit.framework.TestCase.assertNotSame
+import junit.framework.TestCase.assertTrue
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.robolectric.RuntimeEnvironment
-import org.robolectric.annotation.Config
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
+@RunWith(AndroidJUnit4::class)
 class ComposerCompositionContextTests : ComposerComposeTestCase() {
 
+    @get:Rule
+    val activityRule = ActivityTestRule(TestActivity::class.java)
+
+    private fun compose(composable: (ViewComposition) -> Unit) =
+        compose(activityRule.activity, composable)
+
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testNativeViewWithAttributes() = compose {
         with(it) {
             // <TextView id={456} text="some text" />
@@ -54,6 +66,8 @@
     }
 
     @Test
+    @SmallTest
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testSlotKeyChangeCausesRecreate() {
         var i = 1
 
@@ -91,6 +105,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testViewWithViewChildren() {
         compose {
             // <LinearLayout id={345}>
@@ -129,6 +145,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testForLoop() {
         val items = listOf(1, 2, 3, 4, 5, 6)
         compose {
@@ -161,6 +179,9 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testRecompose() {
         val counter = Counter()
 
@@ -179,10 +200,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            // Robolectric will by default just run everything sync. pause() is needed to emulate
-            // delays
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             (activity.findViewById(100) as TextView).performClick()
             (activity.findViewById(102) as TextView).performClick()
 
@@ -192,24 +209,17 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().unPause()
-
             // only the clicked view got rerendered
             assertEquals(1, counter["A"])
             assertEquals(2, counter["100"])
             assertEquals(1, counter["101"])
             assertEquals(2, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             // recompose() both the parent and the child... and show that the child only
             // recomposes once as a result
             (activity.findViewById(99) as LinearLayout).performClick()
             (activity.findViewById(102) as TextView).performClick()
 
-            RuntimeEnvironment.getMasterScheduler().unPause()
-            RuntimeEnvironment.getMasterScheduler().advanceToLastPostedRunnable()
-
             assertEquals(2, counter["A"])
             assertEquals(2, counter["100"])
             assertEquals(1, counter["101"])
@@ -218,6 +228,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testRecomposeSync() {
         val counter = Counter()
 
@@ -236,9 +248,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            // stop the time so only sync recomposes will take place
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             (activity.findViewById(100) as TextView).performClick()
 
             // only the clicked view got rerendered
@@ -247,15 +256,11 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            // unpause to see if nothing is scheduled during recomposeSync()
-            RuntimeEnvironment.getMasterScheduler().unPause()
-
             assertEquals(1, counter["A"])
             assertEquals(2, counter["100"])
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().pause()
             // try to recompose the parent, but ensure that even if we tap textView several times,
             // it's all got recomposed once
             (activity.findViewById(99) as LinearLayout).performClick()
@@ -269,12 +274,13 @@
             assertEquals(5, counter["100"])
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
-
-            RuntimeEnvironment.getMasterScheduler().unPause()
         }
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
     fun testRootRecompose() {
         val counter = Counter()
 
@@ -300,10 +306,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            // Robolectric will by default just run everything sync. pause() is needed to emulate
-            // delays
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             (activity.findViewById(100) as TextView).performClick()
             (activity.findViewById(102) as TextView).performClick()
 
@@ -313,8 +315,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().unPause()
-
             // as we recompose ROOT on every tap, only root(and LinearLayout) counter should we
             // increased once, because two clicks layed to one frame
             assertEquals(2, counter["A"])
@@ -322,14 +322,9 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             (activity.findViewById(99) as LinearLayout).performClick()
             (activity.findViewById(102) as TextView).performClick()
 
-            RuntimeEnvironment.getMasterScheduler().unPause()
-            RuntimeEnvironment.getMasterScheduler().advanceToLastPostedRunnable()
-
             // again, no matter what we tappes, we want to recompose root, so LinearLayout's counter
             // got increased
             assertEquals(3, counter["A"])
@@ -340,6 +335,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testRootRecomposeSync() {
         val counter = Counter()
 
@@ -364,9 +361,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            // stop the time so only sync recomposes will take place
-            RuntimeEnvironment.getMasterScheduler().pause()
-
             (activity.findViewById(100) as TextView).performClick()
 
             // important! as we recompose Root every time
@@ -383,8 +377,6 @@
             assertEquals(1, counter["101"])
             assertEquals(1, counter["102"])
 
-            RuntimeEnvironment.getMasterScheduler().unPause()
-            RuntimeEnvironment.getMasterScheduler().advanceToLastPostedRunnable()
             // make sure nothing has been scheduled inside recomposeSync()
             assertEquals(3, counter["A"])
             assertEquals(1, counter["100"])
@@ -464,6 +456,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testCorrectViewTree() = compose {
         // <LinearLayout>
         //   <LinearLayout />
@@ -491,6 +485,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testCorrectViewTreeWithComponents() {
 
         class B : Component() {
@@ -540,6 +536,8 @@
     }
 
     @Test
+    @MediumTest
+    @UiThreadTest
     fun testCorrectViewTreeWithComponentWithMultipleRoots() {
 
         class B : Component() {
@@ -592,6 +590,8 @@
     }
 
     @Test
+    @SmallTest
+    @UiThreadTest
     fun testFrameTransition() {
         var frameId: Int? = null
         compose {
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ReconciliationInternalTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ReconciliationInternalTests.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/ReconciliationInternalTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ReconciliationInternalTests.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/SlotTableTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/SlotTableTests.kt
similarity index 99%
rename from compose/compose-runtime/src/test/java/androidx/compose/SlotTableTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/SlotTableTests.kt
index b6bd33c..8d4f8ac 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/SlotTableTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/SlotTableTests.kt
@@ -16,9 +16,11 @@
 
 package androidx.compose
 
+import androidx.test.filters.SmallTest
 import junit.framework.TestCase
 import org.junit.Assert
 
+@SmallTest
 class SlotTableTests : TestCase() {
     fun testCanCreate() {
         SlotTable()
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ViewComposerTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ViewComposerTests.kt
similarity index 92%
rename from compose/compose-runtime/src/test/java/androidx/compose/ViewComposerTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ViewComposerTests.kt
index 9acdbcc..08a097b 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/ViewComposerTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/ViewComposerTests.kt
@@ -24,14 +24,17 @@
 import android.widget.FrameLayout
 import android.widget.LinearLayout
 import android.widget.TextView
-import junit.framework.TestCase
+import androidx.test.annotation.UiThreadTest
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.rule.ActivityTestRule
+import junit.framework.TestCase.assertEquals
+import org.junit.Ignore
+import org.junit.Rule
 import org.junit.runner.RunWith
 import org.junit.Test
-import org.robolectric.Robolectric
-import org.robolectric.RuntimeEnvironment
-import org.robolectric.annotation.Config
 
-private class TestActivity : Activity() {
+class TestActivity : Activity() {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
         setContentView(LinearLayout(this).apply {
@@ -41,15 +44,15 @@
     }
 }
 
-@RunWith(ComposeRobolectricTestRunner::class)
-@Config(
-    manifest = Config.NONE,
-    minSdk = 23,
-    maxSdk = 23
-)
-class NewCodeGenTests : TestCase() {
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class NewCodeGenTests {
+
+    @get:Rule
+    val activityRule = ActivityTestRule(TestActivity::class.java)
 
     @Test
+    @UiThreadTest
     fun testStaticComposition() {
         val tv1Id = 100
         val tv2Id = 200
@@ -81,6 +84,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testUpdatedComposition() {
         val tv1Id = 100
         val tv2Id = 200
@@ -119,56 +123,7 @@
     }
 
     @Test
-    fun testDisposeComposition() {
-        class DisposeTestActivity : Activity() {
-            override fun onCreate(savedInstanceState: Bundle?) {
-                super.onCreate(savedInstanceState)
-                val root = FrameLayout(this)
-                val log = mutableListOf<String>()
-                val composable = @Composable {
-                    +onPreCommit {
-                        log.add("onPreCommit")
-                        onDispose {
-                            log.add("onPreCommitDispose")
-                        }
-                    }
-                    +onActive {
-                        log.add("onActive")
-                        onDispose {
-                            log.add("onActiveDispose")
-                        }
-                    }
-                }
-
-                val scheduler = RuntimeEnvironment.getMasterScheduler()
-
-                log.clear()
-                Compose.composeInto(container = root, composable = composable)
-                scheduler.advanceToLastPostedRunnable()
-                assertEquals("onPreCommit, onActive", log.joinToString())
-
-                log.clear()
-                Compose.composeInto(container = root, composable = composable)
-                scheduler.advanceToLastPostedRunnable()
-                assertEquals("onPreCommitDispose, onPreCommit", log.joinToString())
-
-                log.clear()
-                Compose.disposeComposition(container = root)
-                scheduler.advanceToLastPostedRunnable()
-                assertEquals("onActiveDispose, onPreCommitDispose", log.joinToString())
-
-                log.clear()
-                Compose.composeInto(container = root, composable = composable)
-                scheduler.advanceToLastPostedRunnable()
-                assertEquals("onPreCommit, onActive", log.joinToString())
-            }
-        }
-
-        val controller = Robolectric.buildActivity(DisposeTestActivity::class.java)
-        controller.create()
-    }
-
-    @Test
+    @UiThreadTest
     fun testSingleView() {
         val tvId = 237
         var text = "Hello world"
@@ -190,6 +145,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testViewGroup() {
         val tvId = 258
         val llId = 260
@@ -223,6 +179,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testComposableFunctionInvocationOneParameter() {
         data class Phone(val area: String, val prefix: String, val number: String)
 
@@ -262,6 +219,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testComposableFunctionInvocationTwoParameters() {
         val tvId = 279
         var left = 0
@@ -317,6 +275,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testStatelessComposableClassInvocationProperties() {
         val tvId = 338
         var addCalled = 0
@@ -381,6 +340,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testStatelessComposableClassInvocationParameters() {
         val tvId = 338
         var addCalled = 0
@@ -439,6 +399,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testStatefulComposableClassInvocation() {
         val tvId = 470
         val tvPrivateValue = 471
@@ -527,6 +488,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testStatefulComposableClassWithCtorParametersInvocation() {
         val tvId = 604
         val tvOffsetId = 605
@@ -598,6 +560,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testStatefulComposableClassWithPivotalProperty() {
         val tvId = 604
         val tvOffsetId = 605
@@ -668,6 +631,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testMoveComponents() {
         val data = mutableListOf(1, 2, 3, 4, 5)
         compose {
@@ -688,6 +652,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testViewClassWithCtorParametersInvocation() {
         val tvId = 749
 
@@ -715,6 +680,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testViewClassWithMutableCtorParameter() {
         val tvId = 749
 
@@ -743,6 +709,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testEmittingAnEmittable() {
 
         class MyEmittable : MockEmittable() {
@@ -772,6 +739,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testCGEmittingAnEmittable() {
 
         class MyEmittable : MockEmittable() {
@@ -814,6 +782,7 @@
     }
 
     @Test
+    @UiThreadTest
     fun testCGEmittableAsRoot() {
         class MyEmittable : MockEmittable() {
             var message: String = ""
@@ -898,9 +867,9 @@
     }
 
     fun compose(block: ViewComposition.() -> Unit) =
-        CompositionTest(block)
+        CompositionTest(activityRule.activity, block)
 
-    class CompositionTest(val composable: ViewComposition.() -> Unit) {
+    class CompositionTest(val activity: Activity, val composable: ViewComposition.() -> Unit) {
 
         inner class ActiveTest(val composition: ViewComposition, val activity: Activity) {
             private fun compose() {
@@ -918,8 +887,6 @@
         }
 
         fun then(block: (activity: Activity) -> Unit): ActiveTest {
-            val controller = Robolectric.buildActivity(TestActivity::class.java)
-            val activity = controller.create().get()
             val composition = ViewComposition(
                 ViewComposer(activity.root, activity, object : Recomposer() {
                     override fun scheduleChangesDispatch() {}
@@ -953,13 +920,16 @@
     }
 
     fun composeCG(block: TestContext.(activity: Activity) -> Unit) =
-        CompositionCodeGenTest(block)
+        CompositionCodeGenTest(activityRule.activity, block)
 
     private class Root : Component() {
         override fun compose() {}
     }
 
-    class CompositionCodeGenTest(val composable: TestContext.(activity: Activity) -> Unit) {
+    class CompositionCodeGenTest(
+        val activity: Activity,
+        val composable: TestContext.(activity: Activity) -> Unit
+    ) {
         inner class ActiveTest(
             val activity: Activity,
             val context: TestContext,
@@ -980,8 +950,6 @@
         }
 
         fun then(block: TestContext.(activity: Activity) -> Unit): ActiveTest {
-            val controller = Robolectric.buildActivity(TestActivity::class.java)
-            val activity = controller.create().get()
             val root = activity.root
             val component = Root()
             val cc = Compose.createCompositionContext(root.context, root, component, null)
@@ -990,4 +958,56 @@
     }
 }
 
+@RunWith(AndroidJUnit4::class)
+class DisposeTests {
+
+    @get:Rule
+    val disposeActivityRule = ActivityTestRule(DisposeTestActivity::class.java)
+
+    class DisposeTestActivity : Activity() {
+        override fun onCreate(savedInstanceState: Bundle?) {
+            super.onCreate(savedInstanceState)
+            val root = FrameLayout(this)
+            val log = mutableListOf<String>()
+            val composable = @Composable {
+                +onPreCommit {
+                    log.add("onPreCommit")
+                    onDispose {
+                        log.add("onPreCommitDispose")
+                    }
+                }
+                +onActive {
+                    log.add("onActive")
+                    onDispose {
+                        log.add("onActiveDispose")
+                    }
+                }
+            }
+
+            log.clear()
+            Compose.composeInto(container = root, composable = composable)
+            assertEquals("onPreCommit, onActive", log.joinToString())
+
+            log.clear()
+            Compose.composeInto(container = root, composable = composable)
+            assertEquals("onPreCommitDispose, onPreCommit", log.joinToString())
+
+            log.clear()
+            Compose.disposeComposition(container = root)
+            assertEquals("onActiveDispose, onPreCommitDispose", log.joinToString())
+
+            log.clear()
+            Compose.composeInto(container = root, composable = composable)
+            assertEquals("onPreCommit, onActive", log.joinToString())
+        }
+    }
+
+    @Test
+    @SmallTest
+    @Ignore("TODO(b/138720405): Investigate synchronisation issues in tests")
+    fun testDisposeComposition() {
+        disposeActivityRule.activity
+    }
+}
+
 private val Activity.root get() = findViewById(ComposerComposeTestCase.ROOT_ID) as ViewGroup
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/frames/FramesTests.kt b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/frames/FramesTests.kt
similarity index 97%
rename from compose/compose-runtime/src/test/java/androidx/compose/frames/FramesTests.kt
rename to compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/frames/FramesTests.kt
index 8c4e3e3..7c2e9c4 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/frames/FramesTests.kt
+++ b/compose/compose-runtime/integration-tests/android-tests/src/androidTest/java/androidx/compose/frames/FramesTests.kt
@@ -1,5 +1,22 @@
+/*
+ * 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.compose.frames
 
+import androidx.test.filters.SmallTest
 import junit.framework.TestCase
 import org.junit.Assert
 import java.util.ArrayDeque
@@ -10,6 +27,7 @@
 const val NEW_STREET = "456 New Street"
 const val NEW_CITY = "AnyCity"
 
+@SmallTest
 class FrameTest : TestCase() {
 
     fun testCreatingAddress() {
@@ -134,7 +152,7 @@
         }
         speculate()
         address.street = NEW_STREET
-        val speculation = androidx.compose.frames.suspend()
+        val speculation = suspend()
         frame {
             Assert.assertEquals(OLD_STREET, address.street)
         }
@@ -1075,7 +1093,7 @@
     open(false)
     try {
         block()
-        return androidx.compose.frames.suspend()
+        return suspend()
     } catch (e: Exception) {
         abortHandler()
         throw e
diff --git a/compose/compose-runtime/integration-tests/android-tests/src/main/AndroidManifest.xml b/compose/compose-runtime/integration-tests/android-tests/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..50d6c6b3
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/android-tests/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest
+        package="androidx.compose.integrationtests.androidtests" xmlns:android="http://schemas.android.com/apk/res/android">
+    <application/>
+</manifest>
diff --git a/compose/compose-runtime/integration-tests/build.gradle b/compose/compose-runtime/integration-tests/build.gradle
new file mode 100644
index 0000000..122416d
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/build.gradle
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+
+import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("kotlin-android")
+}
+
+dependencies {
+    implementation(project(":compose:compose-runtime"))
+    implementation(KOTLIN_COMPOSE_STDLIB)
+
+    implementation(JUNIT)
+}
+
+android {
+    defaultConfig {
+        minSdkVersion 18
+    }
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/integration-tests/src/main/AndroidManifest.xml b/compose/compose-runtime/integration-tests/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..50d6c6b3
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/src/main/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest
+        package="androidx.compose.integrationtests.androidtests" xmlns:android="http://schemas.android.com/apk/res/android">
+    <application/>
+</manifest>
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/frames/Address.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/frames/Address.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/frames/Address.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/frames/Address.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeContact.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeContact.kt
similarity index 75%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeContact.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeContact.kt
index f53c431..7409e90 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeContact.kt
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeContact.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.compose.mock
 
 // <linear>
diff --git a/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposePoints.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposePoints.kt
new file mode 100644
index 0000000..8a62094
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposePoints.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.compose.mock
+
+fun MockViewComposition.point(point: Point) {
+    text("X: ${point.x} Y: ${point.y}")
+}
+
+fun MockViewValidator.point(point: Point) {
+    text("X: ${point.x} Y: ${point.y}")
+}
+
+object SLPoints
+
+fun MockViewComposition.points(points: Iterable<Point>) {
+    repeat(of = points) {
+        memoize(SLPoints, it) { point(it) }
+    }
+}
+
+fun MockViewValidator.points(points: Iterable<Point>) {
+    repeat(of = points) {
+        point(it)
+    }
+}
diff --git a/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeReport.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeReport.kt
new file mode 100644
index 0000000..cf50387
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ComposeReport.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.compose.mock
+
+fun MockViewComposition.reportsTo(report: Report) {
+    text(report.from)
+    text("reports to")
+    text(report.to)
+}
+fun MockViewValidator.reportsTo(report: Report) {
+    text(report.from)
+    text("reports to")
+    text(report.to)
+}
+
+fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
+    linear {
+        repeat(of = reports) { report ->
+            reportsTo(report)
+        }
+    }
+}
+
+fun MockViewValidator.reportsReport(reports: Iterable<Report>) {
+    linear {
+        repeat(of = reports) { report ->
+            reportsTo(report)
+        }
+    }
+}
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/Contact.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Contact.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/Contact.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Contact.kt
diff --git a/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ContactModel.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ContactModel.kt
new file mode 100644
index 0000000..622cb0d
--- /dev/null
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ContactModel.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.compose.mock
+
+class ContactModel(
+    var filter: String = "",
+    val contacts: MutableList<Contact>,
+    var selected: Contact? = null
+) {
+    val filtered get() = contacts.filter { it.name.contains(filter) }
+
+    fun add(contact: Contact, after: Contact? = null) {
+        if (after == null) {
+            contacts.add(contact)
+        } else {
+            contacts.add(find(after) + 1, contact)
+        }
+    }
+
+    fun move(contact: Contact, after: Contact?) {
+        if (after == null) {
+            contacts.removeAt(find(contact))
+            contacts.add(0, contact)
+        } else {
+            contacts.removeAt(find(contact))
+            contacts.add(find(after) + 1, contact)
+        }
+    }
+
+    private fun find(contact: Contact): Int {
+        val index = contacts.indexOf(contact)
+        if (index < 0) error("Contact $contact not found")
+        return index
+    }
+}
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/MockViewValidator.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/MockViewValidator.kt
similarity index 77%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/MockViewValidator.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/MockViewValidator.kt
index 5e12eb8..6d3377d 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/MockViewValidator.kt
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/MockViewValidator.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.compose.mock
 
 import org.junit.Assert
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/Point.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Point.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/Point.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Point.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/Report.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Report.kt
similarity index 100%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/Report.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Report.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/View.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/View.kt
similarity index 74%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/View.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/View.kt
index ae356bc..fd36381 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/View.kt
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/View.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.compose.mock
 
 fun indent(indent: Int) {
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/ViewComposer.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ViewComposer.kt
similarity index 90%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/ViewComposer.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ViewComposer.kt
index 6381542..e60ef68 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/ViewComposer.kt
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/ViewComposer.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.compose.mock
 
 import androidx.compose.Applier
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/Views.kt b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Views.kt
similarity index 68%
rename from compose/compose-runtime/src/test/java/androidx/compose/mock/Views.kt
rename to compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Views.kt
index 6e21d32..f86c36f 100644
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/Views.kt
+++ b/compose/compose-runtime/integration-tests/src/main/java/androidx/compose/mock/Views.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.compose.mock
 
 class SourceLocation(val name: String) {
diff --git a/compose/compose-runtime/src/main/AndroidManifest.xml b/compose/compose-runtime/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from compose/compose-runtime/src/main/AndroidManifest.xml
rename to compose/compose-runtime/src/androidMain/AndroidManifest.xml
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualAndroid.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualAndroid.kt
new file mode 100644
index 0000000..60234d1
--- /dev/null
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualAndroid.kt
@@ -0,0 +1,82 @@
+/*
+ * 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.compose
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual typealias ViewParent = android.view.ViewParent
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual typealias View = android.view.View
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual val View.parent: ViewParent
+    get() = parent
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual val View.context: Context
+    get() = context
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual typealias ViewGroup = android.view.ViewGroup
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual typealias Context = android.content.Context
+
+// TODO(b/137794549): Remove View System-related expect/actuals
+actual typealias FrameLayout = android.widget.FrameLayout
+
+// TODO(b/137794558): Create portable abstraction for scheduling
+actual typealias Looper = android.os.Looper
+
+// TODO(b/137794558): Create portable abstraction for scheduling
+actual object LooperWrapper {
+    actual fun getMainLooper(): Looper = android.os.Looper.getMainLooper()
+}
+
+actual fun isMainThread(): Boolean {
+    return android.os.Looper.myLooper() == android.os.Looper.getMainLooper()
+}
+
+// TODO(b/137794558): Create portable abstraction for scheduling
+actual class Handler {
+    val handler: android.os.Handler
+
+    actual constructor(looper: Looper) {
+        handler = android.os.Handler(looper)
+    }
+    actual fun postAtFrontOfQueue(block: () -> Unit): Boolean {
+        return handler.postAtFrontOfQueue { block() }
+    }
+}
+
+// TODO(b/137794558): Create portable abstraction for scheduling
+actual object Choreographer {
+    actual fun postFrameCallback(callback: (Long) -> Unit) {
+        android.view.Choreographer.getInstance().postFrameCallback(callback)
+    }
+    actual fun postFrameCallbackDelayed(delayMillis: Long, callback: (Long) -> Unit) {
+        android.view.Choreographer.getInstance().postFrameCallbackDelayed(callback, delayMillis)
+    }
+    actual fun removeFrameCallback(callback: (Long) -> Unit) {
+        android.view.Choreographer.getInstance().removeFrameCallback(callback)
+    }
+}
+
+actual object Trace {
+    actual fun beginSection(name: String) = android.os.Trace.beginSection(name)
+    actual fun endSection() = android.os.Trace.endSection()
+}
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualJvm.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualJvm.kt
new file mode 100644
index 0000000..7762a4c
--- /dev/null
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ActualJvm.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.compose
+
+actual typealias BitSet = java.util.BitSet
+
+actual open class ThreadLocal<T> actual constructor() : java.lang.ThreadLocal<T>() {
+    actual override fun get(): T? {
+        return super.get()
+    }
+
+    actual override fun set(value: T?) {
+        super.set(value)
+    }
+
+    actual override fun initialValue(): T? {
+        return super.initialValue()
+    }
+}
+
+actual typealias WeakHashMap<K, V> = java.util.WeakHashMap<K, V>
+
+internal actual fun arraycopy(source: Any, sourcePos: Int, dest: Any, destPos: Int, len: Int) =
+    System.arraycopy(source, sourcePos, dest, destPos, len)
+
+actual fun identityHashCode(instance: Any?): Int = System.identityHashCode(instance)
+
+actual inline fun <R> synchronized(lock: Any, block: () -> R): R {
+    kotlin.synchronized(lock) {
+        return block()
+    }
+}
+
+actual typealias WeakReference<T> = java.lang.ref.WeakReference<T>
+
+actual typealias MainThread = androidx.annotation.MainThread
+
+actual typealias TestOnly = org.jetbrains.annotations.TestOnly
+
+actual typealias CheckResult = androidx.annotation.CheckResult
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ComposeAndroid.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ComposeAndroid.kt
new file mode 100644
index 0000000..3e0763a
--- /dev/null
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ComposeAndroid.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.compose
+
+import android.app.Activity
+
+/**
+ * Sets the contentView of an activity to a FrameLayout, and composes the contents of the layout
+ * with the passed in [composable]. This is a convenience method around [Compose.composeInto].
+ *
+ * @see Compose.composeInto
+ * @see Activity.setContentView
+ */
+fun Activity.setViewContent(composable: @Composable() () -> Unit): CompositionContext? {
+    // If there is already a FrameLayout in the root, we assume we want to compose
+    // into it instead of create a new one. This allows for `setContent` to be
+    // called multiple times.
+    val root = window
+        .decorView
+        .findViewById<ViewGroup>(android.R.id.content)
+        .getChildAt(0) as? ViewGroup
+        ?: FrameLayout(this).also { setContentView(it) }
+    return root.setViewContent(composable)
+}
+
+/**
+ * Disposes of a composition that was started using [setContent]. This is a convenience method
+ * around [Compose.disposeComposition].
+ *
+ * @see setContent
+ * @see Compose.disposeComposition
+ */
+fun Activity.disposeComposition() {
+    val view = window
+        .decorView
+        .findViewById<ViewGroup>(android.R.id.content)
+        .getChildAt(0) as? ViewGroup
+        ?: error("No root view found")
+    Compose.disposeComposition(view, null)
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/Recomposer.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/Recomposer.kt
new file mode 100644
index 0000000..6f92528
--- /dev/null
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/Recomposer.kt
@@ -0,0 +1,42 @@
+/*
+ * 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.compose
+
+import android.view.Choreographer
+
+private class AndroidRecomposer : Recomposer() {
+
+    private var frameScheduled = false
+
+    private val frameCallback = Choreographer.FrameCallback {
+        frameScheduled = false
+        dispatchRecomposes()
+    }
+
+    override fun scheduleChangesDispatch() {
+        if (!frameScheduled) {
+            frameScheduled = true
+            Choreographer.getInstance().postFrameCallback(frameCallback)
+        }
+    }
+
+    override fun hasPendingChanges(): Boolean = frameScheduled
+}
+
+internal actual fun createRecomposer(): Recomposer {
+    return AndroidRecomposer()
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/ViewComposer.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
similarity index 97%
rename from compose/compose-runtime/src/main/java/androidx/compose/ViewComposer.kt
rename to compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
index 90ba367..c93eaf0 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/ViewComposer.kt
+++ b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/ViewComposer.kt
@@ -398,7 +398,7 @@
     }
 }
 
-internal val currentComposerNonNull
+internal actual val currentComposerNonNull
     get() = currentComposer ?: emptyComposition()
 
 private fun emptyComposition(): Nothing =
@@ -406,10 +406,10 @@
 
 val composer get() = ViewComposition(currentComposerNonNull as ViewComposer)
 
-internal var currentComposer: Composer<*>? = null
+internal actual var currentComposer: Composer<*>? = null
     private set
 
-fun <T> Composer<*>.runWithCurrent(block: () -> T): T {
+actual fun <T> Composer<*>.runWithCurrent(block: () -> T): T {
     val prev = currentComposer
     try {
         currentComposer = this
@@ -425,14 +425,10 @@
 
 typealias ViewUpdater<T> = ComposerUpdater<Any, T>
 
-@PublishedApi
-internal val invocation = Object()
-
-@PublishedApi
-internal val provider = Object()
-
-@PublishedApi
-internal val consumer = Object()
-
-@PublishedApi
-internal val reference = Object()
+internal actual fun createComposer(
+    root: Any,
+    context: Context,
+    recomposer: Recomposer
+): Composer<*> {
+    return ViewComposer(root, context, recomposer)
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/adapters/ViewAdapter.kt b/compose/compose-runtime/src/androidMain/kotlin/androidx/compose/adapters/ViewAdapter.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/adapters/ViewAdapter.kt
rename to compose/compose-runtime/src/androidMain/kotlin/androidx/compose/adapters/ViewAdapter.kt
diff --git a/compose/compose-runtime/src/androidTest/AndroidManifest.xml b/compose/compose-runtime/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..356bbf4
--- /dev/null
+++ b/compose/compose-runtime/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest package="androidx.ui.material" xmlns:android="http://schemas.android.com/apk/res/android">
+     <application/>
+
+</manifest>
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Ambient.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
similarity index 97%
rename from compose/compose-runtime/src/main/java/androidx/compose/Ambient.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
index 806b474f..4b74acb 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Ambient.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Ambient.kt
@@ -87,7 +87,7 @@
          *  will be thrown. This factory will not be executed more than once.
          */
         inline fun <reified T> of(
-            key: String = T::class.java.simpleName,
+            key: String = T::class.simpleName!!,
             noinline defaultFactory: (() -> T)? = null
         ) = Ambient(key, defaultFactory)
     }
@@ -113,8 +113,7 @@
     @Composable
     fun Provider(
         value: T,
-        @Children
-                children: @Composable() () -> Unit
+        children: @Composable() () -> Unit
     ) {
         with(currentComposerNonNull) {
             val holder = +memo {
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Applier.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Applier.kt
similarity index 99%
rename from compose/compose-runtime/src/main/java/androidx/compose/Applier.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Applier.kt
index f94b0a5..59787e0 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Applier.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Applier.kt
@@ -73,4 +73,4 @@
     fun reset() {
         stack.clear()
     }
-}
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Children.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Children.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Children.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Children.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Component.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Component.kt
similarity index 95%
rename from compose/compose-runtime/src/main/java/androidx/compose/Component.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Component.kt
index 1bc0663..809eb78 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Component.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Component.kt
@@ -55,7 +55,8 @@
 @Suppress("PLUGIN_ERROR")
 abstract class Component {
     @HiddenAttribute
-    internal var recomposeCallback: ((sync: Boolean) -> Unit)? = null
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    var recomposeCallback: ((sync: Boolean) -> Unit)? = null
     private var composing = false
 
     /**
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Composable.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composable.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Composable.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composable.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Compose.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Compose.kt
similarity index 84%
rename from compose/compose-runtime/src/main/java/androidx/compose/Compose.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Compose.kt
index 71a5973..7565647 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Compose.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Compose.kt
@@ -16,15 +16,6 @@
 
 package androidx.compose
 
-import android.app.Activity
-import android.content.Context
-import android.view.View
-import android.view.ViewGroup
-import android.widget.FrameLayout
-import androidx.annotation.MainThread
-import org.jetbrains.annotations.TestOnly
-import java.util.WeakHashMap
-
 // TODO(lmr): consider moving this to the ViewComposer directly
 /**
  * A global namespace to hold some Compose utility methods, such as [Compose.composeInto] and
@@ -53,8 +44,8 @@
         return view.getTag(TAG_ROOT_COMPONENT) as? Component
     }
 
-    // TODO(lmr): used by tests only. consider ways to remove.
-    internal fun findRoot(view: View): Component? {
+    // TODO(b/138254844): Make findRoot/setRoot test-only & Android-only
+    fun findRoot(view: View): Component? {
         var node: View? = view
         while (node != null) {
             val cc = node.getTag(TAG_ROOT_COMPONENT) as? Component
@@ -72,6 +63,7 @@
         return EMITTABLE_ROOT_COMPONENT[emittable]
     }
 
+    // TODO(b/138254844): Make findRoot/setRoot test-only & Android-only
     private fun setRoot(emittable: Emittable, component: Component) {
         EMITTABLE_ROOT_COMPONENT[emittable] = component
     }
@@ -235,41 +227,6 @@
 }
 
 /**
- * Sets the contentView of an activity to a FrameLayout, and composes the contents of the layout
- * with the passed in [composable]. This is a convenience method around [Compose.composeInto].
- *
- * @see Compose.composeInto
- * @see Activity.setContentView
- */
-fun Activity.setViewContent(composable: @Composable() () -> Unit): CompositionContext? {
-    // If there is already a FrameLayout in the root, we assume we want to compose
-    // into it instead of create a new one. This allows for `setContent` to be
-    // called multiple times.
-    val root = window
-        .decorView
-        .findViewById<ViewGroup>(android.R.id.content)
-        .getChildAt(0) as? ViewGroup
-    ?: FrameLayout(this).also { setContentView(it) }
-    return root.setViewContent(composable)
-}
-
-/**
- * Disposes of a composition that was started using [setContent]. This is a convenience method
- * around [Compose.disposeComposition].
- *
- * @see setContent
- * @see Compose.disposeComposition
- */
-fun Activity.disposeComposition() {
-    val view = window
-        .decorView
-        .findViewById<ViewGroup>(android.R.id.content)
-        .getChildAt(0) as? ViewGroup
-        ?: error("No root view found")
-    Compose.disposeComposition(view, null)
-}
-
-/**
  * Composes the children of the view with the passed in [composable]. This is a convenience method
  * around [Compose.composeInto].
  *
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Composer.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
similarity index 98%
rename from compose/compose-runtime/src/main/java/androidx/compose/Composer.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
index f92a9e5..d0f032a 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Composer.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composer.kt
@@ -16,6 +16,8 @@
 
 package androidx.compose
 
+import kotlin.collections.isNotEmpty
+
 internal typealias Change<N> = (
     applier: Applier<N>,
     slots: SlotWriter,
@@ -54,7 +56,7 @@
     var groupIndex: Int = 0
 
     init {
-        assert(startIndex >= 0) { "Invalid start index" }
+        require(startIndex >= 0) { "Invalid start index" }
     }
 
     var nodeCount = parentKeyInfo.nodes
@@ -352,7 +354,7 @@
     }
 
     override fun emitNode(node: N) {
-        assert(inserting) { "emitNode() called when not inserting" }
+        require(inserting) { "emitNode() called when not inserting" }
         val insertIndex = nodeIndexStack.peek()
         // see emitNode
         pending?.let { it.nodeCount++ }
@@ -366,7 +368,7 @@
     }
 
     override fun useNode(): N {
-        assert(!inserting) { "useNode() called while inserting" }
+        require(!inserting) { "useNode() called while inserting" }
         recordDown()
         val result = slots.next()
         childrenAllowed = true
@@ -595,7 +597,7 @@
             invalidateStack.let { if (it.isNotEmpty()) it.peek() else null }
 
     private fun start(key: Any, action: SlotAction) {
-        assert(childrenAllowed) { "A call to createNode(), emitNode() or useNode() expected" }
+        require(childrenAllowed) { "A call to createNode(), emitNode() or useNode() expected" }
 
         // Check for the insert fast path. If we are already inserting (creating nodes) then
         // there is no need to track insert, deletes and moves with a pending changes object.
@@ -883,7 +885,7 @@
         trace("Compose:recordEnters") {
             while (true) {
                 skipToGroupContaining(location)
-                assert(
+                require(
                     slots.isGroup && location >= slots.current &&
                             location < slots.current + slots.groupSize
                 ) {
@@ -1134,14 +1136,14 @@
 
     internal fun finalizeCompose() {
         finalRealizeSlots()
-        assert(pendingStack.isEmpty()) { "Start end imbalance" }
+        require(pendingStack.isEmpty()) { "Start end imbalance" }
         pending = null
         nodeIndex = 0
         groupNodeCount = 0
     }
 
     private fun recordSlotNext(count: Int = 1) {
-        assert(count >= 1) { "Invalid call to recordSlotNext()" }
+        require(count >= 1) { "Invalid call to recordSlotNext()" }
         val actionsSize = slotActions.size
         if (actionsSize > 0) {
             // If the last action was also a skip just add this one to the last one
@@ -1194,7 +1196,7 @@
 
     private fun recordRemoveNode(nodeIndex: Int, count: Int) {
         if (count > 0) {
-            assert(nodeIndex >= 0) { "Invalid remove index $nodeIndex" }
+            require(nodeIndex >= 0) { "Invalid remove index $nodeIndex" }
             if (previousRemove == nodeIndex) previousCount += count
             else {
                 realizeMovement()
@@ -1344,13 +1346,13 @@
 
     fun add(action: SlotAction) {
         if (size >= actions.size) {
-            actions = actions.copyOf(Math.max(size, actions.size * 2))
+            actions = actions.copyOf(kotlin.math.max(size, actions.size * 2))
         }
         actions[size++] = action
     }
 
     fun remove(count: Int) {
-        assert(count <= size) { "Removing too many actions" }
+        require(count <= size) { "Removing too many actions" }
         size -= count
     }
 
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Composition.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composition.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Composition.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Composition.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/CompositionContext.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionContext.kt
similarity index 95%
rename from compose/compose-runtime/src/main/java/androidx/compose/CompositionContext.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionContext.kt
index 09ce471..0455c6f 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/CompositionContext.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionContext.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose
 
-import android.content.Context
-
 // TODO(lmr): this is really only needed for "composition management", but that could maybe move
 // somewhere else. Consider ways to remove this class. Maybe should merge with FrameManager?
 class CompositionContext private constructor(val component: Component, val composer: Composer<*>) {
@@ -30,7 +28,7 @@
         ) = prepare(
             component,
             compositionReference
-        ) { ViewComposer(root, context, this) }
+        ) { createComposer(root, context, this) }
 
         fun prepare(
             component: Component,
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/CompositionLifecycleObserver.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionLifecycleObserver.kt
similarity index 95%
rename from compose/compose-runtime/src/main/java/androidx/compose/CompositionLifecycleObserver.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionLifecycleObserver.kt
index 934ace9..e5e6907 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/CompositionLifecycleObserver.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionLifecycleObserver.kt
@@ -43,5 +43,5 @@
     override fun equals(other: Any?): Boolean =
         other === instance || other is CompositionLifecycleObserverHolder &&
                 instance === other.instance
-    override fun hashCode(): Int = System.identityHashCode(instance)
-}
+    override fun hashCode(): Int = identityHashCode(instance)
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/CompositionReference.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionReference.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/CompositionReference.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/CompositionReference.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Effects.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
similarity index 95%
rename from compose/compose-runtime/src/main/java/androidx/compose/Effects.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
index c3826a2..c8560cb 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Effects.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Effects.kt
@@ -18,8 +18,6 @@
 
 package androidx.compose
 
-import android.view.Choreographer
-import androidx.annotation.CheckResult
 import androidx.compose.annotations.Hide
 import androidx.compose.frames.AbstractRecord
 import androidx.compose.frames.Framed
@@ -33,7 +31,8 @@
  * This is just a sentinel object that represents the absence of an explicit key being defined. This is necessary because
  * we want `null` to be a valid key, and not the absence of one.
  */
-private val absentKey = object {}
+// TODO delete the explicit type after https://youtrack.jetbrains.com/issue/KT-20996
+private val absentKey: Any = object {}
 
 /**
  * This creates a composite key of any value to be used as the key for the group of an effect
@@ -167,7 +166,7 @@
     private var disposeCallback = emptyDispose
 
     override fun onDispose(callback: () -> Unit) {
-        assert(disposeCallback === emptyDispose) {
+        require(disposeCallback === emptyDispose) {
             "onDispose(...) should only be called once"
         }
         disposeCallback = callback
@@ -185,26 +184,25 @@
 @PublishedApi
 internal class PostCommitScopeImpl(
     internal val onCommit: CommitScope.() -> Unit
-) : CommitScope, CompositionLifecycleObserver, Choreographer.FrameCallback {
+) : CommitScope, CompositionLifecycleObserver {
 
     private var disposeCallback = emptyDispose
     private var hasRun = false
 
     override fun onDispose(callback: () -> Unit) {
-        assert(disposeCallback === emptyDispose) {
+        require(disposeCallback === emptyDispose) {
             "onDispose(...) should only be called once"
         }
         disposeCallback = callback
     }
 
-    override fun doFrame(frameTimeNanos: Long) {
+    private val doFrame: (Long) -> Unit = {
         hasRun = true
         onCommit(this)
     }
 
     override fun onEnter() {
-        // TODO(lmr): we should eventually move this to an expect/actual "scheduler" of some sort
-        Choreographer.getInstance().postFrameCallback(this)
+        Choreographer.postFrameCallback(doFrame)
     }
 
     override fun onLeave() {
@@ -213,7 +211,7 @@
         if (hasRun) {
             disposeCallback()
         } else {
-            Choreographer.getInstance().removeFrameCallback(this)
+            Choreographer.removeFrameCallback(doFrame)
         }
     }
 }
@@ -233,7 +231,7 @@
  * @param v1 The value to use as the key. This will be compared to its previous value using `Object.equals`
  * @param block The block to execute other effects in
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun <T, V1> key(v1: V1, block: Effect<T>.() -> T) =
     Effect(block, v1)
 
@@ -255,7 +253,7 @@
  * @param v2 The second value to use as a key. This will be compared to its previous value using `Object.equals`
  * @param block The block to execute other effects in
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun <T, V1, V2> key(v1: V1, v2: V2, block: Effect<T>.() -> T) =
     Effect(block, joinKey(v1, v2))
 
@@ -274,7 +272,7 @@
  * @param inputs The set of values to be used to create a compound key. This will be compared to its previous value using `Object.equals`
  * @param block The block to execute other effects in
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun <T> key(vararg inputs: Any?, block: Effect<T>.() -> T) =
     Effect(
         block,
@@ -286,7 +284,7 @@
  * @param calculation A function to produce the result
  * @return The result of the calculation, or the cached value from the composition
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T> memo(/* crossinline */ calculation: () -> T) = effectOf<T> {
     context.remember(calculation)
 }
@@ -298,7 +296,7 @@
  * @param calculation A function to produce the result
  * @return The result of the calculation, or the cached value from the composition
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T, /* reified */ V1> memo(
     v1: V1,
     /* crossinline */
@@ -315,7 +313,7 @@
  * @param calculation A function to produce the result
  * @return The result of the calculation, or the cached value from the composition
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T, /* reified */ V1, /* reified */ V2> memo(
     v1: V1,
     v2: V2,
@@ -332,7 +330,7 @@
  * @param calculation A function to produce the result
  * @return The result of the calculation, or the cached value from the composition
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun <T> memo(vararg inputs: Any?, calculation: () -> T) = effectOf<T> {
     context.remember(*inputs) { calculation() }
 }
@@ -351,7 +349,7 @@
  * @see [onPreCommit]
  * @see [onDispose]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onActive(callback: CommitScope.() -> Unit) = effectOf<Unit> {
     context.remember { PostCommitScopeImpl(callback) }
 }
@@ -367,7 +365,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onDispose(callback: () -> Unit) = onActive { onDispose(callback) }
 
 /**
@@ -382,7 +380,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onCommit(callback: CommitScope.() -> Unit) = effectOf<Unit> {
     context.changed(PostCommitScopeImpl(callback))
 }
@@ -400,7 +398,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun </* reified */ V1> onCommit(
     v1: V1,
     /* noinline */
@@ -423,7 +421,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun </* reified */ V1, /* reified */ V2> onCommit(
     v1: V1,
     v2: V2,
@@ -446,7 +444,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onCommit(vararg inputs: Any?, callback: CommitScope.() -> Unit) =
     effectOf<Unit> {
         context.remember(*inputs) { PostCommitScopeImpl(callback) }
@@ -466,7 +464,7 @@
  * @see [onPreCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onPreCommit(callback: CommitScope.() -> Unit) =
     effectOf<Unit> {
         context.changed(PreCommitScopeImpl(callback))
@@ -487,7 +485,7 @@
  * @see [onCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun </* reified */ V1> onPreCommit(
     v1: V1,
     /* noinline */
@@ -512,7 +510,7 @@
  * @see [onCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun </* reified */ V1, /* reified */ V2> onPreCommit(
     v1: V1,
     v2: V2,
@@ -537,7 +535,7 @@
  * @see [onCommit]
  * @see [onActive]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun onPreCommit(vararg inputs: Any?, callback: CommitScope.() -> Unit) =
     effectOf<Unit> {
         context.remember(*inputs) { PreCommitScopeImpl(callback) }
@@ -604,7 +602,7 @@
  * @see [model]
  * @see [modelFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T> state(/* crossinline */ init: () -> T) =
     memo { State(init()) }
 
@@ -625,7 +623,7 @@
  * @see [model]
  * @see [modelFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T, /* reified */ V1> stateFor(v1: V1, /* crossinline */ init: () -> T) =
     memo(v1) { State(init()) }
 
@@ -647,7 +645,7 @@
  * @see [model]
  * @see [modelFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T, /* reified */ V1, /* reified */ V2> stateFor(
     v1: V1,
     v2: V2,
@@ -672,7 +670,7 @@
  * @see [model]
  * @see [modelFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T> stateFor(vararg inputs: Any?, /* crossinline */ init: () -> T) =
     memo(*inputs) { State(init()) }
 
@@ -686,8 +684,9 @@
  * @see [state]
  * @see [stateFor]
  */
+// TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
 @Model
-class State<T> @PublishedApi internal constructor(value: T) : Framed {
+class State<T> /*@PublishedApi internal*/ constructor(value: T) : Framed {
     /* NOTE(lmr): When this module is compiled with IR, we will need to remove the below Framed implementation */
 
     @Suppress("UNCHECKED_CAST")
@@ -784,7 +783,7 @@
  * @see [state]
  * @see [stateFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T> model(/* crossinline */ init: () -> T) = memo { init() }
 
 /**
@@ -802,7 +801,7 @@
  * @see [state]
  * @see [stateFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T, /* reified */ V1> modelFor(v1: V1, /* crossinline */ init: () -> T) =
     memo(v1) { init() }
 
@@ -822,7 +821,7 @@
  * @see [state]
  * @see [stateFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <
         T,
         /* reified */ V1,
@@ -845,7 +844,7 @@
  * @see [state]
  * @see [stateFor]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 /* inline */ fun <T> modelFor(vararg inputs: Any?, /* crossinline */ init: () -> T) =
     memo(*inputs) { init() }
 
@@ -857,7 +856,7 @@
  *
  * @see [Ambient]
  */
-@CheckResult(suggest = "+")
+@CheckResult("+")
 fun <T> ambient(key: Ambient<T>) = effectOf<T> {
     context.consume(key)
 }
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/EffectsDsl.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/EffectsDsl.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/EffectsDsl.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/EffectsDsl.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Emittable.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Emittable.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Emittable.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Emittable.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Expect.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Expect.kt
new file mode 100644
index 0000000..59307db
--- /dev/null
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Expect.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.compose
+
+expect class BitSet() {
+    fun set(bitIndex: Int)
+    fun or(set: BitSet)
+    fun clear(bitIndex: Int)
+    operator fun get(bitIndex: Int): Boolean
+}
+
+expect open class ThreadLocal<T>() {
+    fun get(): T?
+    fun set(value: T?)
+    protected open fun initialValue(): T?
+}
+
+expect class WeakHashMap<K, V>() : MutableMap<K, V>
+
+internal expect fun arraycopy(source: Any, sourcePos: Int, dest: Any, destPos: Int, len: Int)
+
+expect fun identityHashCode(instance: Any?): Int
+
+expect interface ViewParent
+
+expect open class View {
+    fun getTag(key: Int): Any
+    fun setTag(key: Int, tag: Any?)
+}
+expect val View.parent: ViewParent
+expect val View.context: Context
+
+expect abstract class ViewGroup : View {
+    fun removeAllViews()
+}
+
+expect abstract class Context
+
+expect class FrameLayout(context: Context)
+
+expect inline fun <R> synchronized(lock: Any, block: () -> R): R
+
+expect class WeakReference<T>(instance: T) {
+    fun get(): T?
+}
+
+expect class Looper
+
+expect fun isMainThread(): Boolean
+
+expect object LooperWrapper {
+    fun getMainLooper(): Looper
+}
+
+expect class Handler(looper: Looper) {
+    fun postAtFrontOfQueue(block: () -> Unit): Boolean
+}
+
+expect object Choreographer {
+    fun postFrameCallback(callback: (Long) -> Unit)
+    fun postFrameCallbackDelayed(delayMillis: Long, callback: (Long) -> Unit)
+    fun removeFrameCallback(callback: (Long) -> Unit)
+}
+
+@MustBeDocumented
+@Retention(AnnotationRetention.BINARY)
+@Target(
+    AnnotationTarget.FUNCTION,
+    AnnotationTarget.CONSTRUCTOR
+)
+expect annotation class MainThread()
+
+@MustBeDocumented
+@Retention(AnnotationRetention.SOURCE)
+@Target(
+    AnnotationTarget.FUNCTION,
+    AnnotationTarget.CONSTRUCTOR
+)
+expect annotation class TestOnly()
+
+@Target(AnnotationTarget.FUNCTION,
+    AnnotationTarget.PROPERTY_GETTER,
+    AnnotationTarget.PROPERTY_SETTER)
+@Retention(AnnotationRetention.BINARY)
+@MustBeDocumented
+expect annotation class CheckResult(
+    val suggest: String
+)
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/FrameManager.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
similarity index 97%
rename from compose/compose-runtime/src/main/java/androidx/compose/FrameManager.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
index 0937e0f..f5abf9a 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/FrameManager.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/FrameManager.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose
 
-import android.os.Handler
-import android.os.Looper
 import androidx.compose.frames.open
 import androidx.compose.frames.commit
 import androidx.compose.frames.suspend
@@ -40,7 +38,7 @@
     private var invalidations = ObserverMap<Any, RecomposeScope>()
     private var removeCommitObserver: (() -> Unit)? = null
 
-    private val handler by lazy { Handler(Looper.getMainLooper()) }
+    private val handler by lazy { Handler(LooperWrapper.getMainLooper()) }
 
     fun ensureStarted() {
         if (!started) {
@@ -163,4 +161,4 @@
     private inline fun schedule(crossinline block: () -> Unit) {
         handler.postAtFrontOfQueue { block() }
     }
-}
+}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/HiddenAttribute.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/HiddenAttribute.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/HiddenAttribute.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/HiddenAttribute.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Immutable.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Immutable.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Immutable.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Immutable.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/JoinedKey.kt
similarity index 96%
rename from compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/JoinedKey.kt
index 601fbf1..bd37846 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/JoinedKey.kt
@@ -16,6 +16,8 @@
 
 package androidx.compose
 
+import kotlin.jvm.JvmField
+
 internal data class JoinedKey(
     @JvmField val left: Any?,
     @JvmField val right: Any?
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Key.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Key.kt
similarity index 95%
rename from compose/compose-runtime/src/main/java/androidx/compose/Key.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Key.kt
index 00c0414..41e9c56 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Key.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Key.kt
@@ -71,6 +71,6 @@
 @Composable
 @Suppress("PLUGIN_ERROR")
 /* inline */
-fun Key(@Suppress("UNUSED_PARAMETER") @Pivotal key: Any?, @Children children: @Composable() () -> Unit) {
+fun Key(@Suppress("UNUSED_PARAMETER") @Pivotal key: Any?, children: @Composable() () -> Unit) {
     children()
 }
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Model.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Model.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Model.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Observe.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
similarity index 94%
rename from compose/compose-runtime/src/main/java/androidx/compose/Observe.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
index 3a05644..6aa9dcb 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Observe.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Observe.kt
@@ -31,7 +31,7 @@
  */
 @Composable
 @Suppress("PLUGIN_ERROR")
-fun Observe(@Children body: @Composable() () -> Unit) =
+fun Observe(body: @Composable() () -> Unit) =
     currentComposerNonNull.let { composer ->
         trace("Compose:Observe") {
             composer.startGroup(observer)
@@ -42,4 +42,4 @@
         }
     }
 
-private val observer = Object()
\ No newline at end of file
+private val observer = Any()
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/ObserverMap.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ObserverMap.kt
similarity index 97%
rename from compose/compose-runtime/src/main/java/androidx/compose/ObserverMap.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ObserverMap.kt
index 65623e7b..d0e4c36 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/ObserverMap.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ObserverMap.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose
 
-import java.lang.ref.WeakReference
-
 /**
  * A map from a key to a set of values used for keeping the relation between some
  * entities and a models changes of which this entities are observing.
@@ -104,7 +102,7 @@
  */
 private class WeakIdentity<T : Any>(value: T) {
     // Save the hash code of value as it might be reclaimed making value.hashCode inaccessible
-    private val myHc = System.identityHashCode(value)
+    private val myHc = identityHashCode(value)
 
     // Preserve a weak reference to the value to prevent read observers from leaking observed values
     private val weakValue = WeakReference(value)
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Pivotal.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Pivotal.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Pivotal.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Pivotal.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Recompose.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
similarity index 96%
rename from compose/compose-runtime/src/main/java/androidx/compose/Recompose.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
index 421d431..fb57067 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Recompose.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recompose.kt
@@ -59,7 +59,7 @@
  * @see invalidate
  */
 @Composable
-fun Recompose(@Children body: @Composable() (recompose: () -> Unit) -> Unit) {
+fun Recompose(body: @Composable() (recompose: () -> Unit) -> Unit) {
     val composer = currentComposerNonNull
     val recomposer = RecomposeHelper()
     val callback = composer.startJoin(false) {
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Recomposer.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
similarity index 76%
rename from compose/compose-runtime/src/main/java/androidx/compose/Recomposer.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
index 79ed5df..baa8521 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Recomposer.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Recomposer.kt
@@ -16,10 +16,6 @@
 
 package androidx.compose
 
-import android.annotation.SuppressLint
-import android.os.Looper
-import android.view.Choreographer
-
 abstract class Recomposer {
 
     companion object {
@@ -31,17 +27,19 @@
          */
         fun hasPendingChanges() = current().hasPendingChanges()
 
-        @SuppressLint("SyntheticAccessor")
         internal fun current(): Recomposer {
-            assert(Looper.myLooper() == Looper.getMainLooper())
+            require(isMainThread()) {
+                "No Recomposer for this Thread"
+            }
             return threadRecomposer.get() ?: error("No Recomposer for this Thread")
         }
 
         internal fun recompose(component: Component, composer: Composer<*>) =
             current().recompose(component, composer)
 
-        private val threadRecomposer = object : ThreadLocal<Recomposer>() {
-            override fun initialValue(): Recomposer? = AndroidRecomposer()
+        // TODO delete the explicit type after https://youtrack.jetbrains.com/issue/KT-20996
+        private val threadRecomposer: ThreadLocal<Recomposer> = object : ThreadLocal<Recomposer>() {
+            override fun initialValue(): Recomposer? = createRecomposer()
         }
     }
 
@@ -83,7 +81,8 @@
         }
     }
 
-    internal abstract fun hasPendingChanges(): Boolean
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    protected abstract fun hasPendingChanges(): Boolean
 
     internal fun scheduleRecompose(composer: Composer<*>) {
         composers.add(composer)
@@ -104,21 +103,4 @@
     }
 }
 
-private class AndroidRecomposer : Recomposer() {
-
-    private var frameScheduled = false
-
-    private val frameCallback = Choreographer.FrameCallback {
-        frameScheduled = false
-        dispatchRecomposes()
-    }
-
-    override fun scheduleChangesDispatch() {
-        if (!frameScheduled) {
-            frameScheduled = true
-            Choreographer.getInstance().postFrameCallback(frameCallback)
-        }
-    }
-
-    override fun hasPendingChanges(): Boolean = frameScheduled
-}
\ No newline at end of file
+internal expect fun createRecomposer(): Recomposer
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/SlotTable.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/SlotTable.kt
similarity index 90%
rename from compose/compose-runtime/src/main/java/androidx/compose/SlotTable.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/SlotTable.kt
index 4193169..d93deac2 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/SlotTable.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/SlotTable.kt
@@ -172,7 +172,7 @@
         nodeCount = 0
         if (validate) {
             val groupStart = advance().asGroupStart
-            assert(groupStart.kind == kind) { "Group kind changed" }
+            require(groupStart.kind == kind) { "Group kind changed" }
             currentEnd = current + groupStart.slots
         }
     }
@@ -197,16 +197,16 @@
 
     internal fun recordEndGroup(writing: Boolean, inserting: Boolean, uncertain: Boolean): Int {
         var count = nodeCount
-        assert(!startStack.isEmpty()) {
+        require(startStack.isNotEmpty()) {
             "Invalid state. Unbalanced calls to startGroup() and endGroup()"
         }
-        assert(inserting || current == currentEnd) { "Expected to be at the end of a group" }
+        require(inserting || current == currentEnd) { "Expected to be at the end of a group" }
 
         // Update group length
         val startLocation = startStack.pop()
         val groupKind = groupKindStack.pop()
         val effectiveStartLocation = effectiveIndex(startLocation)
-        assert(slots[effectiveStartLocation] === SlotTable.EMPTY ||
+        require(slots[effectiveStartLocation] === SlotTable.EMPTY ||
                 slots[effectiveStartLocation] is GroupStart
         ) {
             "Invalid state. Start location stack doesn't refer to a start location"
@@ -217,7 +217,7 @@
         } else {
             val start = slots[effectiveStartLocation].asGroupStart
             // A node count < 0 means that it was reported as uncertain while reading
-            assert(start.slots == len && (nodeCount == start.nodes || uncertain)) {
+            require(start.slots == len && (nodeCount == start.nodes || uncertain)) {
                 "Invalid endGroup call, expected ${start.slots} slots and ${
                 start.nodes} nodes but received, $len slots and $nodeCount nodes"
             }
@@ -261,7 +261,7 @@
      */
     fun previous() {
         if (emptyCount <= 0) {
-            assert(current > 0) { "Invalid call to previous" }
+            require(current > 0) { "Invalid call to previous" }
             current--
         }
     }
@@ -280,7 +280,7 @@
      * End reporting empty for calls to net() and get().
      */
     fun endEmpty() {
-        assert(emptyCount > 0) { "Unbalanced begin/end empty" }
+        require(emptyCount > 0) { "Unbalanced begin/end empty" }
         emptyCount--
     }
 
@@ -302,7 +302,7 @@
      *  Skip a group. Must be called at the start of a group.
      */
     fun skipGroup(): Int {
-        assert(emptyCount == 0) { "Cannot skip while in an empty region" }
+        require(emptyCount == 0) { "Cannot skip while in an empty region" }
         return advanceToNextGroup()
     }
 
@@ -310,8 +310,8 @@
      * Skip the to the end of the group.
      */
     fun skipEnclosingGroup(): Int {
-        assert(emptyCount == 0) { "Cannot skip the enclosing group while in an empty region" }
-        assert(startStack.isNotEmpty()) { "No enclosing group to skip" }
+        require(emptyCount == 0) { "Cannot skip the enclosing group while in an empty region" }
+        require(startStack.isNotEmpty()) { "No enclosing group to skip" }
         val startLocation = startStack.peek()
         val start = get(startLocation).asGroupStart
         current = currentEnd
@@ -347,7 +347,7 @@
      * Skip the current item
      */
     fun skipItem(): Int {
-        assert(emptyCount == 0) { "Cannot skip an item in an empty region" }
+        require(emptyCount == 0) { "Cannot skip an item in an empty region" }
         return advanceToNextItem()
     }
 
@@ -376,7 +376,10 @@
     }
 
     override fun toString(): String {
-        return "${javaClass.simpleName}(current=$current, size=${slots.size - table.gapLen}, gap=${
+        return "${this::class.simpleName}" +
+                "(current=$current, " +
+                "size=${slots.size - table.gapLen}, " +
+                "gap=${
         if (table.gapLen > 0) "$table.gapStart-${table.gapStart + table.gapLen - 1}" else "none"}${
         if (inEmpty) ", in empty" else ""})"
     }
@@ -420,7 +423,7 @@
      * current to be before the key.
      */
     fun previous() {
-        assert(current > 0) { "Invalid call to previous" }
+        require(current > 0) { "Invalid call to previous" }
         current--
     }
 
@@ -436,7 +439,7 @@
      * Ends inserting.
      */
     fun endInsert() {
-        assert(insertCount > 0) { "Unbalenced begin/end insert" }
+        require(insertCount > 0) { "Unbalenced begin/end insert" }
         insertCount--
     }
 
@@ -458,7 +461,7 @@
      *  Skip a group. Must be called at the start of a group.
      */
     fun skipGroup(): Int {
-        assert(insertCount == 0) { "Cannot skip while inserting" }
+        require(insertCount == 0) { "Cannot skip while inserting" }
         return advanceToNextGroup()
     }
 
@@ -473,7 +476,7 @@
      * a keyed group is expected.
      */
     fun moveItem(offset: Int) {
-        assert(insertCount == 0) { "Cannot move an item while inserting" }
+        require(insertCount == 0) { "Cannot move an item while inserting" }
         val oldCurrent = current
         val oldNodeCount = nodeCount
 
@@ -495,7 +498,7 @@
         val newMoveLocation = moveLocation + moveLen
         current = oldCurrent
         nodeCount = oldNodeCount
-        System.arraycopy(
+        arraycopy(
             slots,
             effectiveIndex(newMoveLocation),
             slots,
@@ -508,14 +511,14 @@
 
         // Remove the now duplicate entries
         val anchorsRemoved = remove(moveLocation + moveLen, moveLen)
-        assert(!anchorsRemoved) { "Unexpectedly removed anchors" }
+        require(!anchorsRemoved) { "Unexpectedly removed anchors" }
     }
 
     /**
      * Remove an item. Must be called at the startGroup of an item.
      */
     fun removeItem(): Boolean {
-        assert(insertCount == 0) { "Cannot remove and item while inserting" }
+        require(insertCount == 0) { "Cannot remove and item while inserting" }
         val oldCurrent = current
         val count = advanceToNextItem()
         val anchorsRemoved = remove(oldCurrent, current - oldCurrent)
@@ -560,7 +563,7 @@
      * Skip the current item
      */
     fun skipItem(): Int {
-        assert(insertCount == 0) { "Cannot skip an item while inserting" }
+        require(insertCount == 0) { "Cannot skip an item while inserting" }
         return advanceToNextItem()
     }
 
@@ -579,10 +582,10 @@
                 if (table.anchors.isNotEmpty()) table.updateAnchors(index)
                 if (index < table.gapStart) {
                     val len = table.gapStart - index
-                    System.arraycopy(slots, index, slots, index + table.gapLen, len)
+                    arraycopy(slots, index, slots, index + table.gapLen, len)
                 } else {
                     val len = index - table.gapStart
-                    System.arraycopy(
+                    arraycopy(
                         slots,
                         table.gapStart + table.gapLen,
                         slots,
@@ -607,8 +610,8 @@
                     val oldCapacity = slots.size
                     val oldSize = slots.size - table.gapLen
                     // Double the size of the array, but at least MIN_GROWTH_SIZE and >= size
-                    val newCapacity = Math.max(
-                        Math.max(oldCapacity * 2, oldSize + size),
+                    val newCapacity = kotlin.math.max(
+                        kotlin.math.max(oldCapacity * 2, oldSize + size),
                         MIN_GROWTH_SIZE
                     )
                     val newSlots = arrayOfNulls<Any?>(newCapacity)
@@ -616,8 +619,8 @@
                     val oldGapEnd = table.gapStart + table.gapLen
                     val newGapEnd = table.gapStart + newGapLen
                     // Copy the old array into the new array
-                    System.arraycopy(slots, 0, newSlots, 0, table.gapStart)
-                    System.arraycopy(slots, oldGapEnd, newSlots, newGapEnd, oldCapacity - oldGapEnd)
+                    arraycopy(slots, 0, newSlots, 0, table.gapStart)
+                    arraycopy(slots, oldGapEnd, newSlots, newGapEnd, oldCapacity - oldGapEnd)
 
                     // Update the anchors
                     if (table.anchors.isNotEmpty()) table.anchorGapResize(newGapLen - table.gapLen)
@@ -638,7 +641,8 @@
         }
     }
 
-    internal fun remove(start: Int, len: Int): Boolean {
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    fun remove(start: Int, len: Int): Boolean {
         return if (len > 0) {
             pendingClear = false
             var anchorsRemoved = false
@@ -667,7 +671,10 @@
             pendingClear = false
             table.clearGap()
         }
-        return "${javaClass.simpleName}(current=$current, size=${slots.size - table.gapLen}, gap=${
+        return "${this::class.simpleName}" +
+                "(current=$current, " +
+                "size=${slots.size - table.gapLen}, " +
+                "gap=${
         if (table.gapLen > 0) "$table.gapStart-${table.gapStart + table.gapLen - 1}" else "none"}${
         if (insertCount > 0) ", inserting" else ""})"
     }
@@ -708,12 +715,12 @@
     }
 
     internal fun close(reader: SlotReader) {
-        assert(reader.table === this && readers > 0) { "Unexpected reader close()" }
+        require(reader.table === this && readers > 0) { "Unexpected reader close()" }
         readers--
     }
 
     internal fun close(writer: SlotWriter) {
-        assert(writer.table === this && this.writer) { "Unexpected writer close()" }
+        require(writer.table === this && this.writer) { "Unexpected writer close()" }
         this.writer = false
         clearGap()
     }
@@ -722,7 +729,8 @@
 
     internal fun clearGap() = repeat(gapLen) { i -> slots[gapStart + i] = null }
 
-    internal fun anchor(index: Int): Anchor {
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    fun anchor(index: Int): Anchor {
         // TODO: Consider a buffer gap list of anchors if middle inserts and deletes are common
         val anchorIndex = effectiveIndex(index)
         val location = anchors.search(anchorIndex)
@@ -819,7 +827,8 @@
         }
     }
 
-    internal fun anchorLocation(anchor: Anchor) = anchor.loc.let {
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    fun anchorLocation(anchor: Anchor) = anchor.loc.let {
         if (it > gapStart) it - gapLen else it
     }
 
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/StableMarker.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/StableMarker.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/StableMarker.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Stack.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Stack.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Stack.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Stack.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Stateful.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Stateful.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/Stateful.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Stateful.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/Trace.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Trace.kt
similarity index 92%
rename from compose/compose-runtime/src/main/java/androidx/compose/Trace.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Trace.kt
index e451296..24e89e2 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/Trace.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/Trace.kt
@@ -16,7 +16,10 @@
 
 package androidx.compose
 
-import android.os.Trace
+expect object Trace {
+    fun beginSection(name: String)
+    fun endSection()
+}
 
 /**
  * Wrap the specified [block] in calls to [Trace.beginSection] (with the supplied [sectionName])
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/UnionType.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/UnionType.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/UnionType.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/UnionType.kt
diff --git a/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ViewComposerCommon.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ViewComposerCommon.kt
new file mode 100644
index 0000000..a6a573c6
--- /dev/null
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/ViewComposerCommon.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose
+
+internal expect val currentComposerNonNull: Composer<*>
+internal expect var currentComposer: Composer<*>?
+
+internal expect fun createComposer(root: Any, context: Context, recomposer: Recomposer): Composer<*>
+expect fun <T> Composer<*>.runWithCurrent(block: () -> T): T
+
+// TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+/*@PublishedApi
+internal*/ val invocation = Any()
+
+@PublishedApi
+internal val provider = Any()
+
+@PublishedApi
+internal val consumer = Any()
+
+@PublishedApi
+internal val reference = Any()
\ No newline at end of file
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/annotations/Hide.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/annotations/Hide.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/annotations/Hide.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/annotations/Hide.kt
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/frames/FrameContainers.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/FrameContainers.kt
similarity index 81%
rename from compose/compose-runtime/src/main/java/androidx/compose/frames/FrameContainers.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/FrameContainers.kt
index 596d8fa0..716b22b 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/frames/FrameContainers.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/FrameContainers.kt
@@ -1,5 +1,23 @@
+/*
+ * 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.compose.frames
 
+import kotlin.jvm.JvmField
+
 class ModelList<T> : MutableList<T>, Framed {
     private var myFirst: Record =
         ArrayContainer<T>()
@@ -12,16 +30,16 @@
 
     @Suppress("UNCHECKED_CAST") private val readable: ArrayContainer<T>
         get() =
-        _readable(
-            myFirst,
-            this
-        ) as ArrayContainer<T>
+            _readable(
+                myFirst,
+                this
+            ) as ArrayContainer<T>
     @Suppress("UNCHECKED_CAST") private val writable: ArrayContainer<T>
         get() =
-        _writable(
-            myFirst,
-            this
-        ) as ArrayContainer<T>
+            _writable(
+                myFirst,
+                this
+            ) as ArrayContainer<T>
 
     fun asMutable(): MutableList<T> = writable.list
 
@@ -53,12 +71,13 @@
         writable.list.subList(fromIndex, toIndex)
 
     private class ArrayContainer<T> : AbstractRecord() {
-        @JvmField var list: ArrayList<T> = arrayListOf<T>()
+        @JvmField
+        var list: ArrayList<T> = arrayListOf<T>()
 
         override fun assign(value: Record) {
             @Suppress("UNCHECKED_CAST")
             (value as? ArrayContainer<T>)?.let {
-                this.list = it.list.clone() as ArrayList<T>
+                this.list = it.list.toList() as ArrayList<T>
             }
         }
 
@@ -145,23 +164,26 @@
     override fun retainAll(elements: Collection<T>): Boolean = error()
 }
 
+// TODO delete the explicit type after https://youtrack.jetbrains.com/issue/KT-20996
 private fun <T> immutableIterator(
     iterator: MutableIterator<T>
-) = object : MutableIterator<T> by iterator {
+): MutableIterator<T> = object : MutableIterator<T> by iterator {
     override fun remove() = error()
 }
 
+// TODO delete the explicit type after https://youtrack.jetbrains.com/issue/KT-20996
 private fun <T> immutableListIterator(
     iterator: MutableListIterator<T>
-) = object : MutableListIterator<T> by iterator {
+): MutableListIterator<T> = object : MutableListIterator<T> by iterator {
     override fun add(element: T) = error()
     override fun remove() = error()
     override fun set(element: T) = error()
 }
 
+// TODO delete the explicit type after https://youtrack.jetbrains.com/issue/KT-20996
 private fun <T> immutableCollection(
     collection: MutableCollection<T>
-) = object : MutableCollection<T> by collection {
+): MutableCollection<T> = object : MutableCollection<T> by collection {
     override fun add(element: T): Boolean = error()
     override fun addAll(elements: Collection<T>): Boolean = error()
     override fun clear() = error()
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/frames/Frames.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/Frames.kt
similarity index 93%
rename from compose/compose-runtime/src/main/java/androidx/compose/frames/Frames.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/Frames.kt
index d70216e..02ead93 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/frames/Frames.kt
+++ b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/frames/Frames.kt
@@ -1,11 +1,48 @@
+/*
+ * 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.compose.frames
 
-import java.util.BitSet
-import java.util.HashSet
+import androidx.compose.BitSet
+import androidx.compose.ThreadLocal
+import androidx.compose.synchronized
 
 class FrameAborted(val frame: Frame) : RuntimeException("Frame aborted")
 
 /**
+ * The frame records are created with frame ID CREATION_FRAME when not in a frame.
+ * This allows framed object to be created in the in static initializers when a
+ * frame could not have been created yet.
+ *
+ * The value 2 was chosen because it must be greater than 0, as 0 is reserved to
+ * indicated an invalid frame (in order to avoid an uninitialized record begin
+ * treated a valid record) and 1 is odd and treated as a speculation frame. That
+ * leaves 2 as the lowest valid frame.
+ */
+private const val CREATION_FRAME = 2
+
+/**
+ * Base implementation of a frame record
+ */
+abstract class AbstractRecord : Record {
+    override var frameId: Int = threadFrame.get()?.id ?: CREATION_FRAME
+    override var next: Record? = null
+}
+
+/**
  * Frame local values of a framed object.
  */
 interface Record {
@@ -30,32 +67,17 @@
     fun create(): Record
 }
 
-/**
- * The frame records are created with frame ID CREATION_FRAME when not in a frame.
- * This allows framed object to be created in the in static initializers when a
- * frame could not have been created yet.
- *
- * The value 2 was chosen because it must be greater than 0, as 0 is reserved to
- * indicated an invalid frame (in order to avoid an uninitialized record begin
- * treated a valid record) and 1 is odd and treated as a speculation frame. That
- * leaves 2 as the lowest valid frame.
- */
-private const val CREATION_FRAME = 2
-
-/**
- * Base implementation of a frame record
- */
-abstract class AbstractRecord : Record {
-    override var frameId: Int = threadFrame.get()?.id ?: CREATION_FRAME
-    override var next: Record? = null
+interface Framed {
+    val firstFrameRecord: Record
+    fun prependFrameRecord(value: Record)
 }
 
-internal val threadFrame = ThreadLocal<Frame>()
-
 typealias FrameReadObserver = (read: Any) -> Unit
 typealias FrameWriteObserver = (write: Any) -> Unit
 typealias FrameCommitObserver = (committed: Set<Any>) -> Unit
 
+private val threadFrame = ThreadLocal<Frame>()
+
 /**
  * Information about a frame including the frame id and whether or not it is read only.
  */
@@ -88,7 +110,8 @@
 ) {
     internal val modified = if (readOnly) null else HashSet<Framed>()
 
-    internal val readObservers = mutableListOf<FrameReadObserver>()
+    // TODO(138720404): Investigate if Compose APIs can be internal despite MPP limitations
+    val readObservers = mutableListOf<FrameReadObserver>()
 
     init {
         if (readObserver != null) {
@@ -129,7 +152,7 @@
 val inFrame: Boolean get() = threadFrame.get() != null
 
 // A global synchronization object
-private val sync = Object()
+private val sync = Any()
 
 // The following variables should only be written when sync is taken
 private val openFrames = BitSet()
@@ -418,11 +441,6 @@
 fun _writable(r: Record, framed: Framed): Record = r.writable(framed)
 fun _created(framed: Framed) = threadFrame.get()?.writeObserver?.let { it(framed) }
 
-interface Framed {
-    val firstFrameRecord: Record
-    fun prependFrameRecord(value: Record)
-}
-
 fun <T : Record> T.writable(framed: Framed): T {
     return this.writable(framed, currentFrame())
 }
@@ -494,8 +512,8 @@
         @Suppress("UNCHECKED_CAST")
         (used(framed, id, frame.invalid) as T?)?.apply { frameId = Int.MAX_VALUE }
             ?: readData.create().apply {
-            frameId = Int.MAX_VALUE; framed.prependFrameRecord(this as T)
-        } as T
+                frameId = Int.MAX_VALUE; framed.prependFrameRecord(this as T)
+            } as T
     }
     newData.assign(readData)
     newData.frameId = id
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/sourceLocation.kt b/compose/compose-runtime/src/commonMain/kotlin/androidx/compose/sourceLocation.kt
similarity index 100%
rename from compose/compose-runtime/src/main/java/androidx/compose/sourceLocation.kt
rename to compose/compose-runtime/src/commonMain/kotlin/androidx/compose/sourceLocation.kt
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/ComposeRobolectricTestRunner.kt b/compose/compose-runtime/src/test/java/androidx/compose/ComposeRobolectricTestRunner.kt
deleted file mode 100644
index ff656ad..0000000
--- a/compose/compose-runtime/src/test/java/androidx/compose/ComposeRobolectricTestRunner.kt
+++ /dev/null
@@ -1,29 +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.compose
-
-import org.junit.runners.model.FrameworkMethod
-import org.robolectric.RobolectricTestRunner
-import org.robolectric.internal.bytecode.InstrumentationConfiguration
-
-class ComposeRobolectricTestRunner(testClass: Class<*>) : RobolectricTestRunner(testClass) {
-    override fun createClassLoaderConfig(method: FrameworkMethod?): InstrumentationConfiguration {
-        val builder = InstrumentationConfiguration.Builder(super.createClassLoaderConfig(method))
-        builder.doNotInstrumentPackage("androidx.compose")
-        return builder.build()
-    }
-}
\ No newline at end of file
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposePoints.kt b/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposePoints.kt
deleted file mode 100644
index 9bf3948..0000000
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposePoints.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package androidx.compose.mock
-
-fun MockViewComposition.point(point: Point) {
-    text("X: ${point.x} Y: ${point.y}")
-}
-
-fun MockViewValidator.point(point: Point) {
-    text("X: ${point.x} Y: ${point.y}")
-}
-
-object SLPoints
-
-fun MockViewComposition.points(points: Iterable<Point>) {
-    repeat(of = points) {
-        memoize(SLPoints, it) { point(it) }
-    }
-}
-
-fun MockViewValidator.points(points: Iterable<Point>) {
-    repeat(of = points) {
-        point(it)
-    }
-}
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeReport.kt b/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeReport.kt
deleted file mode 100644
index 057f9ab..0000000
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/ComposeReport.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package androidx.compose.mock
-
-fun MockViewComposition.reportsTo(report: Report) {
-    text(report.from)
-    text("reports to")
-    text(report.to)
-}
-fun MockViewValidator.reportsTo(report: Report) {
-    text(report.from)
-    text("reports to")
-    text(report.to)
-}
-
-fun MockViewComposition.reportsReport(reports: Iterable<Report>) {
-    linear {
-        repeat(of = reports) { report ->
-            reportsTo(report)
-        }
-    }
-}
-
-fun MockViewValidator.reportsReport(reports: Iterable<Report>) {
-    linear {
-        repeat(of = reports) { report ->
-            reportsTo(report)
-        }
-    }
-}
diff --git a/compose/compose-runtime/src/test/java/androidx/compose/mock/ContactModel.kt b/compose/compose-runtime/src/test/java/androidx/compose/mock/ContactModel.kt
deleted file mode 100644
index 3d16cf7..0000000
--- a/compose/compose-runtime/src/test/java/androidx/compose/mock/ContactModel.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package androidx.compose.mock
-
-class ContactModel(
-    var filter: String = "",
-    val contacts: MutableList<Contact>,
-    var selected: Contact? = null
-) {
-    val filtered get() = contacts.filter { it.name.contains(filter) }
-
-    fun add(contact: Contact, after: Contact? = null) {
-        if (after == null) {
-            contacts.add(contact)
-        } else {
-            contacts.add(find(after) + 1, contact)
-        }
-    }
-
-    fun move(contact: Contact, after: Contact?) {
-        if (after == null) {
-            contacts.removeAt(find(contact))
-            contacts.add(0, contact)
-        } else {
-            contacts.removeAt(find(contact))
-            contacts.add(find(after) + 1, contact)
-        }
-    }
-
-    private fun find(contact: Contact): Int {
-        val index = contacts.indexOf(contact)
-        if (index < 0) error("Contact $contact not found")
-        return index
-    }
-}
diff --git a/content/build.gradle b/content/build.gradle
index 4a27186..cafb452 100644
--- a/content/build.gradle
+++ b/content/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(JUNIT)
diff --git a/coordinatorlayout/build.gradle b/coordinatorlayout/build.gradle
index 6050e84..ae2a733 100644
--- a/coordinatorlayout/build.gradle
+++ b/coordinatorlayout/build.gradle
@@ -11,7 +11,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     // TODO: change to 1.1.0-alpha04 after release
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.customview:customview:1.0.0")
 
diff --git a/dynamic-animation/build.gradle b/dynamic-animation/build.gradle
index 6ad3e31..fe7bd58 100644
--- a/dynamic-animation/build.gradle
+++ b/dynamic-animation/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/emoji/core/build.gradle b/emoji/core/build.gradle
index 4e13514..0b811cb 100644
--- a/emoji/core/build.gradle
+++ b/emoji/core/build.gradle
@@ -22,7 +22,7 @@
     // treats this as local jar and package it inside the aar.
     api files(configurations.repackage)
 
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation(project(':collection:collection'))
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/fragment/fragment/build.gradle b/fragment/fragment/build.gradle
index 777cb59..669429a 100644
--- a/fragment/fragment/build.gradle
+++ b/fragment/fragment/build.gradle
@@ -18,7 +18,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     api("androidx.collection:collection:1.1.0")
     api("androidx.viewpager:viewpager:1.0.0")
     api("androidx.loader:loader:1.0.0")
diff --git a/graphics/drawable/static/build.gradle b/graphics/drawable/static/build.gradle
index f5e1ba4..a3e453a 100644
--- a/graphics/drawable/static/build.gradle
+++ b/graphics/drawable/static/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/gridlayout/build.gradle b/gridlayout/build.gradle
index 58ab795..efb7375 100644
--- a/gridlayout/build.gradle
+++ b/gridlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api(ANDROIDX_ANNOTATION)
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/leanback/build.gradle b/leanback/build.gradle
index df32fcf..7588656 100644
--- a/leanback/build.gradle
+++ b/leanback/build.gradle
@@ -11,7 +11,7 @@
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
     api("androidx.interpolator:interpolator:1.0.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.media:media:1.0.0")
     api("androidx.fragment:fragment:1.0.0")
diff --git a/legacy/core-utils/build.gradle b/legacy/core-utils/build.gradle
index c4fed24..7a331a9 100644
--- a/legacy/core-utils/build.gradle
+++ b/legacy/core-utils/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     api(project(":documentfile"))
     api(project(":loader:loader"))
     api(project(":localbroadcastmanager"))
diff --git a/media/build.gradle b/media/build.gradle
index facba79..913a501 100644
--- a/media/build.gradle
+++ b/media/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/media2/integration-tests/testapp/build.gradle b/media2/integration-tests/testapp/build.gradle
index ffefd37..b269e6a 100644
--- a/media2/integration-tests/testapp/build.gradle
+++ b/media2/integration-tests/testapp/build.gradle
@@ -30,7 +30,7 @@
     implementation(project(":media2:media2-player"))
     implementation(project(":media2:media2-widget"))
     implementation("androidx.appcompat:appcompat:1.0.2")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
 }
 
 android {
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserLegacyTest.java b/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserLegacyTest.java
index 33d62d8..061098b 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserLegacyTest.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserLegacyTest.java
@@ -40,6 +40,7 @@
 import androidx.media2.session.MediaBrowser.BrowserCallback;
 import androidx.media2.session.MediaLibraryService.LibraryParams;
 import androidx.media2.session.MockMediaBrowserServiceCompat.Proxy;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.LargeTest;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -47,6 +48,7 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -57,6 +59,7 @@
 /**
  * Tests {@link MediaBrowser} with {@link MediaBrowserServiceCompat}.
  */
+@RunWith(AndroidJUnit4.class)
 @LargeTest
 public class MediaBrowserLegacyTest extends MediaSessionTestBase {
     private static final String TAG = "MediaBrowserLegacyTest";
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java b/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java
index a063c09..68165d2 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MediaBrowserTest.java
@@ -391,8 +391,7 @@
     }
 
     @Test
-    public void testBrowserCallback_onChildrenChangedIsCalledWhenSubscribed()
-            throws InterruptedException {
+    public void testBrowserCallback_onChildrenChangedIsCalledWhenSubscribed() throws Exception {
         // This test uses MediaLibrarySession.notifyChildrenChanged().
         prepareLooper();
         final String expectedParentId = "expectedParentId";
@@ -434,7 +433,10 @@
 
         TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
         MockMediaLibraryService.setAssertLibraryParams(testParams);
-        createBrowser(controllerCallbackProxy).subscribe(expectedParentId, testParams);
+        LibraryResult result = createBrowser(controllerCallbackProxy)
+                .subscribe(expectedParentId, testParams)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
 
         // onChildrenChanged() should be called.
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -497,8 +499,7 @@
     }
 
     @Test
-    public void testBrowserCallback_onChildrenChangedIsCalledWhenSubscribed2()
-            throws InterruptedException {
+    public void testBrowserCallback_onChildrenChangedIsCalledWhenSubscribed2() throws Exception {
         // This test uses MediaLibrarySession.notifyChildrenChanged(ControllerInfo).
         prepareLooper();
         final String expectedParentId = "expectedParentId";
@@ -540,7 +541,10 @@
         };
 
         TestServiceRegistry.getInstance().setSessionCallback(sessionCallback);
-        createBrowser(controllerCallbackProxy).subscribe(expectedParentId, null);
+        LibraryResult result = createBrowser(controllerCallbackProxy)
+                .subscribe(expectedParentId, null)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
 
         // onChildrenChanged() should be called.
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java b/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
index 57af209..a839548 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MediaControllerTest.java
@@ -24,7 +24,6 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.app.PendingIntent;
 import android.content.Context;
@@ -143,14 +142,11 @@
     }
 
     @Test
-    public void testPlay() {
+    public void testPlay() throws Exception {
         prepareLooper();
-        mController.play();
-        try {
-            assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
+        SessionResult result = mController.play().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
+        assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mPlayCalled);
     }
 
@@ -161,46 +157,39 @@
         final MockPlayer player = new MockPlayer(2);
         player.mLastPlayerState = SessionPlayer.PLAYER_STATE_IDLE;
         mSession.updatePlayer(player);
-        mController.play();
+        SessionResult result = mController.play().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(player.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(player.mPlayCalled);
         assertTrue(player.mPrepareCalled);
     }
 
     @Test
-    public void testPause() {
+    public void testPause() throws Exception {
         prepareLooper();
-        mController.pause();
-        try {
-            assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
+        SessionResult result = mController.pause().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
+        assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mPauseCalled);
     }
 
     @Test
-    public void testPrepare() {
+    public void testPrepare() throws Exception {
         prepareLooper();
-        mController.prepare();
-        try {
-            assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
+        SessionResult result = mController.prepare().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
+        assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mPrepareCalled);
     }
 
     @Test
-    public void testSeekTo() {
+    public void testSeekTo() throws Exception {
         prepareLooper();
         final long seekPosition = 12125L;
-        mController.seekTo(seekPosition);
-        try {
-            assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
-        } catch (InterruptedException e) {
-            fail(e.getMessage());
-        }
+        SessionResult result = mController.seekTo(seekPosition)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
+        assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mSeekToCalled);
         assertEquals(seekPosition, mPlayer.mSeekPosition);
     }
@@ -270,7 +259,7 @@
 
         MockPlayer player = new MockPlayer(0);
         player.mLastPlayerState = testState;
-        player.setAudioAttributes(testAudioAttributes);
+        player.mAudioAttributes = testAudioAttributes;
         player.mPlaylist = testPlaylist;
 
         mSession.updatePlayer(player);
@@ -290,10 +279,12 @@
     }
 
     @Test
-    public void testSetPlaylist() throws InterruptedException {
+    public void testSetPlaylist() throws Exception {
         prepareLooper();
         final List<String> list = TestUtils.createMediaIds(2);
-        mController.setPlaylist(list, null /* Metadata */);
+        SessionResult result = mController.setPlaylist(list, null /* Metadata */)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mSetPlaylistCalled);
@@ -311,9 +302,9 @@
     public void testSetMediaItem() throws Exception {
         prepareLooper();
         String mediaId = "testSetMediaItem";
-        int resultCode = mController.setMediaItem(mediaId).get(TIMEOUT_MS, TimeUnit.MILLISECONDS)
-                .getResultCode();
-        assertEquals(RESULT_SUCCESS, resultCode);
+        SessionResult result = mController.setMediaItem(mediaId)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertNull(mPlayer.mMetadata);
@@ -386,10 +377,12 @@
     }
 
     @Test
-    public void testUpdatePlaylistMetadata() throws InterruptedException {
+    public void testUpdatePlaylistMetadata() throws Exception {
         prepareLooper();
         final MediaMetadata testMetadata = TestUtils.createMetadata();
-        mController.updatePlaylistMetadata(testMetadata);
+        SessionResult result = mController.updatePlaylistMetadata(testMetadata)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mUpdatePlaylistMetadataCalled);
@@ -430,7 +423,9 @@
     public void testSetPlaybackSpeed() throws Exception {
         prepareLooper();
         final float speed = 1.5f;
-        mController.setPlaybackSpeed(speed);
+        SessionResult result = mController.setPlaybackSpeed(speed)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertEquals(speed, mPlayer.mPlaybackSpeed, 0.0f);
     }
@@ -445,7 +440,7 @@
     public void testGetPlaybackSpeed() throws InterruptedException {
         prepareLooper();
         final float speed = 1.5f;
-        mPlayer.setPlaybackSpeed(speed);
+        mPlayer.mPlaybackSpeed = speed;
 
         final CountDownLatch latch = new CountDownLatch(1);
         final MediaController controller =
@@ -562,7 +557,7 @@
         };
         final MediaController controller = createController(mSession.getToken(), true, null,
                 callback);
-        mSession.getPlayer().setPlaylist(testPlaylist, null);
+        mPlayer.mPlaylist = testPlaylist;
         mPlayer.mBufferedPosition = testBufferingPosition;
         mPlayer.notifyBufferingStateChanged(testItem, testBufferingState);
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
@@ -606,7 +601,7 @@
         prepareLooper();
         final int listSize = 5;
         final List<MediaItem> list = TestUtils.createMediaItems(listSize);
-        mPlayer.setPlaylist(list, null);
+        mPlayer.mPlaylist = list;
 
         final int index = 3;
         final MediaItem currentItem = list.get(index);
@@ -639,22 +634,25 @@
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         // Known DSD should be notified through the onCurrentMediaItemChanged.
-        mPlayer.skipToPlaylistItem(index);
+        mPlayer.mIndex = index;
+        mPlayer.mCurrentMediaItem = mPlayer.mItem = mPlayer.mPlaylist.get(index);
         mPlayer.notifyCurrentMediaItemChanged(currentItem);
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         // Null DSD becomes null MediaItem.
-        mPlayer.setMediaItem(null);
+        mPlayer.mCurrentMediaItem = mPlayer.mItem = null;
         mPlayer.notifyCurrentMediaItemChanged(null);
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
     @Test
-    public void testAddPlaylistItem() throws InterruptedException {
+    public void testAddPlaylistItem() throws Exception {
         prepareLooper();
         final int testIndex = 12;
         final String testId = "testAddPlaylistItem";
-        mController.addPlaylistItem(testIndex, testId);
+        SessionResult result = mController.addPlaylistItem(testIndex, testId)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mAddPlaylistItemCalled);
@@ -663,7 +661,7 @@
     }
 
     @Test
-    public void testRemovePlaylistItem() throws InterruptedException {
+    public void testRemovePlaylistItem() throws Exception {
         prepareLooper();
         mPlayer.mPlaylist = TestUtils.createMediaItems(2);
 
@@ -672,7 +670,9 @@
         // player.
         MediaController controller = createController(mSession.getToken());
         int targetIndex = 0;
-        controller.removePlaylistItem(targetIndex);
+        SessionResult result = controller.removePlaylistItem(targetIndex)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mRemovePlaylistItemCalled);
@@ -680,11 +680,13 @@
     }
 
     @Test
-    public void testReplacePlaylistItem() throws InterruptedException {
+    public void testReplacePlaylistItem() throws Exception {
         prepareLooper();
         final int testIndex = 12;
         final String testId = "testAddPlaylistItem";
-        mController.replacePlaylistItem(testIndex, testId);
+        SessionResult result = mController.replacePlaylistItem(testIndex, testId)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mReplacePlaylistItemCalled);
@@ -693,29 +695,35 @@
     }
 
     @Test
-    public void testSkipToPreviousItem() throws InterruptedException {
+    public void testSkipToPreviousItem() throws Exception {
         prepareLooper();
-        mController.skipToPreviousPlaylistItem();
+        SessionResult result = mController.skipToPreviousPlaylistItem()
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mSkipToPreviousItemCalled);
     }
 
     @Test
-    public void testSkipToNextItem() throws InterruptedException {
+    public void testSkipToNextItem() throws Exception {
         prepareLooper();
-        mController.skipToNextPlaylistItem();
+        SessionResult result = mController.skipToNextPlaylistItem()
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mSkipToNextItemCalled);
     }
 
     @Test
-    public void testSkipToPlaylistItem() throws InterruptedException {
+    public void testSkipToPlaylistItem() throws Exception {
         prepareLooper();
         List<MediaItem> playlist = TestUtils.createMediaItems(2);
         int targetIndex = 1;
         mPlayer.mPlaylist = playlist;
         MediaController controller = createController(mSession.getToken());
-        controller.skipToPlaylistItem(targetIndex);
+        SessionResult result = controller.skipToPlaylistItem(targetIndex)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mSkipToPlaylistItemCalled);
@@ -745,10 +753,12 @@
     }
 
     @Test
-    public void testSetShuffleMode() throws InterruptedException {
+    public void testSetShuffleMode() throws Exception {
         prepareLooper();
         final int testShuffleMode = SessionPlayer.SHUFFLE_MODE_GROUP;
-        mController.setShuffleMode(testShuffleMode);
+        SessionResult result = mController.setShuffleMode(testShuffleMode)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mSetShuffleModeCalled);
@@ -778,10 +788,12 @@
     }
 
     @Test
-    public void testSetRepeatMode() throws InterruptedException {
+    public void testSetRepeatMode() throws Exception {
         prepareLooper();
         final int testRepeatMode = SessionPlayer.REPEAT_MODE_GROUP;
-        mController.setRepeatMode(testRepeatMode);
+        SessionResult result = mController.setRepeatMode(testRepeatMode)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         assertTrue(mPlayer.mSetRepeatModeCalled);
@@ -875,7 +887,9 @@
         final MediaController controller = createController(mSession.getToken(), true, null, null);
 
         final int targetVolume = 50;
-        controller.setVolumeTo(targetVolume, 0 /* flags */);
+        SessionResult result = controller.setVolumeTo(targetVolume, 0 /* flags */)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(remotePlayer.mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(remotePlayer.mSetVolumeToCalled);
         assertEquals(targetVolume, (int) remotePlayer.mCurrentVolume);
@@ -894,7 +908,9 @@
         final MediaController controller = createController(mSession.getToken(), true, null, null);
 
         final int direction = AudioManager.ADJUST_RAISE;
-        controller.adjustVolume(direction, 0 /* flags */);
+        SessionResult result = controller.adjustVolume(direction, 0 /* flags */)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(remotePlayer.mLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(remotePlayer.mAdjustVolumeCalled);
         assertEquals(direction, remotePlayer.mDirection);
@@ -923,7 +939,7 @@
         AudioAttributesCompat attrs = new AudioAttributesCompat.Builder()
                 .setLegacyStreamType(stream)
                 .build();
-        mPlayer.setAudioAttributes(attrs);
+        mPlayer.mAudioAttributes = attrs;
         mSession.updatePlayer(mPlayer);
 
         final int originalVolume = mAudioManager.getStreamVolume(stream);
@@ -931,7 +947,9 @@
                 ? originalVolume + 1 : originalVolume - 1;
         Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume);
 
-        mController.setVolumeTo(targetVolume, AudioManager.FLAG_SHOW_UI);
+        SessionResult result = mController.setVolumeTo(targetVolume, AudioManager.FLAG_SHOW_UI)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         new PollingCheck(VOLUME_CHANGE_TIMEOUT_MS) {
             @Override
             protected boolean check() {
@@ -966,7 +984,7 @@
         AudioAttributesCompat attrs = new AudioAttributesCompat.Builder()
                 .setLegacyStreamType(stream)
                 .build();
-        mPlayer.setAudioAttributes(attrs);
+        mPlayer.mAudioAttributes = attrs;
         mSession.updatePlayer(mPlayer);
 
         final int originalVolume = mAudioManager.getStreamVolume(stream);
@@ -975,7 +993,9 @@
         final int targetVolume = originalVolume + direction;
         Log.d(TAG, "originalVolume=" + originalVolume + ", targetVolume=" + targetVolume);
 
-        mController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI);
+        SessionResult result = mController.adjustVolume(direction, AudioManager.FLAG_SHOW_UI)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         new PollingCheck(VOLUME_CHANGE_TIMEOUT_MS) {
             @Override
             protected boolean check() {
@@ -995,7 +1015,7 @@
     }
 
     @Test
-    public void testSendCustomCommand() throws InterruptedException {
+    public void testSendCustomCommand() throws Exception {
         prepareLooper();
         // TODO(jaewan): Need to revisit with the permission.
         final String command = "test_custom_command";
@@ -1031,7 +1051,9 @@
         mSession = new MediaSession.Builder(mContext, mPlayer)
                 .setSessionCallback(sHandlerExecutor, callback).setId(TAG).build();
         final MediaController controller = createController(mSession.getToken());
-        controller.sendCustomCommand(testCommand, testArgs);
+        SessionResult result = controller.sendCustomCommand(testCommand, testArgs)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -1084,7 +1106,7 @@
     }
 
     @Test
-    public void testFastForward() throws InterruptedException {
+    public void testFastForward() throws Exception {
         prepareLooper();
         final CountDownLatch latch = new CountDownLatch(1);
         final SessionCallback callback = new SessionCallback() {
@@ -1100,13 +1122,14 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testFastForward").build()) {
             MediaController controller = createController(session.getToken());
-            controller.fastForward();
+            SessionResult result = controller.fastForward().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testRewind() throws InterruptedException {
+    public void testRewind() throws Exception {
         prepareLooper();
         final CountDownLatch latch = new CountDownLatch(1);
         final SessionCallback callback = new SessionCallback() {
@@ -1121,13 +1144,14 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testRewind").build()) {
             MediaController controller = createController(session.getToken());
-            controller.rewind();
+            SessionResult result = controller.rewind().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPlayFromSearch() throws InterruptedException {
+    public void testPlayFromSearch() throws Exception {
         prepareLooper();
         final String request = "random query";
         final Bundle bundle = new Bundle();
@@ -1149,13 +1173,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPlayFromSearch").build()) {
             MediaController controller = createController(session.getToken());
-            controller.playFromSearch(request, bundle);
+            SessionResult result = controller.playFromSearch(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPlayFromUri() throws InterruptedException {
+    public void testPlayFromUri() throws Exception {
         prepareLooper();
         final Uri request = Uri.parse("foo://boo");
         final Bundle bundle = new Bundle();
@@ -1176,13 +1202,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPlayFromUri").build()) {
             MediaController controller = createController(session.getToken());
-            controller.playFromUri(request, bundle);
+            SessionResult result = controller.playFromUri(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPlayFromMediaId() throws InterruptedException {
+    public void testPlayFromMediaId() throws Exception {
         prepareLooper();
         final String request = "media_id";
         final Bundle bundle = new Bundle();
@@ -1203,13 +1231,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPlayFromMediaId").build()) {
             MediaController controller = createController(session.getToken());
-            controller.playFromMediaId(request, bundle);
+            SessionResult result = controller.playFromMediaId(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPrepareFromSearch() throws InterruptedException {
+    public void testPrepareFromSearch() throws Exception {
         prepareLooper();
         final String request = "random query";
         final Bundle bundle = new Bundle();
@@ -1230,13 +1260,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPrepareFromSearch").build()) {
             MediaController controller = createController(session.getToken());
-            controller.prepareFromSearch(request, bundle);
+            SessionResult result = controller.prepareFromSearch(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPrepareFromUri() throws InterruptedException {
+    public void testPrepareFromUri() throws Exception {
         prepareLooper();
         final Uri request = Uri.parse("foo://boo");
         final Bundle bundle = new Bundle();
@@ -1257,13 +1289,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPrepareFromUri").build()) {
             MediaController controller = createController(session.getToken());
-            controller.prepareFromUri(request, bundle);
+            SessionResult result = controller.prepareFromUri(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testPrepareFromMediaId() throws InterruptedException {
+    public void testPrepareFromMediaId() throws Exception {
         prepareLooper();
         final String request = "media_id";
         final Bundle bundle = new Bundle();
@@ -1284,13 +1318,15 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testPrepareFromMediaId").build()) {
             MediaController controller = createController(session.getToken());
-            controller.prepareFromMediaId(request, bundle);
+            SessionResult result = controller.prepareFromMediaId(request, bundle)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
 
     @Test
-    public void testSetRating() throws InterruptedException {
+    public void testSetRating() throws Exception {
         prepareLooper();
         final float ratingValue = 3.5f;
         final Rating rating = new StarRating(5, ratingValue);
@@ -1314,7 +1350,9 @@
                 .setSessionCallback(sHandlerExecutor, callback)
                 .setId("testSetRating").build()) {
             MediaController controller = createController(session.getToken());
-            controller.setRating(mediaId, rating);
+            SessionResult result = controller.setRating(mediaId, rating)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
@@ -1367,6 +1405,7 @@
             });
             final MediaController controller = createController(mSession.getToken());
             testHandler.post(new Runnable() {
+                @SuppressWarnings("FutureReturnValueIgnored")
                 @Override
                 public void run() {
                     final int state = SessionPlayer.PLAYER_STATE_ERROR;
@@ -1423,18 +1462,18 @@
     }
 
     @Test
-    public void testConnectToService_sessionService() throws InterruptedException {
+    public void testConnectToService_sessionService() throws Exception {
         prepareLooper();
         testConnectToService(MockMediaSessionService.ID);
     }
 
     @Test
-    public void testConnectToService_libraryService() throws InterruptedException {
+    public void testConnectToService_libraryService() throws Exception {
         prepareLooper();
         testConnectToService(MockMediaLibraryService.ID);
     }
 
-    public void testConnectToService(String id) throws InterruptedException {
+    public void testConnectToService(String id) throws Exception {
         prepareLooper();
         final CountDownLatch latch = new CountDownLatch(1);
         final MediaLibrarySessionCallback sessionCallback = new MediaLibrarySessionCallback() {
@@ -1474,7 +1513,8 @@
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
         // Test command from controller to session service.
-        mController.play();
+        SessionResult result = mController.play().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mPlayCalled);
 
@@ -1492,7 +1532,7 @@
 
     @LargeTest
     @Test
-    public void testControllerAfterSessionIsClosed_sessionService() throws InterruptedException {
+    public void testControllerAfterSessionIsClosed_sessionService() throws Exception {
         prepareLooper();
         testConnectToService(MockMediaSessionService.ID);
         testControllerAfterSessionIsClosed(MockMediaSessionService.ID);
@@ -1601,7 +1641,7 @@
             }
         };
         MediaController controller = createController(mSession.getToken(), true, null, callback);
-        mPlayer.setMediaItem(item);
+        mPlayer.mCurrentMediaItem = mPlayer.mItem = item;
         mPlayer.notifyCurrentMediaItemChanged(item);
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         item.setMetadata(TestUtils.createMetadata(item.getMediaId(), duration));
@@ -1638,8 +1678,9 @@
             }
         };
         MediaController controller = createController(mSession.getToken(), true, null, callback);
-        mPlayer.setPlaylist(list, null);
-        mPlayer.skipToPlaylistItem(currentItemIdx);
+        mPlayer.mPlaylist = list;
+        mPlayer.mIndex = currentItemIdx;
+        mPlayer.mCurrentMediaItem = mPlayer.mItem = mPlayer.mPlaylist.get(currentItemIdx);
         mPlayer.notifyPlaylistChanged();
         assertFalse(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         list.get(1).setMetadata(newMetadata);
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MediaSessionTest.java b/media2/session/src/androidTest/java/androidx/media2/session/MediaSessionTest.java
index b41b628..c6a1640 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MediaSessionTest.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MediaSessionTest.java
@@ -159,7 +159,7 @@
         final AudioAttributesCompat attrs = new AudioAttributesCompat.Builder()
                 .setContentType(CONTENT_TYPE_MUSIC)
                 .build();
-        player.setAudioAttributes(attrs);
+        player.mAudioAttributes = attrs;
 
         final int maxVolume = 100;
         final int currentVolume = 23;
@@ -217,37 +217,37 @@
     }
 
     @Test
-    public void testPlay() throws Exception {
+    public void testPlay() {
         prepareLooper();
-        mSession.getPlayer().play();
+        assertNotNull(mSession.getPlayer().play());
         assertTrue(mPlayer.mPlayCalled);
     }
 
     @Test
-    public void testPause() throws Exception {
+    public void testPause() {
         prepareLooper();
-        mSession.getPlayer().pause();
+        assertNotNull(mSession.getPlayer().pause());
         assertTrue(mPlayer.mPauseCalled);
     }
 
     @Test
-    public void testPrepare() throws Exception {
+    public void testPrepare() {
         prepareLooper();
-        mSession.getPlayer().prepare();
+        assertNotNull(mSession.getPlayer().prepare());
         assertTrue(mPlayer.mPrepareCalled);
     }
 
     @Test
-    public void testSeekTo() throws Exception {
+    public void testSeekTo() {
         prepareLooper();
         final long pos = 1004L;
-        mSession.getPlayer().seekTo(pos);
+        assertNotNull(mSession.getPlayer().seekTo(pos));
         assertTrue(mPlayer.mSeekToCalled);
         assertEquals(pos, mPlayer.mSeekPosition);
     }
 
     @Test
-    public void testGetDuration() throws Exception {
+    public void testGetDuration() {
         prepareLooper();
         final long testDuration = 9999;
         mPlayer.mDuration = testDuration;
@@ -256,19 +256,19 @@
     }
 
     @Test
-    public void testSetPlaybackSpeed() throws Exception {
+    public void testSetPlaybackSpeed() {
         prepareLooper();
         final float speed = 1.5f;
-        mSession.getPlayer().setPlaybackSpeed(speed);
+        assertNotNull(mSession.getPlayer().setPlaybackSpeed(speed));
         assertTrue(mPlayer.mSetPlaybackSpeedCalled);
         assertEquals(speed, mPlayer.mPlaybackSpeed, 0.0f);
     }
 
     @Test
-    public void testGetPlaybackSpeed() throws Exception {
+    public void testGetPlaybackSpeed() {
         prepareLooper();
         final float speed = 1.5f;
-        mPlayer.setPlaybackSpeed(speed);
+        mPlayer.mPlaybackSpeed = speed;
         mPlayer.mLastPlayerState = SessionPlayer.PLAYER_STATE_PLAYING;
         assertEquals(speed, mSession.getPlayer().getPlaybackSpeed(), 0.0f);
     }
@@ -284,24 +284,24 @@
     @Test
     public void testSkipToPreviousItem() {
         prepareLooper();
-        mSession.getPlayer().skipToPreviousPlaylistItem();
+        assertNotNull(mSession.getPlayer().skipToPreviousPlaylistItem());
         assertTrue(mPlayer.mSkipToPreviousItemCalled);
     }
 
     @Test
-    public void testSkipToNextItem() throws Exception {
+    public void testSkipToNextItem() {
         prepareLooper();
-        mSession.getPlayer().skipToNextPlaylistItem();
+        assertNotNull(mSession.getPlayer().skipToNextPlaylistItem());
         assertTrue(mPlayer.mSkipToNextItemCalled);
     }
 
     @Test
-    public void testSkipToPlaylistItem() throws Exception {
+    public void testSkipToPlaylistItem() {
         prepareLooper();
         final List<MediaItem> list = TestUtils.createMediaItems(2);
         int targetIndex = 0;
-        mSession.getPlayer().setPlaylist(list, null);
-        mSession.getPlayer().skipToPlaylistItem(targetIndex);
+        assertNotNull(mSession.getPlayer().setPlaylist(list, null));
+        assertNotNull(mSession.getPlayer().skipToPlaylistItem(targetIndex));
         assertTrue(mPlayer.mSkipToPlaylistItemCalled);
         assertSame(targetIndex, mPlayer.mIndex);
     }
@@ -344,7 +344,7 @@
     public void testSetPlaylist() {
         prepareLooper();
         final List<MediaItem> list = TestUtils.createMediaItems(2);
-        mSession.getPlayer().setPlaylist(list, null);
+        assertNotNull(mSession.getPlayer().setPlaylist(list, null));
         assertTrue(mPlayer.mSetPlaylistCalled);
         assertSame(list, mPlayer.mPlaylist);
         assertNull(mPlayer.mMetadata);
@@ -362,7 +362,7 @@
     public void testUpdatePlaylistMetadata() {
         prepareLooper();
         final MediaMetadata testMetadata = TestUtils.createMetadata();
-        mSession.getPlayer().updatePlaylistMetadata(testMetadata);
+        assertNotNull(mSession.getPlayer().updatePlaylistMetadata(testMetadata));
         assertTrue(mPlayer.mUpdatePlaylistMetadataCalled);
         assertSame(testMetadata, mPlayer.mMetadata);
     }
@@ -380,7 +380,7 @@
         prepareLooper();
         final int testIndex = 12;
         final MediaItem testMediaItem = TestUtils.createMediaItemWithMetadata();
-        mSession.getPlayer().addPlaylistItem(testIndex, testMediaItem);
+        assertNotNull(mSession.getPlayer().addPlaylistItem(testIndex, testMediaItem));
         assertTrue(mPlayer.mAddPlaylistItemCalled);
         assertEquals(testIndex, mPlayer.mIndex);
         assertSame(testMediaItem, mPlayer.mItem);
@@ -391,18 +391,18 @@
         prepareLooper();
         final List<MediaItem> list = TestUtils.createMediaItems(2);
         int targetIndex = 0;
-        mSession.getPlayer().setPlaylist(list, null);
-        mSession.getPlayer().removePlaylistItem(targetIndex);
+        assertNotNull(mSession.getPlayer().setPlaylist(list, null));
+        assertNotNull(mSession.getPlayer().removePlaylistItem(targetIndex));
         assertTrue(mPlayer.mRemovePlaylistItemCalled);
         assertSame(targetIndex, mPlayer.mIndex);
     }
 
     @Test
-    public void testReplacePlaylistItem() throws InterruptedException {
+    public void testReplacePlaylistItem() {
         prepareLooper();
         final int testIndex = 12;
         final MediaItem testMediaItem = TestUtils.createMediaItemWithMetadata();
-        mSession.getPlayer().replacePlaylistItem(testIndex, testMediaItem);
+        assertNotNull(mSession.getPlayer().replacePlaylistItem(testIndex, testMediaItem));
         assertTrue(mPlayer.mReplacePlaylistItemCalled);
         assertEquals(testIndex, mPlayer.mIndex);
         assertSame(testMediaItem, mPlayer.mItem);
@@ -412,7 +412,7 @@
     public void testSetShuffleMode() {
         prepareLooper();
         final int testShuffleMode = SessionPlayer.SHUFFLE_MODE_GROUP;
-        mSession.getPlayer().setShuffleMode(testShuffleMode);
+        assertNotNull(mSession.getPlayer().setShuffleMode(testShuffleMode));
         assertTrue(mPlayer.mSetShuffleModeCalled);
         assertEquals(testShuffleMode, mPlayer.mShuffleMode);
     }
@@ -421,13 +421,13 @@
     public void testSetRepeatMode() {
         prepareLooper();
         final int testRepeatMode = SessionPlayer.REPEAT_MODE_GROUP;
-        mSession.getPlayer().setRepeatMode(testRepeatMode);
+        assertNotNull(mSession.getPlayer().setRepeatMode(testRepeatMode));
         assertTrue(mPlayer.mSetRepeatModeCalled);
         assertEquals(testRepeatMode, mPlayer.mRepeatMode);
     }
 
     @Test
-    public void testOnCommandCallback() throws InterruptedException {
+    public void testOnCommandCallback() throws Exception {
         prepareLooper();
         final MockOnCommandCallback callback = new MockOnCommandCallback();
         sHandler.postAndSync(new Runnable() {
@@ -440,14 +440,16 @@
             }
         });
         MediaController controller = createController(mSession.getToken());
-        controller.pause();
+        SessionResult pauseResult = controller.pause().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_ERROR_INVALID_STATE, pauseResult.getResultCode());
         assertFalse(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertFalse(mPlayer.mPauseCalled);
         assertEquals(1, callback.commands.size());
         assertEquals(SessionCommand.COMMAND_CODE_PLAYER_PAUSE,
-                (long) callback.commands.get(0).getCommandCode());
+                callback.commands.get(0).getCommandCode());
 
-        controller.play();
+        SessionResult playResult = controller.play().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, playResult.getResultCode());
         assertTrue(mPlayer.mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         assertTrue(mPlayer.mPlayCalled);
         assertFalse(mPlayer.mPauseCalled);
@@ -495,7 +497,7 @@
     }
 
     @Test
-    public void testSetCustomLayout() throws InterruptedException {
+    public void testSetCustomLayout() throws Exception {
         prepareLooper();
         final List<CommandButton> customLayout = new ArrayList<>();
         customLayout.add(new CommandButton.Builder()
@@ -534,7 +536,9 @@
                 }
             };
             MediaController controller = createController(session.getToken(), true, null, callback);
-            session.setCustomLayout(mTestControllerInfo, customLayout);
+            SessionResult result = session.setCustomLayout(mTestControllerInfo, customLayout)
+                    .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            assertEquals(RESULT_SUCCESS, result.getResultCode());
             assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         }
     }
@@ -571,7 +575,7 @@
     }
 
     @Test
-    public void testSendCustomCommand() throws InterruptedException {
+    public void testSendCustomCommand() throws Exception {
         prepareLooper();
         final SessionCommand testCommand = new SessionCommand("test_command_code", null);
         final Bundle testArgs = new Bundle();
@@ -597,7 +601,9 @@
         ControllerInfo controllerInfo = getTestControllerInfo();
         assertNotNull(controllerInfo);
         // TODO(jaewan): Test receivers as well.
-        mSession.sendCustomCommand(controllerInfo, testCommand, testArgs);
+        SessionResult result = mSession.sendCustomCommand(controllerInfo, testCommand, testArgs)
+                .get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        assertEquals(RESULT_SUCCESS, result.getResultCode());
         assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
     }
 
@@ -615,7 +621,7 @@
             @Nullable
             public SessionCommandGroup onConnect(@NonNull MediaSession session,
                     @NonNull ControllerInfo controller) {
-                session.sendCustomCommand(controller, testCommand, null);
+                assertNotNull(session.sendCustomCommand(controller, testCommand, null));
                 return super.onConnect(session, controller);
             }
         };
@@ -659,7 +665,7 @@
             @Override
             public void onPostConnect(@NonNull MediaSession session,
                     @NonNull ControllerInfo controller) {
-                session.sendCustomCommand(controller, testCommand, null);
+                assertNotNull(session.sendCustomCommand(controller, testCommand, null));
             }
         };
         final ControllerCallback testControllerCallback = new ControllerCallback() {
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MockMediaBrowserServiceCompat.java b/media2/session/src/androidTest/java/androidx/media2/session/MockMediaBrowserServiceCompat.java
index 2f3fd4f..a33ac3a 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MockMediaBrowserServiceCompat.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MockMediaBrowserServiceCompat.java
@@ -22,13 +22,12 @@
 import android.support.v4.media.session.MediaSessionCompat;
 import android.support.v4.media.session.MediaSessionCompat.Callback;
 
+import androidx.annotation.GuardedBy;
 import androidx.media.MediaBrowserServiceCompat;
 
 import java.lang.reflect.Method;
 import java.util.List;
 
-import javax.annotation.concurrent.GuardedBy;
-
 /**
  * Mock implementation of the browser.
  */
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MockMediaLibraryService.java b/media2/session/src/androidTest/java/androidx/media2/session/MockMediaLibraryService.java
index f6c5185..c52bd8c 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MockMediaLibraryService.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MockMediaLibraryService.java
@@ -25,6 +25,7 @@
 import static androidx.media2.session.LibraryResult.RESULT_SUCCESS;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -32,6 +33,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.GuardedBy;
 import androidx.annotation.NonNull;
 import androidx.media2.common.MediaItem;
 import androidx.media2.common.MediaMetadata;
@@ -46,8 +48,6 @@
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
-import javax.annotation.concurrent.GuardedBy;
-
 /**
  * Mock implementation of {@link MediaLibraryService} for testing.
  */
@@ -221,13 +221,13 @@
                         params);
             } else if (SEARCH_QUERY_TAKES_TIME.equals(query)) {
                 // Searching takes some time. Notify after 5 seconds.
-                Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
+                assertNotNull(Executors.newSingleThreadScheduledExecutor().schedule(new Runnable() {
                     @Override
                     public void run() {
                         mSession.notifySearchResultChanged(
                                 controllerInfo, query, SEARCH_RESULT_COUNT, params);
                     }
-                }, SEARCH_TIME_IN_MS, TimeUnit.MILLISECONDS);
+                }, SEARCH_TIME_IN_MS, TimeUnit.MILLISECONDS));
             } else if (SEARCH_QUERY_EMPTY_RESULT.equals(query)) {
                 mSession.notifySearchResultChanged(controllerInfo, query, 0, params);
             } else {
diff --git a/media2/session/src/androidTest/java/androidx/media2/session/MockPlayer.java b/media2/session/src/androidTest/java/androidx/media2/session/MockPlayer.java
index 4d935f2..12a672c 100644
--- a/media2/session/src/androidTest/java/androidx/media2/session/MockPlayer.java
+++ b/media2/session/src/androidTest/java/androidx/media2/session/MockPlayer.java
@@ -87,7 +87,7 @@
     public boolean mSetRepeatModeCalled;
     public boolean mSetShuffleModeCalled;
 
-    private AudioAttributesCompat mAudioAttributes;
+    AudioAttributesCompat mAudioAttributes;
 
     public MockPlayer(int count) {
         this(count, false);
diff --git a/media2/session/src/main/java/androidx/media2/session/SessionTokenImplBase.java b/media2/session/src/main/java/androidx/media2/session/SessionTokenImplBase.java
index b0296b7..1db4c73 100644
--- a/media2/session/src/main/java/androidx/media2/session/SessionTokenImplBase.java
+++ b/media2/session/src/main/java/androidx/media2/session/SessionTokenImplBase.java
@@ -156,7 +156,7 @@
     }
 
     @Override
-    @NonNull
+    @Nullable
     public Bundle getExtras() {
         return mExtras;
     }
diff --git a/palette/palette/build.gradle b/palette/palette/build.gradle
index 87eb258b..1a785db 100644
--- a/palette/palette/build.gradle
+++ b/palette/palette/build.gradle
@@ -9,7 +9,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     annotationProcessor(NULLAWAY)
diff --git a/percentlayout/percentlayout/build.gradle b/percentlayout/percentlayout/build.gradle
index e5c8470..5b2ac05 100644
--- a/percentlayout/percentlayout/build.gradle
+++ b/percentlayout/percentlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api(ANDROIDX_ANNOTATION)
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/preference/build.gradle b/preference/build.gradle
index 8235c7a..43b0f07 100644
--- a/preference/build.gradle
+++ b/preference/build.gradle
@@ -30,7 +30,7 @@
     implementation("androidx.annotation:annotation:1.1.0")
     api("androidx.appcompat:appcompat:1.1.0-rc01")
     // TODO: change to alpha05 after release
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.fragment:fragment:1.1.0-rc01")
     api("androidx.recyclerview:recyclerview:1.0.0")
diff --git a/recyclerview/recyclerview-selection/build.gradle b/recyclerview/recyclerview-selection/build.gradle
index a364be0..ac2f787 100644
--- a/recyclerview/recyclerview-selection/build.gradle
+++ b/recyclerview/recyclerview-selection/build.gradle
@@ -27,7 +27,7 @@
 dependencies {
     api(project(":recyclerview:recyclerview"))
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.1.0")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/recyclerview/recyclerview/build.gradle b/recyclerview/recyclerview/build.gradle
index 4ec3faf..16d7734 100644
--- a/recyclerview/recyclerview/build.gradle
+++ b/recyclerview/recyclerview/build.gradle
@@ -11,7 +11,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc02")
     implementation("androidx.collection:collection:1.0.0")
     api("androidx.customview:customview:1.0.0")
 
diff --git a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
index c14e5a8..0d1f6d9 100644
--- a/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
+++ b/recyclerview/recyclerview/src/main/java/androidx/recyclerview/widget/RecyclerView.java
@@ -5140,11 +5140,13 @@
 
     void dispatchOnScrolled(int hresult, int vresult) {
         mDispatchScrollCounter++;
-        // Pass the current scrollX/scrollY values; no actual change in these properties occurred
-        // but some general-purpose code may choose to respond to changes this way.
+        // Pass the current scrollX/scrollY values as current values. No actual change in these
+        // properties occurred. Pass negative hresult and vresult as old values so that
+        // postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt) in onScrollChanged
+        // sends the scrolled accessibility event correctly.
         final int scrollX = getScrollX();
         final int scrollY = getScrollY();
-        onScrollChanged(scrollX, scrollY, scrollX, scrollY);
+        onScrollChanged(scrollX, scrollY, scrollX - hresult, scrollY - vresult);
 
         // Pass the real deltas to onScrolled, the RecyclerView-specific method.
         onScrolled(hresult, vresult);
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/FieldProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/FieldProcessor.kt
index 07d1f2c..5d04025 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/FieldProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/FieldProcessor.kt
@@ -32,8 +32,8 @@
     val containing: DeclaredType,
     val element: Element,
     val bindingScope: BindingScope,
-                     // pass only if this is processed as a child of Embedded field
-    val fieldParent: EmbeddedField?
+    val fieldParent: EmbeddedField?, // pass only if this is processed as a child of Embedded field
+    val onBindingError: (field: Field, errorMsg: String) -> Unit
 ) {
     val context = baseContext.fork(element)
     fun process(): Field {
@@ -82,20 +82,23 @@
                 field.statementBinder = adapter
                 field.cursorValueReader = adapter
                 field.affinity = adapterAffinity
-                context.checker.check(adapter != null, field.element,
-                        ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER)
+                if (adapter == null) {
+                    onBindingError(field, ProcessorErrors.CANNOT_FIND_COLUMN_TYPE_ADAPTER)
+                }
             }
             BindingScope.BIND_TO_STMT -> {
                 field.statementBinder = context.typeAdapterStore
                         .findStatementValueBinder(field.type, field.affinity)
-                context.checker.check(field.statementBinder != null, field.element,
-                        ProcessorErrors.CANNOT_FIND_STMT_BINDER)
+                if (field.statementBinder == null) {
+                    onBindingError(field, ProcessorErrors.CANNOT_FIND_STMT_BINDER)
+                }
             }
             BindingScope.READ_FROM_CURSOR -> {
                 field.cursorValueReader = context.typeAdapterStore
                         .findCursorValueReader(field.type, field.affinity)
-                context.checker.check(field.cursorValueReader != null, field.element,
-                        ProcessorErrors.CANNOT_FIND_CURSOR_READER)
+                if (field.cursorValueReader == null) {
+                    onBindingError(field, ProcessorErrors.CANNOT_FIND_CURSOR_READER)
+                }
             }
         }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
index 40869db..1059368 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/FtsTableEntityProcessor.kt
@@ -61,17 +61,14 @@
                 ProcessorErrors.ENTITY_MUST_BE_ANNOTATED_WITH_ENTITY)
         val entityAnnotation = element.toAnnotationBox(androidx.room.Entity::class)
         val tableName: String
-        val ignoredColumns: Set<String>
         if (entityAnnotation != null) {
             tableName = extractTableName(element, entityAnnotation.value)
-            ignoredColumns = entityAnnotation.value.ignoredColumns.toSet()
             context.checker.check(extractIndices(entityAnnotation, tableName).isEmpty(),
                     element, ProcessorErrors.INDICES_IN_FTS_ENTITY)
             context.checker.check(extractForeignKeys(entityAnnotation).isEmpty(),
                     element, ProcessorErrors.FOREIGN_KEYS_IN_FTS_ENTITY)
         } else {
             tableName = element.simpleName.toString()
-            ignoredColumns = emptySet()
         }
 
         val pojo = PojoProcessor.createFor(
@@ -79,8 +76,7 @@
                 element = element,
                 bindingScope = FieldProcessor.BindingScope.TWO_WAY,
                 parent = null,
-                referenceStack = referenceStack,
-                ignoredColumns = ignoredColumns).process()
+                referenceStack = referenceStack).process()
 
         context.checker.check(pojo.relations.isEmpty(), element, ProcessorErrors.RELATION_IN_ENTITY)
 
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 efebfac..235a457 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/PojoProcessor.kt
@@ -79,7 +79,6 @@
     val bindingScope: FieldProcessor.BindingScope,
     val parent: EmbeddedField?,
     val referenceStack: LinkedHashSet<Name> = LinkedHashSet(),
-    val ignoredColumns: Set<String>,
     private val delegate: Delegate
 ) {
     val context = baseContext.fork(element)
@@ -97,8 +96,7 @@
             element: TypeElement,
             bindingScope: FieldProcessor.BindingScope,
             parent: EmbeddedField?,
-            referenceStack: LinkedHashSet<Name> = LinkedHashSet(),
-            ignoredColumns: Set<String> = emptySet()
+            referenceStack: LinkedHashSet<Name> = LinkedHashSet()
         ): PojoProcessor {
             val (pojoElement, delegate) = if (element.hasAnnotation(AutoValue::class)) {
                 val elementUtils = context.processingEnv.elementUtils
@@ -117,7 +115,6 @@
                     bindingScope = bindingScope,
                     parent = parent,
                     referenceStack = referenceStack,
-                    ignoredColumns = ignoredColumns,
                     delegate = delegate)
         }
     }
@@ -161,6 +158,10 @@
                     }
                 }
 
+        val ignoredColumns =
+            element.toAnnotationBox(androidx.room.Entity::class)?.value?.ignoredColumns?.toSet()
+                ?: emptySet()
+        val fieldBindingErrors = mutableMapOf<Field, String>()
         val unfilteredMyFields = allFields[null]
                 ?.map {
                     FieldProcessor(
@@ -168,10 +169,17 @@
                             containing = declaredType,
                             element = it,
                             bindingScope = bindingScope,
-                            fieldParent = parent).process()
+                            fieldParent = parent,
+                            onBindingError = { field, errorMsg ->
+                                fieldBindingErrors[field] = errorMsg
+                            }).process()
                 } ?: emptyList()
         val myFields = unfilteredMyFields.filterNot { ignoredColumns.contains(it.columnName) }
-
+        myFields.forEach { field ->
+            fieldBindingErrors[field]?.let {
+                context.logger.e(field.element, it)
+            }
+        }
         val unfilteredEmbeddedFields =
                 allFields[Embedded::class]
                         ?.mapNotNull {
@@ -707,7 +715,9 @@
                     context.logger.e(field.element,
                             ProcessorErrors.tooManyMatchingGetters(field, matching))
                 })
-        context.checker.check(success, field.element, CANNOT_FIND_GETTER_FOR_FIELD)
+        context.checker.check(
+            success || bindingScope == FieldProcessor.BindingScope.READ_FROM_CURSOR,
+            field.element, CANNOT_FIND_GETTER_FOR_FIELD)
     }
 
     private fun assignSetters(
@@ -756,7 +766,9 @@
                     context.logger.e(field.element,
                             ProcessorErrors.tooManyMatchingSetter(field, matching))
                 })
-        context.checker.check(success, field.element, CANNOT_FIND_SETTER_FOR_FIELD)
+        context.checker.check(
+            success || bindingScope == FieldProcessor.BindingScope.BIND_TO_STMT,
+            field.element, CANNOT_FIND_SETTER_FOR_FIELD)
     }
 
     /**
diff --git a/room/compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt b/room/compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
index a0b0c29..f570457 100644
--- a/room/compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/processor/TableEntityProcessor.kt
@@ -65,19 +65,16 @@
         val entityIndices: List<IndexInput>
         val foreignKeyInputs: List<ForeignKeyInput>
         val inheritSuperIndices: Boolean
-        val ignoredColumns: Set<String>
         if (annotationBox != null) {
             tableName = extractTableName(element, annotationBox.value)
             entityIndices = extractIndices(annotationBox, tableName)
             inheritSuperIndices = annotationBox.value.inheritSuperIndices
             foreignKeyInputs = extractForeignKeys(annotationBox)
-            ignoredColumns = annotationBox.value.ignoredColumns.toSet()
         } else {
             tableName = element.simpleName.toString()
             foreignKeyInputs = emptyList()
             entityIndices = emptyList()
             inheritSuperIndices = false
-            ignoredColumns = emptySet()
         }
         context.checker.notBlank(tableName, element,
                 ProcessorErrors.ENTITY_TABLE_NAME_CANNOT_BE_EMPTY)
@@ -85,12 +82,12 @@
                 ProcessorErrors.ENTITY_TABLE_NAME_CANNOT_START_WITH_SQLITE)
 
         val pojo = PojoProcessor.createFor(
-                context = context,
-                element = element,
-                bindingScope = FieldProcessor.BindingScope.TWO_WAY,
-                parent = null,
-                referenceStack = referenceStack,
-                ignoredColumns = ignoredColumns).process()
+            context = context,
+            element = element,
+            bindingScope = FieldProcessor.BindingScope.TWO_WAY,
+            parent = null,
+            referenceStack = referenceStack
+        ).process()
         context.checker.check(pojo.relations.isEmpty(), element, RELATION_IN_ENTITY)
 
         val fieldIndices = pojo.fields
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/BaseObservableQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/BaseObservableQueryResultBinder.kt
index f33bef3..887fec8 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/BaseObservableQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/BaseObservableQueryResultBinder.kt
@@ -46,7 +46,8 @@
         roomSQLiteQueryVar: String,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val transactionWrapper = if (inTransaction) {
             builder.transactionWrapper(dbField)
@@ -58,13 +59,16 @@
         val cursorVar = scope.getTmpVar("_cursor")
         transactionWrapper?.beginTransactionWithControlFlow()
         builder.apply {
-            addStatement("final $T $L = $T.query($N, $L, $L)",
-                    AndroidTypeNames.CURSOR,
-                    cursorVar,
-                    RoomTypeNames.DB_UTIL,
-                    dbField,
-                    roomSQLiteQueryVar,
-                    if (shouldCopyCursor) "true" else "false")
+            addStatement(
+                "final $T $L = $T.query($N, $L, $L, $L)",
+                AndroidTypeNames.CURSOR,
+                cursorVar,
+                RoomTypeNames.DB_UTIL,
+                dbField,
+                roomSQLiteQueryVar,
+                if (shouldCopyCursor) "true" else "false",
+                cancellationSignalVar
+            )
             beginControlFlow("try").apply {
                 val adapterScope = scope.fork()
                 adapter?.convert(outVar, cursorVar, adapterScope)
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
index bc2fb8e..127d925 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CoroutineFlowResultBinder.kt
@@ -44,7 +44,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
             createRunQueryAndReturnStatements(
@@ -53,7 +54,8 @@
                 canReleaseQuery = canReleaseQuery,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = scope)
+                scope = scope,
+                cancellationSignalVar = cancellationSignalVar)
         }.build()
 
         scope.builder().apply {
@@ -75,7 +77,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val transactionWrapper = if (inTransaction) {
             builder.transactionWrapper(dbField)
@@ -87,13 +90,14 @@
         val cursorVar = scope.getTmpVar("_cursor")
         transactionWrapper?.beginTransactionWithControlFlow()
         builder.apply {
-            addStatement("final $T $L = $T.query($N, $L, $L)",
+            addStatement("final $T $L = $T.query($N, $L, $L, $L)",
                 AndroidTypeNames.CURSOR,
                 cursorVar,
                 RoomTypeNames.DB_UTIL,
                 dbField,
                 roomSQLiteQueryVar,
-                if (shouldCopyCursor) "true" else "false")
+                if (shouldCopyCursor) "true" else "false",
+                cancellationSignalVar)
             beginControlFlow("try").apply {
                 val adapterScope = scope.fork()
                 adapter?.convert(outVar, cursorVar, adapterScope)
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 d97ba61..906db3b 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
@@ -43,7 +43,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
             createRunQueryAndReturnStatements(
@@ -52,7 +53,8 @@
                 canReleaseQuery = canReleaseQuery,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = scope)
+                scope = scope,
+                cancellationSignalVar = cancellationSignalVar)
         }.build()
 
         scope.builder().apply {
@@ -72,7 +74,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val transactionWrapper = if (inTransaction) {
             builder.transactionWrapper(dbField)
@@ -84,13 +87,16 @@
         val cursorVar = scope.getTmpVar("_cursor")
         transactionWrapper?.beginTransactionWithControlFlow()
         builder.apply {
-            addStatement("final $T $L = $T.query($N, $L, $L)",
+            addStatement(
+                "final $T $L = $T.query($N, $L, $L, $L)",
                 AndroidTypeNames.CURSOR,
                 cursorVar,
                 RoomTypeNames.DB_UTIL,
                 dbField,
                 roomSQLiteQueryVar,
-                if (shouldCopyCursor) "true" else "false")
+                if (shouldCopyCursor) "true" else "false",
+                cancellationSignalVar
+            )
             beginControlFlow("try").apply {
                 val adapterScope = scope.fork()
                 adapter?.convert(outVar, cursorVar, adapterScope)
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CursorQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CursorQueryResultBinder.kt
index 9f8c9e7..9e9eb9c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CursorQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/CursorQueryResultBinder.kt
@@ -29,7 +29,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val builder = scope.builder()
         val transactionWrapper = if (inTransaction) {
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder.kt
index 9bf9860..2609a29 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/DataSourceFactoryQueryResultBinder.kt
@@ -37,7 +37,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         scope.builder().apply {
             val pagedListProvider = TypeSpec
@@ -48,7 +49,8 @@
                         roomSQLiteQueryVar = roomSQLiteQueryVar,
                         dbField = dbField,
                         inTransaction = inTransaction,
-                        scope = scope))
+                        scope = scope,
+                        cancellationSignalVar = cancellationSignalVar))
             }.build()
             addStatement("return $L", pagedListProvider)
         }
@@ -58,7 +60,8 @@
         roomSQLiteQueryVar: String,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ): MethodSpec = MethodSpec.methodBuilder("create").apply {
         addAnnotation(Override::class.java)
         addModifiers(Modifier.PUBLIC)
@@ -69,7 +72,8 @@
                 canReleaseQuery = true,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = countedBinderScope)
+                scope = countedBinderScope,
+                cancellationSignalVar = cancellationSignalVar)
         addCode(countedBinderScope.builder().build())
     }.build()
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
index 722242e..b3d8c2c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/GuavaListenableFutureQueryResultBinder.kt
@@ -41,7 +41,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         // Callable<T> // Note that this callable does not release the query object.
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
@@ -50,7 +51,8 @@
                 roomSQLiteQueryVar = roomSQLiteQueryVar,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = scope
+                scope = scope,
+                cancellationSignalVar = cancellationSignalVar
             )
         }.build()
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
index 156117c..48e322c 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/InstantQueryResultBinder.kt
@@ -33,7 +33,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         scope.builder().apply {
             addStatement("$N.assertNotSuspendingTransaction()", DaoWriter.dbField)
@@ -48,13 +49,16 @@
             val shouldCopyCursor = adapter?.shouldCopyCursor() == true
             val outVar = scope.getTmpVar("_result")
             val cursorVar = scope.getTmpVar("_cursor")
-            addStatement("final $T $L = $T.query($N, $L, $L)",
-                    AndroidTypeNames.CURSOR,
-                    cursorVar,
-                    RoomTypeNames.DB_UTIL,
-                    dbField,
-                    roomSQLiteQueryVar,
-                    if (shouldCopyCursor) "true" else "false")
+            addStatement(
+                "final $T $L = $T.query($N, $L, $L, $L)",
+                AndroidTypeNames.CURSOR,
+                cursorVar,
+                RoomTypeNames.DB_UTIL,
+                dbField,
+                roomSQLiteQueryVar,
+                if (shouldCopyCursor) "true" else "false",
+                cancellationSignalVar
+            )
             beginControlFlow("try").apply {
                 adapter?.convert(outVar, cursorVar, scope)
                 transactionWrapper?.commitTransaction()
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
index cd84015..e4e77d2 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/LiveDataQueryResultBinder.kt
@@ -48,7 +48,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
             createRunQueryAndReturnStatements(
@@ -56,7 +57,8 @@
                 roomSQLiteQueryVar = roomSQLiteQueryVar,
                 inTransaction = inTransaction,
                 dbField = dbField,
-                scope = scope
+                scope = scope,
+                cancellationSignalVar = "null" // LiveData can't be cancelled
             )
         }.apply {
             if (canReleaseQuery) {
@@ -83,7 +85,8 @@
         observerField: FieldSpec,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignal: String
     ): MethodSpec {
         return MethodSpec.methodBuilder("compute").apply {
             addAnnotation(Override::class.java)
@@ -104,7 +107,8 @@
                 roomSQLiteQueryVar = roomSQLiteQueryVar,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = scope
+                scope = scope,
+                cancellationSignalVar = cancellationSignal
             )
         }.build()
     }
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder.kt
index 8ddf99f..1efee13 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/PositionalDataSourceQueryResultBinder.kt
@@ -43,7 +43,8 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         // first comma for table names comes from the string since it might be empty in which case
         // we don't need a comma. If list is empty, this prevents generating bad code (it is still
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
index d3d6d8c..faa3854 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/QueryResultBinder.kt
@@ -36,6 +36,7 @@
         canReleaseQuery: Boolean, // false if query is provided by the user
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String // "null" if cancellation isn't supported
     )
 }
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxCallableQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxCallableQueryResultBinder.kt
index 71a4a2c..fc454fe 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxCallableQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxCallableQueryResultBinder.kt
@@ -46,14 +46,16 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val callable = CallableTypeSpecBuilder(typeArg.typeName()) {
             fillInCallMethod(
                 roomSQLiteQueryVar = roomSQLiteQueryVar,
                 dbField = dbField,
                 inTransaction = inTransaction,
-                scope = scope)
+                scope = scope,
+                cancellationSignalVar = cancellationSignalVar)
         }.apply {
             if (canReleaseQuery) {
                 addMethod(createFinalizeMethod(roomSQLiteQueryVar))
@@ -72,7 +74,8 @@
         roomSQLiteQueryVar: String,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val adapterScope = scope.fork()
         val transactionWrapper = if (inTransaction) {
@@ -84,13 +87,14 @@
         val shouldCopyCursor = adapter?.shouldCopyCursor() == true
         val outVar = scope.getTmpVar("_result")
         val cursorVar = scope.getTmpVar("_cursor")
-        addStatement("final $T $L = $T.query($N, $L, $L)",
+        addStatement("final $T $L = $T.query($N, $L, $L, $L)",
                 AndroidTypeNames.CURSOR,
                 cursorVar,
                 RoomTypeNames.DB_UTIL,
                 dbField,
                 roomSQLiteQueryVar,
-                if (shouldCopyCursor) "true" else "false")
+                if (shouldCopyCursor) "true" else "false",
+                cancellationSignalVar)
         beginControlFlow("try").apply {
             adapter?.convert(outVar, cursorVar, adapterScope)
             addCode(adapterScope.generate())
diff --git a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
index d52e804..f042089 100644
--- a/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/solver/query/result/RxQueryResultBinder.kt
@@ -43,14 +43,16 @@
         canReleaseQuery: Boolean,
         dbField: FieldSpec,
         inTransaction: Boolean,
-        scope: CodeGenScope
+        scope: CodeGenScope,
+        cancellationSignalVar: String
     ) {
         val callableImpl = CallableTypeSpecBuilder(typeArg.typeName()) {
             createRunQueryAndReturnStatements(builder = this,
                 roomSQLiteQueryVar = roomSQLiteQueryVar,
                 inTransaction = inTransaction,
                 dbField = dbField,
-                scope = scope)
+                scope = scope,
+                cancellationSignalVar = cancellationSignalVar)
         }.apply {
             if (canReleaseQuery) {
                 addMethod(createFinalizeMethod(roomSQLiteQueryVar))
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
index 5d9dc90..d3a2106 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/DaoWriter.kt
@@ -273,7 +273,8 @@
                         canReleaseQuery = shouldReleaseQuery,
                         dbField = dbField,
                         inTransaction = method.inTransaction,
-                        scope = scope)
+                        scope = scope,
+                        cancellationSignalVar = "null")
             }
             addCode(scope.builder().build())
         }.build()
@@ -424,7 +425,8 @@
                 canReleaseQuery = true,
                 dbField = dbField,
                 inTransaction = method.inTransaction,
-                scope = scope)
+                scope = scope,
+                cancellationSignalVar = "null")
         return scope.builder().build()
     }
 
diff --git a/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt b/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
index ae44b51..b2d3410 100644
--- a/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
+++ b/room/compiler/src/main/kotlin/androidx/room/writer/RelationCollectorMethodWriter.kt
@@ -133,13 +133,14 @@
             val shouldCopyCursor = collector.rowAdapter.let {
                 it is PojoRowAdapter && it.relationCollectors.isNotEmpty()
             }
-            addStatement("final $T $L = $T.query($N, $L, $L)",
+            addStatement("final $T $L = $T.query($N, $L, $L, $L)",
                     AndroidTypeNames.CURSOR,
                     cursorVar,
                     RoomTypeNames.DB_UTIL,
                     DaoWriter.dbField,
                     stmtVar,
-                    if (shouldCopyCursor) "true" else "false")
+                    if (shouldCopyCursor) "true" else "false",
+                    "null")
 
             beginControlFlow("try").apply {
                 if (relation.junction != null) {
diff --git a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
index b3399a9..72e3734 100644
--- a/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
+++ b/room/compiler/src/test/data/daoWriter/output/ComplexDao.java
@@ -47,7 +47,7 @@
         int _argIndex = 1;
         _statement.bindLong(_argIndex, id);
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfFullName = CursorUtil.getColumnIndexOrThrow(_cursor, "fullName");
             final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
@@ -73,7 +73,7 @@
         int _argIndex = 1;
         _statement.bindLong(_argIndex, id);
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
             final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -115,7 +115,7 @@
             _statement.bindString(_argIndex, lastName);
         }
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
             final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -158,7 +158,7 @@
             _argIndex ++;
         }
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
             final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -190,7 +190,7 @@
         int _argIndex = 1;
         _statement.bindLong(_argIndex, id);
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _result;
             if(_cursor.moveToFirst()) {
@@ -221,7 +221,7 @@
             _argIndex ++;
         }
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int[] _result = new int[_cursor.getCount()];
             int _index = 0;
@@ -258,7 +258,7 @@
             _argIndex ++;
         }
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final List<Integer> _result = new ArrayList<Integer>(_cursor.getCount());
             while(_cursor.moveToNext()) {
@@ -286,7 +286,7 @@
         return __db.getInvalidationTracker().createLiveData(new String[]{"user"}, false, new Callable<User>() {
             @Override
             public User call() throws Exception {
-                final Cursor _cursor = DBUtil.query(__db, _statement, false);
+                final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
                 try {
                     final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
                     final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -337,7 +337,7 @@
         return __db.getInvalidationTracker().createLiveData(new String[]{"user"}, false, new Callable<List<User>>() {
             @Override
             public List<User> call() throws Exception {
-                final Cursor _cursor = DBUtil.query(__db, _statement, false);
+                final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
                 try {
                     final int _cursorIndexOfUid = CursorUtil.getColumnIndexOrThrow(_cursor, "uid");
                     final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -405,7 +405,7 @@
             _argIndex ++;
         }
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final List<Integer> _result = new ArrayList<Integer>(_cursor.getCount());
             while(_cursor.moveToNext()) {
@@ -429,7 +429,7 @@
         final String _sql = "SELECT * FROM Child1";
         final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
             final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
@@ -465,7 +465,7 @@
         final String _sql = "SELECT * FROM Child2";
         final RoomSQLiteQuery _statement = RoomSQLiteQuery.acquire(_sql, 0);
         __db.assertNotSuspendingTransaction();
-        final Cursor _cursor = DBUtil.query(__db, _statement, false);
+        final Cursor _cursor = DBUtil.query(__db, _statement, false, null);
         try {
             final int _cursorIndexOfId = CursorUtil.getColumnIndexOrThrow(_cursor, "id");
             final int _cursorIndexOfName = CursorUtil.getColumnIndexOrThrow(_cursor, "name");
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
index a685e40..71d2a72f 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/FieldProcessorTest.kt
@@ -435,7 +435,7 @@
                 .processedWith(TestProcessor.builder()
                         .forAnnotations(androidx.room.Entity::class)
                         .nextRunHandler { invocation ->
-                            val (owner, field) = invocation.roundEnv
+                            val (owner, fieldElement) = invocation.roundEnv
                                     .getElementsAnnotatedWith(Entity::class.java)
                                     .map {
                                         Pair(it, invocation.processingEnv.elementUtils
@@ -451,9 +451,12 @@
                             val parser = FieldProcessor(
                                     baseContext = entityContext,
                                     containing = MoreTypes.asDeclared(owner.asType()),
-                                    element = field!!,
+                                    element = fieldElement!!,
                                     bindingScope = FieldProcessor.BindingScope.TWO_WAY,
-                                    fieldParent = null)
+                                    fieldParent = null,
+                                    onBindingError = { field, errorMsg ->
+                                        invocation.context.logger.e(field.element, errorMsg) }
+                                    )
                             handler(parser.process(), invocation)
                             true
                         }
diff --git a/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt b/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
index 4dd648a..e51aad4 100644
--- a/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
+++ b/room/compiler/src/test/kotlin/androidx/room/processor/PojoProcessorTest.kt
@@ -1364,6 +1364,8 @@
                 """
                 package foo.bar;
                 import androidx.room.*;
+
+                @Entity(ignoredColumns = {"bar"})
                 public class ${MY_POJO.simpleName()} {
                     public String foo;
                     public String bar;
@@ -1372,7 +1374,6 @@
             val pojo = PojoProcessor.createFor(context = invocation.context,
                     element = invocation.typeElement(MY_POJO.toString()),
                     bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
-                    ignoredColumns = setOf("bar"),
                     parent = null).process()
             assertThat(pojo.fields.find { it.name == "foo" }, notNullValue())
             assertThat(pojo.fields.find { it.name == "bar" }, nullValue())
@@ -1385,6 +1386,8 @@
             """
                 package foo.bar;
                 import androidx.room.*;
+
+                @Entity(ignoredColumns = {"bar"})
                 public class ${MY_POJO.simpleName()} {
                     private final String foo;
                     private final String bar;
@@ -1402,8 +1405,7 @@
             val pojo = PojoProcessor.createFor(context = invocation.context,
                 element = invocation.typeElement(MY_POJO.toString()),
                 bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
-                ignoredColumns = setOf("bar"),
-                parent = null).process()
+                    parent = null).process()
             assertThat(pojo.fields.find { it.name == "foo" }, notNullValue())
             assertThat(pojo.fields.find { it.name == "bar" }, nullValue())
         }.compilesWithoutError()
@@ -1415,6 +1417,8 @@
             """
                 package foo.bar;
                 import androidx.room.*;
+
+                @Entity(ignoredColumns = {"bar"})
                 public class ${MY_POJO.simpleName()} {
                     private String foo;
                     private String bar;
@@ -1431,7 +1435,6 @@
             val pojo = PojoProcessor.createFor(context = invocation.context,
                 element = invocation.typeElement(MY_POJO.toString()),
                 bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
-                ignoredColumns = setOf("bar"),
                 parent = null).process()
             assertThat(pojo.fields.find { it.name == "foo" }, notNullValue())
             assertThat(pojo.fields.find { it.name == "bar" }, nullValue())
@@ -1444,6 +1447,8 @@
                 """
                 package foo.bar;
                 import androidx.room.*;
+
+                @Entity(ignoredColumns = {"my_bar"})
                 public class ${MY_POJO.simpleName()} {
                     public String foo;
                     @ColumnInfo(name = "my_bar")
@@ -1453,7 +1458,6 @@
             val pojo = PojoProcessor.createFor(context = invocation.context,
                     element = invocation.typeElement(MY_POJO.toString()),
                     bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
-                    ignoredColumns = setOf("my_bar"),
                     parent = null).process()
             assertThat(pojo.fields.find { it.name == "foo" }, notNullValue())
             assertThat(pojo.fields.find { it.name == "bar" }, nullValue())
@@ -1466,6 +1470,8 @@
                 """
                 package foo.bar;
                 import androidx.room.*;
+
+                @Entity(ignoredColumns = {"no_such_column"})
                 public class ${MY_POJO.simpleName()} {
                     public String foo;
                     public String bar;
@@ -1474,7 +1480,6 @@
             val pojo = PojoProcessor.createFor(context = invocation.context,
                     element = invocation.typeElement(MY_POJO.toString()),
                     bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
-                    ignoredColumns = setOf("no_such_column"),
                     parent = null).process()
             assertThat(pojo.fields.find { it.name == "foo" }, notNullValue())
             assertThat(pojo.fields.find { it.name == "bar" }, notNullValue())
@@ -1482,6 +1487,132 @@
                 ProcessorErrors.missingIgnoredColumns(listOf("no_such_column")))
     }
 
+    @Test
+    fun noSetter_scopeBindStmt() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public String getFoo() { return foo; }
+                    public String getBar() { return bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.BIND_TO_STMT,
+                parent = null).process()
+        }.compilesWithoutError()
+    }
+
+    @Test
+    fun noSetter_scopeTwoWay() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public String getFoo() { return foo; }
+                    public String getBar() { return bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.TWO_WAY,
+                parent = null).process()
+        }.failsToCompile().withErrorContaining("Cannot find setter for field.")
+    }
+
+    @Test
+    fun noSetter_scopeReadFromCursor() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public String getFoo() { return foo; }
+                    public String getBar() { return bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+                parent = null).process()
+        }.failsToCompile().withErrorContaining("Cannot find setter for field.")
+    }
+
+    @Test
+    fun noGetter_scopeBindStmt() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public void setFoo(String foo) { this.foo = foo; }
+                    public void setBar(String bar) { this.bar = bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.BIND_TO_STMT,
+                parent = null).process()
+        }.failsToCompile().withErrorContaining("Cannot find getter for field.")
+    }
+
+    @Test
+    fun noGetter_scopeTwoWay() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public void setFoo(String foo) { this.foo = foo; }
+                    public void setBar(String bar) { this.bar = bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.TWO_WAY,
+                parent = null).process()
+        }.failsToCompile().withErrorContaining("Cannot find getter for field.")
+    }
+
+    @Test
+    fun noGetter_scopeReadCursor() {
+        simpleRun(
+            """
+                package foo.bar;
+                import androidx.room.*;
+                public class ${MY_POJO.simpleName()} {
+                    private String foo;
+                    private String bar;
+
+                    public void setFoo(String foo) { this.foo = foo; }
+                    public void setBar(String bar) { this.bar = bar; }
+                }
+                """.toJFO(MY_POJO.toString())) { invocation ->
+            PojoProcessor.createFor(context = invocation.context,
+                element = invocation.typeElement(MY_POJO.toString()),
+                bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+                parent = null).process()
+        }.compilesWithoutError()
+    }
+
     private fun singleRun(
         code: String,
         vararg jfos: JavaFileObject,
@@ -1523,7 +1654,7 @@
             handler.invoke(
                 PojoProcessor.createFor(context = invocation.context,
                         element = invocation.typeElement(MY_POJO.toString()),
-                        bindingScope = FieldProcessor.BindingScope.READ_FROM_CURSOR,
+                        bindingScope = FieldProcessor.BindingScope.TWO_WAY,
                         parent = null).process(),
                 invocation
             )
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
index 6cadb2f..8dae07b0 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/dao/BooksDao.kt
@@ -33,6 +33,7 @@
 import androidx.room.integration.kotlintestapp.vo.BookWithPublisher
 import androidx.room.integration.kotlintestapp.vo.DateConverter
 import androidx.room.integration.kotlintestapp.vo.Lang
+import androidx.room.integration.kotlintestapp.vo.MiniBook
 import androidx.room.integration.kotlintestapp.vo.Publisher
 import androidx.room.integration.kotlintestapp.vo.PublisherWithBookSales
 import androidx.room.integration.kotlintestapp.vo.PublisherWithBooks
@@ -116,6 +117,9 @@
     @Insert
     fun addBooks(vararg books: Book)
 
+    @Insert(entity = Book::class)
+    fun addMiniBook(miniBook: MiniBook)
+
     @Insert
     fun addBookAuthors(vararg bookAuthors: BookAuthor)
 
diff --git a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
index 6d7b7a7..21292d5 100644
--- a/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/Book.kt
@@ -16,6 +16,7 @@
 
 package androidx.room.integration.kotlintestapp.vo
 
+import androidx.room.ColumnInfo
 import androidx.room.Entity
 import androidx.room.ForeignKey
 import androidx.room.PrimaryKey
@@ -30,7 +31,9 @@
     @PrimaryKey val bookId: String,
     val title: String,
     val bookPublisherId: String,
+    @ColumnInfo(defaultValue = "0")
     @field:TypeConverters(Lang::class)
     val languages: Set<Lang>,
+    @ColumnInfo(defaultValue = "0")
     val salesCnt: Int
 )
diff --git a/compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt
similarity index 75%
copy from compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt
copy to room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt
index 601fbf1..42d013a 100644
--- a/compose/compose-runtime/src/main/java/androidx/compose/JoinedKey.kt
+++ b/room/integration-tests/kotlintestapp/src/androidTest/java/androidx/room/integration/kotlintestapp/vo/MiniBook.kt
@@ -14,9 +14,12 @@
  * limitations under the License.
  */
 
-package androidx.compose
+package androidx.room.integration.kotlintestapp.vo
 
-internal data class JoinedKey(
-    @JvmField val left: Any?,
-    @JvmField val right: Any?
+import androidx.room.PrimaryKey
+
+data class MiniBook(
+    @PrimaryKey val bookId: String,
+    val title: String,
+    val bookPublisherId: String
 )
\ No newline at end of file
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/TestDatabase.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/TestDatabase.java
index f32c5cc..8e36cd8 100644
--- a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/TestDatabase.java
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/TestDatabase.java
@@ -22,6 +22,7 @@
 import androidx.room.TypeConverters;
 import androidx.room.integration.testapp.dao.BlobEntityDao;
 import androidx.room.integration.testapp.dao.FunnyNamedDao;
+import androidx.room.integration.testapp.dao.LibraryItemDao;
 import androidx.room.integration.testapp.dao.PetCoupleDao;
 import androidx.room.integration.testapp.dao.PetDao;
 import androidx.room.integration.testapp.dao.ProductDao;
@@ -45,6 +46,7 @@
 import androidx.room.integration.testapp.vo.PetWithUser;
 import androidx.room.integration.testapp.vo.Product;
 import androidx.room.integration.testapp.vo.Robot;
+import androidx.room.integration.testapp.vo.RoomLibraryPojo;
 import androidx.room.integration.testapp.vo.School;
 import androidx.room.integration.testapp.vo.Toy;
 import androidx.room.integration.testapp.vo.User;
@@ -57,7 +59,7 @@
 
 @Database(entities = {User.class, Pet.class, School.class, PetCouple.class, Toy.class,
         BlobEntity.class, Product.class, FunnyNamedEntity.class, House.class,
-        FriendsJunction.class, Hivemind.class, Robot.class},
+        FriendsJunction.class, Hivemind.class, Robot.class, RoomLibraryPojo.class},
         views = {PetWithUser.class},
         version = 1, exportSchema = false)
 @TypeConverters(TestDatabase.Converters.class)
@@ -76,6 +78,7 @@
     public abstract RawDao getRawDao();
     public abstract UserHouseDao getUserHouseDao();
     public abstract RobotsDao getRobotsDao();
+    public abstract LibraryItemDao getLibraryItemDao();
 
     @SuppressWarnings("unused")
     public static class Converters {
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/LibraryItemDao.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/LibraryItemDao.java
new file mode 100644
index 0000000..5f9bcb0
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/dao/LibraryItemDao.java
@@ -0,0 +1,44 @@
+/*
+ * 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.dao;
+
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.integration.testapp.vo.RoomLibraryPojo;
+
+import java.util.List;
+
+@Dao
+public interface LibraryItemDao {
+
+    @Query("SELECT mId, mName, mPrice FROM library_items")
+    List<RoomLibraryPojo> getAll();
+
+    @Query("SELECT mId, mName, mPrice FROM library_items WHERE mId IN (:ids)")
+    List<RoomLibraryPojo> loadAllByIds(int[] ids);
+
+    @Query("SELECT mId, mName, mPrice FROM library_items WHERE mName LIKE :name LIMIT 1")
+    RoomLibraryPojo findByName(String name);
+
+    @Insert
+    void insertAll(RoomLibraryPojo... item);
+
+    @Delete
+    void delete(RoomLibraryPojo item);
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/LibraryPojo.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/LibraryPojo.java
new file mode 100644
index 0000000..c9852f7
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/LibraryPojo.java
@@ -0,0 +1,64 @@
+/*
+ * 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.vo;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * A unmodifiable POJO that comes from a library.
+ */
+public class LibraryPojo {
+
+    private final JSONObject mJsonObj = new JSONObject();
+
+    public Long getPrice() {
+        return mJsonObj.optLong("price");
+    }
+
+    public Long getId() {
+        return mJsonObj.optLong("id");
+    }
+
+    public String getName() {
+        return mJsonObj.optString("name");
+    }
+
+    public void setPrice(Long price) {
+        try {
+            mJsonObj.put("price", price);
+        } catch (JSONException e) {
+            // ignored
+        }
+    }
+
+    public void setId(long id) {
+        try {
+            mJsonObj.put("id", id);
+        } catch (JSONException e) {
+            // ignored
+        }
+    }
+
+    public void setName(String name) {
+        try {
+            mJsonObj.put("name", name);
+        } catch (JSONException e) {
+            // ignored
+        }
+    }
+}
diff --git a/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/RoomLibraryPojo.java b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/RoomLibraryPojo.java
new file mode 100644
index 0000000..fc02ba4
--- /dev/null
+++ b/room/integration-tests/testapp/src/androidTest/java/androidx/room/integration/testapp/vo/RoomLibraryPojo.java
@@ -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.room.integration.testapp.vo;
+
+import androidx.room.Entity;
+import androidx.room.PrimaryKey;
+
+/**
+ * A Room POJO is just wraps a POJO provided by some library.
+ */
+@Entity(tableName = "library_items", ignoredColumns = "mJsonObj")
+public class RoomLibraryPojo extends LibraryPojo {
+
+    @PrimaryKey
+    private long mId;
+    private String mName;
+    private Long mPrice;
+
+    public RoomLibraryPojo(long id, String name, Long price) {
+        setId(id);
+        setName(name);
+        setPrice(price);
+    }
+
+}
diff --git a/room/runtime/api/2.2.0-alpha02.txt b/room/runtime/api/2.2.0-alpha02.txt
index 7c34026..1d210e5 100644
--- a/room/runtime/api/2.2.0-alpha02.txt
+++ b/room/runtime/api/2.2.0-alpha02.txt
@@ -56,8 +56,9 @@
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
     method public boolean isOpen();
-    method public android.database.Cursor! query(String!, Object![]?);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
+    method public android.database.Cursor query(String, Object![]?);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method public void runInTransaction(Runnable);
     method public <V> V! runInTransaction(java.util.concurrent.Callable<V!>);
     method @Deprecated public void setTransactionSuccessful();
diff --git a/room/runtime/api/current.txt b/room/runtime/api/current.txt
index 7c34026..1d210e5 100644
--- a/room/runtime/api/current.txt
+++ b/room/runtime/api/current.txt
@@ -56,8 +56,9 @@
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
     method public boolean isOpen();
-    method public android.database.Cursor! query(String!, Object![]?);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
+    method public android.database.Cursor query(String, Object![]?);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method public void runInTransaction(Runnable);
     method public <V> V! runInTransaction(java.util.concurrent.Callable<V!>);
     method @Deprecated public void setTransactionSuccessful();
diff --git a/room/runtime/api/restricted_2.2.0-alpha02.txt b/room/runtime/api/restricted_2.2.0-alpha02.txt
index 170506d..8e744d7 100644
--- a/room/runtime/api/restricted_2.2.0-alpha02.txt
+++ b/room/runtime/api/restricted_2.2.0-alpha02.txt
@@ -95,8 +95,9 @@
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
     method public boolean isOpen();
-    method public android.database.Cursor! query(String!, Object![]?);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
+    method public android.database.Cursor query(String, Object![]?);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method public void runInTransaction(Runnable);
     method public <V> V! runInTransaction(java.util.concurrent.Callable<V!>);
     method @Deprecated public void setTransactionSuccessful();
@@ -233,7 +234,8 @@
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DBUtil {
     method public static void dropFtsSyncTriggers(androidx.sqlite.db.SupportSQLiteDatabase!);
-    method public static android.database.Cursor query(androidx.room.RoomDatabase!, androidx.sqlite.db.SupportSQLiteQuery!, boolean);
+    method @Deprecated public static android.database.Cursor query(androidx.room.RoomDatabase!, androidx.sqlite.db.SupportSQLiteQuery!, boolean);
+    method public static android.database.Cursor query(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, android.os.CancellationSignal?);
     method public static int readVersion(java.io.File) throws java.io.IOException;
   }
 
diff --git a/room/runtime/api/restricted_current.txt b/room/runtime/api/restricted_current.txt
index 170506d..8e744d7 100644
--- a/room/runtime/api/restricted_current.txt
+++ b/room/runtime/api/restricted_current.txt
@@ -95,8 +95,9 @@
     method @CallSuper public void init(androidx.room.DatabaseConfiguration);
     method protected void internalInitInvalidationTracker(androidx.sqlite.db.SupportSQLiteDatabase);
     method public boolean isOpen();
-    method public android.database.Cursor! query(String!, Object![]?);
-    method public android.database.Cursor! query(androidx.sqlite.db.SupportSQLiteQuery!);
+    method public android.database.Cursor query(String, Object![]?);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery);
+    method public android.database.Cursor query(androidx.sqlite.db.SupportSQLiteQuery, android.os.CancellationSignal?);
     method public void runInTransaction(Runnable);
     method public <V> V! runInTransaction(java.util.concurrent.Callable<V!>);
     method @Deprecated public void setTransactionSuccessful();
@@ -233,7 +234,8 @@
 
   @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public class DBUtil {
     method public static void dropFtsSyncTriggers(androidx.sqlite.db.SupportSQLiteDatabase!);
-    method public static android.database.Cursor query(androidx.room.RoomDatabase!, androidx.sqlite.db.SupportSQLiteQuery!, boolean);
+    method @Deprecated public static android.database.Cursor query(androidx.room.RoomDatabase!, androidx.sqlite.db.SupportSQLiteQuery!, boolean);
+    method public static android.database.Cursor query(androidx.room.RoomDatabase, androidx.sqlite.db.SupportSQLiteQuery, boolean, android.os.CancellationSignal?);
     method public static int readVersion(java.io.File) throws java.io.IOException;
   }
 
diff --git a/room/runtime/src/main/java/androidx/room/RoomDatabase.java b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
index 2e88a28..b038c89 100644
--- a/room/runtime/src/main/java/androidx/room/RoomDatabase.java
+++ b/room/runtime/src/main/java/androidx/room/RoomDatabase.java
@@ -21,6 +21,7 @@
 import android.content.Context;
 import android.database.Cursor;
 import android.os.Build;
+import android.os.CancellationSignal;
 import android.os.Looper;
 import android.util.Log;
 
@@ -294,7 +295,8 @@
      * @param args  The bind arguments for the placeholders in the query
      * @return A Cursor obtained by running the given query in the Room database.
      */
-    public Cursor query(String query, @Nullable Object[] args) {
+    @NonNull
+    public Cursor query(@NonNull String query, @Nullable Object[] args) {
         return mOpenHelper.getWritableDatabase().query(new SimpleSQLiteQuery(query, args));
     }
 
@@ -304,10 +306,27 @@
      * @param query The Query which includes the SQL and a bind callback for bind arguments.
      * @return Result of the query.
      */
-    public Cursor query(SupportSQLiteQuery query) {
+    @NonNull
+    public Cursor query(@NonNull SupportSQLiteQuery query) {
+        return query(query, null);
+    }
+
+    /**
+     * Wrapper for {@link SupportSQLiteDatabase#query(SupportSQLiteQuery)}.
+     *
+     * @param query The Query which includes the SQL and a bind callback for bind arguments.
+     * @param signal The cancellation signal to be attached to the query.
+     * @return Result of the query.
+     */
+    @NonNull
+    public Cursor query(@NonNull SupportSQLiteQuery query, @Nullable CancellationSignal signal) {
         assertNotMainThread();
         assertNotSuspendingTransaction();
-        return mOpenHelper.getWritableDatabase().query(query);
+        if (signal != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+            return mOpenHelper.getWritableDatabase().query(query, signal);
+        } else {
+            return mOpenHelper.getWritableDatabase().query(query);
+        }
     }
 
     /**
diff --git a/room/runtime/src/main/java/androidx/room/util/DBUtil.java b/room/runtime/src/main/java/androidx/room/util/DBUtil.java
index f7afd26..f802e6d 100644
--- a/room/runtime/src/main/java/androidx/room/util/DBUtil.java
+++ b/room/runtime/src/main/java/androidx/room/util/DBUtil.java
@@ -19,8 +19,10 @@
 import android.database.AbstractWindowedCursor;
 import android.database.Cursor;
 import android.os.Build;
+import android.os.CancellationSignal;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.RestrictTo;
 import androidx.room.RoomDatabase;
 import androidx.sqlite.db.SupportSQLiteDatabase;
@@ -53,10 +55,32 @@
      * @param sqLiteQuery The query to perform.
      * @param maybeCopy   True if the result cursor should maybe be copied, false otherwise.
      * @return Result of the query.
+     *
+     * @deprecated This is only used in the generated code and shouldn't be called directly.
      */
+    @Deprecated
     @NonNull
     public static Cursor query(RoomDatabase db, SupportSQLiteQuery sqLiteQuery, boolean maybeCopy) {
-        final Cursor cursor = db.query(sqLiteQuery);
+        return query(db, sqLiteQuery, maybeCopy, null);
+    }
+
+    /**
+     * Performs the SQLiteQuery on the given database.
+     * <p>
+     * This util method encapsulates copying the cursor if the {@code maybeCopy} parameter is
+     * {@code true} and either the api level is below a certain threshold or the full result of the
+     * query does not fit in a single window.
+     *
+     * @param db          The database to perform the query on.
+     * @param sqLiteQuery The query to perform.
+     * @param maybeCopy   True if the result cursor should maybe be copied, false otherwise.
+     * @param signal      The cancellation signal to be attached to the query.
+     * @return Result of the query.
+     */
+    @NonNull
+    public static Cursor query(@NonNull RoomDatabase db, @NonNull SupportSQLiteQuery sqLiteQuery,
+            boolean maybeCopy, @Nullable CancellationSignal signal) {
+        final Cursor cursor = db.query(sqLiteQuery, signal);
         if (maybeCopy && cursor instanceof AbstractWindowedCursor) {
             AbstractWindowedCursor windowedCursor = (AbstractWindowedCursor) cursor;
             int rowsInCursor = windowedCursor.getCount(); // Should fill the window.
diff --git a/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java b/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
index f3caf34..f5026e1 100644
--- a/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
+++ b/room/runtime/src/test/java/androidx/room/InvalidationTrackerTest.java
@@ -187,7 +187,8 @@
 
     @Test
     public void refreshCheckTasks() throws Exception {
-        when(mRoomDatabase.query(any(SimpleSQLiteQuery.class))).thenReturn(mock(Cursor.class));
+        when(mRoomDatabase.query(any(SimpleSQLiteQuery.class)))
+                .thenReturn(mock(Cursor.class));
         mTracker.refreshVersionsAsync();
         mTracker.refreshVersionsAsync();
         verify(mTaskExecutorRule.getTaskExecutor()).executeOnDiskIO(mTracker.mRefreshRunnable);
diff --git a/sharetarget/build.gradle b/sharetarget/build.gradle
index cc27624..b750a70 100644
--- a/sharetarget/build.gradle
+++ b/sharetarget/build.gradle
@@ -25,7 +25,7 @@
 }
 
 dependencies {
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     implementation("androidx.collection:collection:1.0.0")
     api(GUAVA_LISTENABLE_FUTURE)
     implementation("androidx.concurrent:concurrent-futures:1.0.0-alpha02")
diff --git a/slices/builders/build.gradle b/slices/builders/build.gradle
index 63bbe8d..914633c 100644
--- a/slices/builders/build.gradle
+++ b/slices/builders/build.gradle
@@ -28,7 +28,7 @@
     implementation(project(":slice-core"))
     api(project(":remotecallback"))
     implementation "androidx.annotation:annotation:1.1.0"
-    implementation "androidx.core:core:1.1.0"
+    implementation "androidx.core:core:1.1.0-rc01"
     implementation project(':collection:collection')
 }
 
diff --git a/slidingpanelayout/build.gradle b/slidingpanelayout/build.gradle
index 7738665..b9732d5 100644
--- a/slidingpanelayout/build.gradle
+++ b/slidingpanelayout/build.gradle
@@ -9,7 +9,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     api(project(":customview"))
 }
 
diff --git a/swiperefreshlayout/build.gradle b/swiperefreshlayout/build.gradle
index 46c3da4..1309851 100644
--- a/swiperefreshlayout/build.gradle
+++ b/swiperefreshlayout/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
     api("androidx.interpolator:interpolator:1.0.0")
 
     androidTestImplementation(JUNIT)
diff --git a/textclassifier/build.gradle b/textclassifier/build.gradle
index 92508eb..d2cd121 100644
--- a/textclassifier/build.gradle
+++ b/textclassifier/build.gradle
@@ -13,7 +13,7 @@
     api("androidx.annotation:annotation:1.1.0")
     implementation("androidx.collection:collection:1.0.0")
     // TODO: change to 1.1.0-alpha04 after release
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/tv-provider/build.gradle b/tv-provider/build.gradle
index 902b0d5..b4cbc11 100644
--- a/tv-provider/build.gradle
+++ b/tv-provider/build.gradle
@@ -10,7 +10,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
     androidTestImplementation(ANDROIDX_TEST_CORE)
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/TestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/TestCase.kt
index 7004525..c5297e2 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/TestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/TestCase.kt
@@ -25,10 +25,14 @@
 import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
+import androidx.compose.Children
+import androidx.compose.Composable
 import androidx.compose.CompositionContext
+import androidx.compose.FrameManager
 import androidx.ui.core.AndroidCraneView
 import androidx.ui.core.ComponentNode
 import androidx.ui.core.DrawNode
+import androidx.ui.core.setContent
 import com.google.common.truth.Truth
 import org.junit.Assert
 
@@ -41,7 +45,8 @@
     private val renderNode = RenderNode("test")
     private var canvas: Canvas? = null
 
-    var view: ViewGroup
+    lateinit var view: ViewGroup
+        private set
 
     init {
         val displayMetrics = DisplayMetrics()
@@ -51,10 +56,13 @@
 
         screenWithSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST)
         screenHeightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)
-        view = activity.findViewById(android.R.id.content)
     }
 
-    abstract fun setupContent(activity: Activity)
+    fun setupContent(activity: Activity) {
+        view = setupContentInternal(activity)
+    }
+
+    protected abstract fun setupContentInternal(activity: Activity): ViewGroup
 
     /**
      * Runs all the steps leading into drawing first pixels. Useful to get into the initial state
@@ -122,13 +130,28 @@
 
 abstract class AndroidTestCase(
     activity: Activity
-) : TestCase(activity)
+) : TestCase(activity) {
+
+    override fun setupContentInternal(activity: Activity) = createViewContent(activity)
+        .apply { activity.setContentView(this) }
+
+    abstract fun createViewContent(activity: Activity): ViewGroup
+}
 
 abstract class ComposeTestCase(
     activity: Activity
 ) : TestCase(activity) {
 
     lateinit var compositionContext: CompositionContext
+        private set
+
+    override fun setupContentInternal(activity: Activity): ViewGroup {
+        compositionContext = setComposeContent(activity)
+        FrameManager.nextFrame()
+        return findComposeView()!!
+    }
+
+    abstract fun setComposeContent(activity: Activity): CompositionContext
 }
 
 /**
@@ -213,4 +236,33 @@
     val imageView = ImageView(activity)
     imageView.setImageBitmap(Bitmap.createBitmap(picture))
     activity.setContentView(imageView)
+}
+
+/**
+ * Returns the first found [AndroidCraneView] in the content view hierarchy:
+ *
+ *     override fun setupContent(activity: Activity) {
+ *         activity.setContent { ... }
+ *         view = findComposeView()!!
+ *         FrameManager.nextFrame()
+ *     }
+ */
+fun ComposeTestCase.findComposeView(): AndroidCraneView? {
+    return findComposeView(activity.findViewById(android.R.id.content))
+}
+
+private fun findComposeView(view: View): AndroidCraneView? {
+    if (view is AndroidCraneView) {
+        return view
+    }
+
+    if (view is ViewGroup) {
+        for (i in 0 until view.childCount) {
+            val composeView = findComposeView(view.getChildAt(i))
+            if (composeView != null) {
+                return composeView
+            }
+        }
+    }
+    return null
 }
\ No newline at end of file
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/CheckboxesInRowsTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/CheckboxesInRowsTestCase.kt
index fa19488..dd5abdd 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/CheckboxesInRowsTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/CheckboxesInRowsTestCase.kt
@@ -17,8 +17,10 @@
 package androidx.ui.test.cases
 
 import android.app.Activity
+import android.view.View
 import androidx.compose.composer
 import androidx.compose.Composable
+import androidx.compose.CompositionContext
 import androidx.compose.FrameManager
 import androidx.compose.State
 import androidx.compose.state
@@ -34,6 +36,7 @@
 import androidx.ui.material.surface.Surface
 import androidx.ui.test.ComposeTestCase
 import androidx.ui.test.ToggleableTestCase
+import androidx.ui.test.findComposeView
 
 /**
  * Test case that puts the given amount of checkboxes into a column of rows and makes changes by
@@ -46,29 +49,26 @@
 
     private val states = mutableListOf<State<Boolean>>()
 
-    override fun setupContent(activity: Activity) {
-        compositionContext = activity.setContent {
-            MaterialTheme {
-                Surface {
-                    Column {
-                        repeat(amountOfCheckboxes) {
-                            FlexRow {
-                                inflexible {
-                                    Text(text = "Check Me!")
-                                }
-                                expanded(1f) {
-                                    Align(alignment = Alignment.CenterRight) {
-                                        CheckboxWithState()
-                                    }
+    override fun setComposeContent(activity: Activity) = activity.setContent {
+        MaterialTheme {
+            Surface {
+                Column {
+                    repeat(amountOfCheckboxes) {
+                        FlexRow {
+                            inflexible {
+                                Text(text = "Check Me!")
+                            }
+                            expanded(1f) {
+                                Align(alignment = Alignment.CenterRight) {
+                                    CheckboxWithState()
                                 }
                             }
                         }
                     }
                 }
             }
-        }!!
-        FrameManager.nextFrame()
-    }
+        }
+    }!!
 
     override fun toggleState() {
         val state = states.first()
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnSharedModelTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnSharedModelTestCase.kt
index d33c624..6660cf6 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnSharedModelTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnSharedModelTestCase.kt
@@ -17,6 +17,8 @@
 package androidx.ui.test.cases
 
 import android.app.Activity
+import androidx.compose.Composable
+import androidx.compose.CompositionContext
 import androidx.compose.composer
 import androidx.compose.FrameManager
 import androidx.compose.Model
@@ -46,22 +48,19 @@
 
     private val model = RectanglesInColumnTestCaseColorModel(Color.Black)
 
-    override fun setupContent(activity: Activity) {
-        compositionContext = activity.setContent {
-            MaterialTheme {
-                Column {
-                    repeat(amountOfRectangles) { i ->
-                        if (i == 0) {
-                            ColoredRect(color = model.color, width = 100.dp, height = 50.dp)
-                        } else {
-                            ColoredRect(color = Color.Green, width = 100.dp, height = 50.dp)
-                        }
+    override fun setComposeContent(activity: Activity) = activity.setContent {
+        MaterialTheme {
+            Column {
+                repeat(amountOfRectangles) { i ->
+                    if (i == 0) {
+                        ColoredRect(color = model.color, width = 100.dp, height = 50.dp)
+                    } else {
+                        ColoredRect(color = Color.Green, width = 100.dp, height = 50.dp)
                     }
                 }
             }
-        }!!
-        FrameManager.nextFrame()
-    }
+        }
+    }!!
 
     override fun toggleState() {
         if (model.color == Color.Purple) {
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnTestCase.kt
index 526c984..0f25cc2 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/RectsInColumnTestCase.kt
@@ -19,6 +19,7 @@
 import android.app.Activity
 import androidx.compose.composer
 import androidx.compose.Composable
+import androidx.compose.CompositionContext
 import androidx.compose.FrameManager
 import androidx.compose.State
 import androidx.compose.state
@@ -46,20 +47,17 @@
 
     private val states = mutableListOf<State<Color>>()
 
-    override fun setupContent(activity: Activity) {
-        compositionContext = activity.setContent {
-            MaterialTheme {
-                Surface {
-                    Column {
-                        repeat(amountOfRectangles) {
-                            ColoredRectWithModel()
-                        }
+    override fun setComposeContent(activity: Activity) = activity.setContent {
+        MaterialTheme {
+            Surface {
+                Column {
+                    repeat(amountOfRectangles) {
+                        ColoredRectWithModel()
                     }
                 }
             }
-        }!!
-        FrameManager.nextFrame()
-    }
+        }
+    }!!
 
     override fun toggleState() {
         val state = states.first()
diff --git a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/view/AndroidCheckboxesInLinearLayoutTestCase.kt b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/view/AndroidCheckboxesInLinearLayoutTestCase.kt
index 1d93e85..8941a79 100644
--- a/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/view/AndroidCheckboxesInLinearLayoutTestCase.kt
+++ b/ui/integration-tests/test/src/main/java/androidx/ui/test/cases/view/AndroidCheckboxesInLinearLayoutTestCase.kt
@@ -36,7 +36,7 @@
 
     private val checkboxes = mutableListOf<CheckBox>()
 
-    override fun setupContent(activity: Activity) {
+    override fun createViewContent(activity: Activity): ViewGroup {
         val column = LinearLayout(activity)
         column.orientation = LinearLayout.VERTICAL
         column.layoutParams = ViewGroup.LayoutParams(
@@ -73,7 +73,7 @@
             row.addView(checkbox)
             column.addView(row)
         }
-        activity.setContentView(column)
+        return column
     }
 
     fun toggleState() {
diff --git a/ui/settings.gradle b/ui/settings.gradle
index 75431ad..2063fef 100644
--- a/ui/settings.gradle
+++ b/ui/settings.gradle
@@ -55,6 +55,10 @@
 includeProject(":ui:ui-test", "ui-test")
 includeProject(":ui:ui-text", "ui-text")
 includeProject(":ui:ui-text:integration-tests:ui-text-demos", "ui-text/integration-tests/text-demos")
+includeProject(":ui:ui-vector", "ui-vector")
+includeProject(":compose:compose-runtime:integration-tests", "../compose/compose-runtime/integration-tests")
+includeProject(":compose:compose-runtime:integration-tests:android-tests", "../compose/compose-runtime/integration-tests/android-tests")
+
 
 /////////////////////////////
 //
diff --git a/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt b/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
index c1a49d5..f3f6dd7 100644
--- a/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
+++ b/ui/ui-animation/src/main/java/androidx/ui/animation/Transition.kt
@@ -46,7 +46,7 @@
 fun <T> Transition(
     definition: TransitionDefinition<T>,
     toState: T,
-    @Children children: @Composable() (state: TransitionState) -> Unit
+    children: @Composable() (state: TransitionState) -> Unit
 ) {
     if (transitionsEnabled) {
         // TODO: This null is workaround for b/132148894
diff --git a/ui/ui-core/api/1.0.0-alpha01.txt b/ui/ui-core/api/1.0.0-alpha01.txt
index d0525d8..195ecdf 100644
--- a/ui/ui-core/api/1.0.0-alpha01.txt
+++ b/ui/ui-core/api/1.0.0-alpha01.txt
@@ -479,7 +479,9 @@
 
   public static final class Px.Companion {
     method public androidx.ui.core.Px getInfinity();
+    method public androidx.ui.core.Px getZero();
     property public final androidx.ui.core.Px Infinity;
+    property public final androidx.ui.core.Px Zero;
   }
 
   public final class PxBounds {
@@ -1320,6 +1322,255 @@
 
 }
 
+package androidx.ui.graphics.vectorgraphics {
+
+  public interface Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+  }
+
+  public final class BrushKt {
+    ctor public BrushKt();
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient HorizontalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush HorizontalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(androidx.ui.graphics.Color![] colors, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush getEmptyBrush();
+    method public static androidx.ui.graphics.vectorgraphics.Brush obtainBrush(Object? brush);
+  }
+
+  public final class GroupComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public GroupComponent(String name);
+    ctor public GroupComponent();
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getClipPathNodes();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public void insertAt(int index, androidx.ui.graphics.vectorgraphics.VNode instance);
+    method public void move(int from, int to, int count);
+    method public void remove(int index, int count);
+    method public void setClipPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setPivotX(float value);
+    method public void setPivotY(float value);
+    method public void setRotation(float value);
+    method public void setScaleX(float value);
+    method public void setScaleY(float value);
+    method public void setTranslationX(float value);
+    method public void setTranslationY(float value);
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] clipPathNodes;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotation;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final int size;
+    property public final float translationX;
+    property public final float translationY;
+  }
+
+  public final class LinearGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public java.util.List<androidx.ui.graphics.Color> component1();
+    method public java.util.List<java.lang.Float>? component2();
+    method public androidx.ui.core.Px component3();
+    method public androidx.ui.core.Px component4();
+    method public androidx.ui.core.Px component5();
+    method public androidx.ui.core.Px component6();
+    method public androidx.ui.painting.TileMode component7();
+    method public androidx.ui.graphics.vectorgraphics.LinearGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode);
+    method public java.util.List<androidx.ui.graphics.Color> getColors();
+    method public androidx.ui.core.Px getEndX();
+    method public androidx.ui.core.Px getEndY();
+    method public androidx.ui.core.Px getStartX();
+    method public androidx.ui.core.Px getStartY();
+    method public java.util.List<java.lang.Float>? getStops();
+    method public androidx.ui.painting.TileMode getTileMode();
+  }
+
+  public final class PathBuilder {
+    ctor public PathBuilder();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder close();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getNodes();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineTo(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineTo(float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  }
+
+  public enum PathCommand {
+    method public final char toKey();
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand Close;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand CurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand HorizontalLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand LineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand MoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand QuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeClose;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeHorizontalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeMoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeVerticalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand VerticalLineTo;
+  }
+
+  public final class PathCommandKt {
+    ctor public PathCommandKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathCommand toPathCommand(char);
+  }
+
+  public final class PathComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public PathComponent(String name);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.Brush getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getPathNodes();
+    method public androidx.ui.graphics.vectorgraphics.Brush getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
+    method public void setFill(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setFillAlpha(float value);
+    method public void setPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setStroke(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setStrokeAlpha(float value);
+    method public void setStrokeLineCap(androidx.ui.painting.StrokeCap value);
+    method public void setStrokeLineJoin(androidx.ui.painting.StrokeJoin value);
+    method public void setStrokeLineMiter(float value);
+    method public void setStrokeLineWidth(float value);
+    property public final androidx.ui.graphics.vectorgraphics.Brush fill;
+    property public final float fillAlpha;
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] pathNodes;
+    property public final androidx.ui.graphics.vectorgraphics.Brush stroke;
+    property public final float strokeAlpha;
+    property public final androidx.ui.painting.StrokeCap strokeLineCap;
+    property public final androidx.ui.painting.StrokeJoin strokeLineJoin;
+    property public final float strokeLineMiter;
+    property public final float strokeLineWidth;
+  }
+
+  public final class PathDelegate {
+    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
+    method public kotlin.jvm.functions.Function1<androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
+  }
+
+  public final class PathNode {
+    ctor public PathNode(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public androidx.ui.graphics.vectorgraphics.PathCommand component1();
+    method public float[] component2();
+    method public androidx.ui.graphics.vectorgraphics.PathNode copy(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public float[] getArgs();
+    method public androidx.ui.graphics.vectorgraphics.PathCommand getCommand();
+  }
+
+  public final class PathNodeKt {
+    ctor public PathNodeKt();
+    method public static operator StringBuilder plus(StringBuilder, androidx.ui.graphics.vectorgraphics.PathNode node);
+  }
+
+  public final class PathParser {
+    ctor public PathParser();
+    method public androidx.ui.graphics.vectorgraphics.PathParser addPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] nodes);
+    method public void clear();
+    method public androidx.ui.graphics.vectorgraphics.PathParser parsePathString(String pathData);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] toNodes();
+    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = androidx.ui.painting.Path());
+  }
+
+  public final class PathParserKt {
+    ctor public PathParserKt();
+  }
+
+  public final class RadialGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.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.painting.TileMode tileMode);
+  }
+
+  public final class SolidColor implements androidx.ui.graphics.vectorgraphics.Brush {
+    ctor public SolidColor(androidx.ui.graphics.Color value);
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.SolidColor copy(androidx.ui.graphics.Color value);
+  }
+
+  public abstract sealed class VNode {
+    method public abstract void draw(androidx.ui.painting.Canvas canvas);
+  }
+
+  public final class VectorComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public VectorComponent(String name, float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.GroupComponent getRoot();
+    method public int getSize();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public void setDefaultHeight(androidx.ui.core.Px p);
+    method public void setDefaultWidth(androidx.ui.core.Px p);
+    method public void setViewportHeight(float p);
+    method public void setViewportWidth(float p);
+    property public final androidx.ui.graphics.vectorgraphics.GroupComponent root;
+    property public final int size;
+  }
+
+  public final class VectorKt {
+    ctor public VectorKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] createPath(Object? pathData);
+    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
+    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] getEmptyPath();
+    field public static final float DefaultAlpha = 1.0f;
+    field public static final String DefaultGroupName = "";
+    field public static final String DefaultPathName = "";
+    field public static final float DefaultPivotX = 0.0f;
+    field public static final float DefaultPivotY = 0.0f;
+    field public static final float DefaultRotation = 0.0f;
+    field public static final float DefaultScaleX = 1.0f;
+    field public static final float DefaultScaleY = 1.0f;
+    field public static final float DefaultStrokeLineMiter = 4.0f;
+    field public static final float DefaultStrokeLineWidth = 0.0f;
+    field public static final float DefaultTranslationX = 0.0f;
+    field public static final float DefaultTranslationY = 0.0f;
+  }
+
+}
+
 package androidx.ui.painting {
 
   public final class AndroidCanvasKt {
@@ -1441,7 +1692,7 @@
 
   public static final class Gradient.Companion {
     method public androidx.ui.painting.Gradient linear(androidx.ui.engine.geometry.Offset from, androidx.ui.engine.geometry.Offset to, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? colorStops = null, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
-    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4, androidx.ui.engine.geometry.Offset? focal, float focalRadius);
+    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4);
     method public androidx.ui.painting.Gradient sweep(androidx.ui.engine.geometry.Offset center, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float> colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, float startAngle, float endAngle = 6.2831855f, androidx.ui.vectormath64.Matrix4 matrix4);
   }
 
@@ -1685,6 +1936,7 @@
     method public static androidx.ui.core.PointerInputChange consume(androidx.ui.core.PointerInputChange, float dx = 0f, float dy = 0f, boolean downChange = false);
     method public static androidx.ui.core.PointerInputChange down(int id = 0, androidx.ui.core.Timestamp timestamp = 0.millisecondsToTimestamp(), float x = 0f, float y = 0f);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges);
+    method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, androidx.ui.core.PointerInputChange... pointerInputChanges);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges, androidx.ui.core.PointerEventPass... pointerEventPasses);
     method public static androidx.ui.core.PointerInputChange moveBy(androidx.ui.core.PointerInputChange, androidx.ui.core.Duration duration, float dx = 0f, float dy = 0f);
     method public static androidx.ui.core.PointerInputChange moveTo(androidx.ui.core.PointerInputChange, androidx.ui.core.Timestamp timestamp, float x = 0f, float y = 0f);
diff --git a/ui/ui-core/api/current.txt b/ui/ui-core/api/current.txt
index d0525d8..195ecdf 100644
--- a/ui/ui-core/api/current.txt
+++ b/ui/ui-core/api/current.txt
@@ -479,7 +479,9 @@
 
   public static final class Px.Companion {
     method public androidx.ui.core.Px getInfinity();
+    method public androidx.ui.core.Px getZero();
     property public final androidx.ui.core.Px Infinity;
+    property public final androidx.ui.core.Px Zero;
   }
 
   public final class PxBounds {
@@ -1320,6 +1322,255 @@
 
 }
 
+package androidx.ui.graphics.vectorgraphics {
+
+  public interface Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+  }
+
+  public final class BrushKt {
+    ctor public BrushKt();
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient HorizontalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush HorizontalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(androidx.ui.graphics.Color![] colors, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush getEmptyBrush();
+    method public static androidx.ui.graphics.vectorgraphics.Brush obtainBrush(Object? brush);
+  }
+
+  public final class GroupComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public GroupComponent(String name);
+    ctor public GroupComponent();
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getClipPathNodes();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public void insertAt(int index, androidx.ui.graphics.vectorgraphics.VNode instance);
+    method public void move(int from, int to, int count);
+    method public void remove(int index, int count);
+    method public void setClipPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setPivotX(float value);
+    method public void setPivotY(float value);
+    method public void setRotation(float value);
+    method public void setScaleX(float value);
+    method public void setScaleY(float value);
+    method public void setTranslationX(float value);
+    method public void setTranslationY(float value);
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] clipPathNodes;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotation;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final int size;
+    property public final float translationX;
+    property public final float translationY;
+  }
+
+  public final class LinearGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public java.util.List<androidx.ui.graphics.Color> component1();
+    method public java.util.List<java.lang.Float>? component2();
+    method public androidx.ui.core.Px component3();
+    method public androidx.ui.core.Px component4();
+    method public androidx.ui.core.Px component5();
+    method public androidx.ui.core.Px component6();
+    method public androidx.ui.painting.TileMode component7();
+    method public androidx.ui.graphics.vectorgraphics.LinearGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode);
+    method public java.util.List<androidx.ui.graphics.Color> getColors();
+    method public androidx.ui.core.Px getEndX();
+    method public androidx.ui.core.Px getEndY();
+    method public androidx.ui.core.Px getStartX();
+    method public androidx.ui.core.Px getStartY();
+    method public java.util.List<java.lang.Float>? getStops();
+    method public androidx.ui.painting.TileMode getTileMode();
+  }
+
+  public final class PathBuilder {
+    ctor public PathBuilder();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder close();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getNodes();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineTo(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineTo(float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  }
+
+  public enum PathCommand {
+    method public final char toKey();
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand Close;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand CurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand HorizontalLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand LineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand MoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand QuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeClose;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeHorizontalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeMoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeVerticalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand VerticalLineTo;
+  }
+
+  public final class PathCommandKt {
+    ctor public PathCommandKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathCommand toPathCommand(char);
+  }
+
+  public final class PathComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public PathComponent(String name);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.Brush getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getPathNodes();
+    method public androidx.ui.graphics.vectorgraphics.Brush getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
+    method public void setFill(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setFillAlpha(float value);
+    method public void setPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setStroke(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setStrokeAlpha(float value);
+    method public void setStrokeLineCap(androidx.ui.painting.StrokeCap value);
+    method public void setStrokeLineJoin(androidx.ui.painting.StrokeJoin value);
+    method public void setStrokeLineMiter(float value);
+    method public void setStrokeLineWidth(float value);
+    property public final androidx.ui.graphics.vectorgraphics.Brush fill;
+    property public final float fillAlpha;
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] pathNodes;
+    property public final androidx.ui.graphics.vectorgraphics.Brush stroke;
+    property public final float strokeAlpha;
+    property public final androidx.ui.painting.StrokeCap strokeLineCap;
+    property public final androidx.ui.painting.StrokeJoin strokeLineJoin;
+    property public final float strokeLineMiter;
+    property public final float strokeLineWidth;
+  }
+
+  public final class PathDelegate {
+    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
+    method public kotlin.jvm.functions.Function1<androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
+  }
+
+  public final class PathNode {
+    ctor public PathNode(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public androidx.ui.graphics.vectorgraphics.PathCommand component1();
+    method public float[] component2();
+    method public androidx.ui.graphics.vectorgraphics.PathNode copy(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public float[] getArgs();
+    method public androidx.ui.graphics.vectorgraphics.PathCommand getCommand();
+  }
+
+  public final class PathNodeKt {
+    ctor public PathNodeKt();
+    method public static operator StringBuilder plus(StringBuilder, androidx.ui.graphics.vectorgraphics.PathNode node);
+  }
+
+  public final class PathParser {
+    ctor public PathParser();
+    method public androidx.ui.graphics.vectorgraphics.PathParser addPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] nodes);
+    method public void clear();
+    method public androidx.ui.graphics.vectorgraphics.PathParser parsePathString(String pathData);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] toNodes();
+    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = androidx.ui.painting.Path());
+  }
+
+  public final class PathParserKt {
+    ctor public PathParserKt();
+  }
+
+  public final class RadialGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.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.painting.TileMode tileMode);
+  }
+
+  public final class SolidColor implements androidx.ui.graphics.vectorgraphics.Brush {
+    ctor public SolidColor(androidx.ui.graphics.Color value);
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.SolidColor copy(androidx.ui.graphics.Color value);
+  }
+
+  public abstract sealed class VNode {
+    method public abstract void draw(androidx.ui.painting.Canvas canvas);
+  }
+
+  public final class VectorComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public VectorComponent(String name, float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.GroupComponent getRoot();
+    method public int getSize();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public void setDefaultHeight(androidx.ui.core.Px p);
+    method public void setDefaultWidth(androidx.ui.core.Px p);
+    method public void setViewportHeight(float p);
+    method public void setViewportWidth(float p);
+    property public final androidx.ui.graphics.vectorgraphics.GroupComponent root;
+    property public final int size;
+  }
+
+  public final class VectorKt {
+    ctor public VectorKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] createPath(Object? pathData);
+    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
+    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] getEmptyPath();
+    field public static final float DefaultAlpha = 1.0f;
+    field public static final String DefaultGroupName = "";
+    field public static final String DefaultPathName = "";
+    field public static final float DefaultPivotX = 0.0f;
+    field public static final float DefaultPivotY = 0.0f;
+    field public static final float DefaultRotation = 0.0f;
+    field public static final float DefaultScaleX = 1.0f;
+    field public static final float DefaultScaleY = 1.0f;
+    field public static final float DefaultStrokeLineMiter = 4.0f;
+    field public static final float DefaultStrokeLineWidth = 0.0f;
+    field public static final float DefaultTranslationX = 0.0f;
+    field public static final float DefaultTranslationY = 0.0f;
+  }
+
+}
+
 package androidx.ui.painting {
 
   public final class AndroidCanvasKt {
@@ -1441,7 +1692,7 @@
 
   public static final class Gradient.Companion {
     method public androidx.ui.painting.Gradient linear(androidx.ui.engine.geometry.Offset from, androidx.ui.engine.geometry.Offset to, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? colorStops = null, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
-    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4, androidx.ui.engine.geometry.Offset? focal, float focalRadius);
+    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4);
     method public androidx.ui.painting.Gradient sweep(androidx.ui.engine.geometry.Offset center, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float> colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, float startAngle, float endAngle = 6.2831855f, androidx.ui.vectormath64.Matrix4 matrix4);
   }
 
@@ -1685,6 +1936,7 @@
     method public static androidx.ui.core.PointerInputChange consume(androidx.ui.core.PointerInputChange, float dx = 0f, float dy = 0f, boolean downChange = false);
     method public static androidx.ui.core.PointerInputChange down(int id = 0, androidx.ui.core.Timestamp timestamp = 0.millisecondsToTimestamp(), float x = 0f, float y = 0f);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges);
+    method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, androidx.ui.core.PointerInputChange... pointerInputChanges);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges, androidx.ui.core.PointerEventPass... pointerEventPasses);
     method public static androidx.ui.core.PointerInputChange moveBy(androidx.ui.core.PointerInputChange, androidx.ui.core.Duration duration, float dx = 0f, float dy = 0f);
     method public static androidx.ui.core.PointerInputChange moveTo(androidx.ui.core.PointerInputChange, androidx.ui.core.Timestamp timestamp, float x = 0f, float y = 0f);
diff --git a/ui/ui-core/api/restricted_1.0.0-alpha01.txt b/ui/ui-core/api/restricted_1.0.0-alpha01.txt
index d0525d8..195ecdf 100644
--- a/ui/ui-core/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-core/api/restricted_1.0.0-alpha01.txt
@@ -479,7 +479,9 @@
 
   public static final class Px.Companion {
     method public androidx.ui.core.Px getInfinity();
+    method public androidx.ui.core.Px getZero();
     property public final androidx.ui.core.Px Infinity;
+    property public final androidx.ui.core.Px Zero;
   }
 
   public final class PxBounds {
@@ -1320,6 +1322,255 @@
 
 }
 
+package androidx.ui.graphics.vectorgraphics {
+
+  public interface Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+  }
+
+  public final class BrushKt {
+    ctor public BrushKt();
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient HorizontalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush HorizontalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(androidx.ui.graphics.Color![] colors, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush getEmptyBrush();
+    method public static androidx.ui.graphics.vectorgraphics.Brush obtainBrush(Object? brush);
+  }
+
+  public final class GroupComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public GroupComponent(String name);
+    ctor public GroupComponent();
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getClipPathNodes();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public void insertAt(int index, androidx.ui.graphics.vectorgraphics.VNode instance);
+    method public void move(int from, int to, int count);
+    method public void remove(int index, int count);
+    method public void setClipPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setPivotX(float value);
+    method public void setPivotY(float value);
+    method public void setRotation(float value);
+    method public void setScaleX(float value);
+    method public void setScaleY(float value);
+    method public void setTranslationX(float value);
+    method public void setTranslationY(float value);
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] clipPathNodes;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotation;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final int size;
+    property public final float translationX;
+    property public final float translationY;
+  }
+
+  public final class LinearGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public java.util.List<androidx.ui.graphics.Color> component1();
+    method public java.util.List<java.lang.Float>? component2();
+    method public androidx.ui.core.Px component3();
+    method public androidx.ui.core.Px component4();
+    method public androidx.ui.core.Px component5();
+    method public androidx.ui.core.Px component6();
+    method public androidx.ui.painting.TileMode component7();
+    method public androidx.ui.graphics.vectorgraphics.LinearGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode);
+    method public java.util.List<androidx.ui.graphics.Color> getColors();
+    method public androidx.ui.core.Px getEndX();
+    method public androidx.ui.core.Px getEndY();
+    method public androidx.ui.core.Px getStartX();
+    method public androidx.ui.core.Px getStartY();
+    method public java.util.List<java.lang.Float>? getStops();
+    method public androidx.ui.painting.TileMode getTileMode();
+  }
+
+  public final class PathBuilder {
+    ctor public PathBuilder();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder close();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getNodes();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineTo(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineTo(float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  }
+
+  public enum PathCommand {
+    method public final char toKey();
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand Close;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand CurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand HorizontalLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand LineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand MoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand QuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeClose;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeHorizontalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeMoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeVerticalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand VerticalLineTo;
+  }
+
+  public final class PathCommandKt {
+    ctor public PathCommandKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathCommand toPathCommand(char);
+  }
+
+  public final class PathComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public PathComponent(String name);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.Brush getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getPathNodes();
+    method public androidx.ui.graphics.vectorgraphics.Brush getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
+    method public void setFill(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setFillAlpha(float value);
+    method public void setPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setStroke(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setStrokeAlpha(float value);
+    method public void setStrokeLineCap(androidx.ui.painting.StrokeCap value);
+    method public void setStrokeLineJoin(androidx.ui.painting.StrokeJoin value);
+    method public void setStrokeLineMiter(float value);
+    method public void setStrokeLineWidth(float value);
+    property public final androidx.ui.graphics.vectorgraphics.Brush fill;
+    property public final float fillAlpha;
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] pathNodes;
+    property public final androidx.ui.graphics.vectorgraphics.Brush stroke;
+    property public final float strokeAlpha;
+    property public final androidx.ui.painting.StrokeCap strokeLineCap;
+    property public final androidx.ui.painting.StrokeJoin strokeLineJoin;
+    property public final float strokeLineMiter;
+    property public final float strokeLineWidth;
+  }
+
+  public final class PathDelegate {
+    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
+    method public kotlin.jvm.functions.Function1<androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
+  }
+
+  public final class PathNode {
+    ctor public PathNode(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public androidx.ui.graphics.vectorgraphics.PathCommand component1();
+    method public float[] component2();
+    method public androidx.ui.graphics.vectorgraphics.PathNode copy(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public float[] getArgs();
+    method public androidx.ui.graphics.vectorgraphics.PathCommand getCommand();
+  }
+
+  public final class PathNodeKt {
+    ctor public PathNodeKt();
+    method public static operator StringBuilder plus(StringBuilder, androidx.ui.graphics.vectorgraphics.PathNode node);
+  }
+
+  public final class PathParser {
+    ctor public PathParser();
+    method public androidx.ui.graphics.vectorgraphics.PathParser addPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] nodes);
+    method public void clear();
+    method public androidx.ui.graphics.vectorgraphics.PathParser parsePathString(String pathData);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] toNodes();
+    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = androidx.ui.painting.Path());
+  }
+
+  public final class PathParserKt {
+    ctor public PathParserKt();
+  }
+
+  public final class RadialGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.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.painting.TileMode tileMode);
+  }
+
+  public final class SolidColor implements androidx.ui.graphics.vectorgraphics.Brush {
+    ctor public SolidColor(androidx.ui.graphics.Color value);
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.SolidColor copy(androidx.ui.graphics.Color value);
+  }
+
+  public abstract sealed class VNode {
+    method public abstract void draw(androidx.ui.painting.Canvas canvas);
+  }
+
+  public final class VectorComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public VectorComponent(String name, float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.GroupComponent getRoot();
+    method public int getSize();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public void setDefaultHeight(androidx.ui.core.Px p);
+    method public void setDefaultWidth(androidx.ui.core.Px p);
+    method public void setViewportHeight(float p);
+    method public void setViewportWidth(float p);
+    property public final androidx.ui.graphics.vectorgraphics.GroupComponent root;
+    property public final int size;
+  }
+
+  public final class VectorKt {
+    ctor public VectorKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] createPath(Object? pathData);
+    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
+    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] getEmptyPath();
+    field public static final float DefaultAlpha = 1.0f;
+    field public static final String DefaultGroupName = "";
+    field public static final String DefaultPathName = "";
+    field public static final float DefaultPivotX = 0.0f;
+    field public static final float DefaultPivotY = 0.0f;
+    field public static final float DefaultRotation = 0.0f;
+    field public static final float DefaultScaleX = 1.0f;
+    field public static final float DefaultScaleY = 1.0f;
+    field public static final float DefaultStrokeLineMiter = 4.0f;
+    field public static final float DefaultStrokeLineWidth = 0.0f;
+    field public static final float DefaultTranslationX = 0.0f;
+    field public static final float DefaultTranslationY = 0.0f;
+  }
+
+}
+
 package androidx.ui.painting {
 
   public final class AndroidCanvasKt {
@@ -1441,7 +1692,7 @@
 
   public static final class Gradient.Companion {
     method public androidx.ui.painting.Gradient linear(androidx.ui.engine.geometry.Offset from, androidx.ui.engine.geometry.Offset to, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? colorStops = null, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
-    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4, androidx.ui.engine.geometry.Offset? focal, float focalRadius);
+    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4);
     method public androidx.ui.painting.Gradient sweep(androidx.ui.engine.geometry.Offset center, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float> colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, float startAngle, float endAngle = 6.2831855f, androidx.ui.vectormath64.Matrix4 matrix4);
   }
 
@@ -1685,6 +1936,7 @@
     method public static androidx.ui.core.PointerInputChange consume(androidx.ui.core.PointerInputChange, float dx = 0f, float dy = 0f, boolean downChange = false);
     method public static androidx.ui.core.PointerInputChange down(int id = 0, androidx.ui.core.Timestamp timestamp = 0.millisecondsToTimestamp(), float x = 0f, float y = 0f);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges);
+    method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, androidx.ui.core.PointerInputChange... pointerInputChanges);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges, androidx.ui.core.PointerEventPass... pointerEventPasses);
     method public static androidx.ui.core.PointerInputChange moveBy(androidx.ui.core.PointerInputChange, androidx.ui.core.Duration duration, float dx = 0f, float dy = 0f);
     method public static androidx.ui.core.PointerInputChange moveTo(androidx.ui.core.PointerInputChange, androidx.ui.core.Timestamp timestamp, float x = 0f, float y = 0f);
diff --git a/ui/ui-core/api/restricted_current.txt b/ui/ui-core/api/restricted_current.txt
index d0525d8..195ecdf 100644
--- a/ui/ui-core/api/restricted_current.txt
+++ b/ui/ui-core/api/restricted_current.txt
@@ -479,7 +479,9 @@
 
   public static final class Px.Companion {
     method public androidx.ui.core.Px getInfinity();
+    method public androidx.ui.core.Px getZero();
     property public final androidx.ui.core.Px Infinity;
+    property public final androidx.ui.core.Px Zero;
   }
 
   public final class PxBounds {
@@ -1320,6 +1322,255 @@
 
 }
 
+package androidx.ui.graphics.vectorgraphics {
+
+  public interface Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+  }
+
+  public final class BrushKt {
+    ctor public BrushKt();
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient HorizontalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush HorizontalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px endX, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient LinearGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.RadialGradient RadialGradient(androidx.ui.graphics.Color![] colors, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(androidx.ui.graphics.Color![] colors, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.LinearGradient VerticalGradient(kotlin.Pair<java.lang.Float,androidx.ui.graphics.Color>![] colorStops, androidx.ui.core.Px startY, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
+    method public static androidx.ui.graphics.vectorgraphics.Brush getEmptyBrush();
+    method public static androidx.ui.graphics.vectorgraphics.Brush obtainBrush(Object? brush);
+  }
+
+  public final class GroupComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public GroupComponent(String name);
+    ctor public GroupComponent();
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getClipPathNodes();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public void insertAt(int index, androidx.ui.graphics.vectorgraphics.VNode instance);
+    method public void move(int from, int to, int count);
+    method public void remove(int index, int count);
+    method public void setClipPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setPivotX(float value);
+    method public void setPivotY(float value);
+    method public void setRotation(float value);
+    method public void setScaleX(float value);
+    method public void setScaleY(float value);
+    method public void setTranslationX(float value);
+    method public void setTranslationY(float value);
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] clipPathNodes;
+    property public final float pivotX;
+    property public final float pivotY;
+    property public final float rotation;
+    property public final float scaleX;
+    property public final float scaleY;
+    property public final int size;
+    property public final float translationX;
+    property public final float translationY;
+  }
+
+  public final class LinearGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public java.util.List<androidx.ui.graphics.Color> component1();
+    method public java.util.List<java.lang.Float>? component2();
+    method public androidx.ui.core.Px component3();
+    method public androidx.ui.core.Px component4();
+    method public androidx.ui.core.Px component5();
+    method public androidx.ui.core.Px component6();
+    method public androidx.ui.painting.TileMode component7();
+    method public androidx.ui.graphics.vectorgraphics.LinearGradient copy(java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? stops, androidx.ui.core.Px startX, androidx.ui.core.Px startY, androidx.ui.core.Px endX, androidx.ui.core.Px endY, androidx.ui.painting.TileMode tileMode);
+    method public java.util.List<androidx.ui.graphics.Color> getColors();
+    method public androidx.ui.core.Px getEndX();
+    method public androidx.ui.core.Px getEndY();
+    method public androidx.ui.core.Px getStartX();
+    method public androidx.ui.core.Px getStartY();
+    method public java.util.List<java.lang.Float>? getStops();
+    method public androidx.ui.painting.TileMode getTileMode();
+  }
+
+  public final class PathBuilder {
+    ctor public PathBuilder();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder close();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getNodes();
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineTo(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder lineToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveTo(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder moveToRelative(float x, float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineTo(float y);
+    method public androidx.ui.graphics.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  }
+
+  public enum PathCommand {
+    method public final char toKey();
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand Close;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand CurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand HorizontalLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand LineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand MoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand QuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand ReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeArcTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeClose;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeHorizontalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeLineTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeMoveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand RelativeVerticalTo;
+    enum_constant public static final androidx.ui.graphics.vectorgraphics.PathCommand VerticalLineTo;
+  }
+
+  public final class PathCommandKt {
+    ctor public PathCommandKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathCommand toPathCommand(char);
+  }
+
+  public final class PathComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public PathComponent(String name);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.graphics.vectorgraphics.Brush getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] getPathNodes();
+    method public androidx.ui.graphics.vectorgraphics.Brush getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
+    method public void setFill(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setFillAlpha(float value);
+    method public void setPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] value);
+    method public void setStroke(androidx.ui.graphics.vectorgraphics.Brush value);
+    method public void setStrokeAlpha(float value);
+    method public void setStrokeLineCap(androidx.ui.painting.StrokeCap value);
+    method public void setStrokeLineJoin(androidx.ui.painting.StrokeJoin value);
+    method public void setStrokeLineMiter(float value);
+    method public void setStrokeLineWidth(float value);
+    property public final androidx.ui.graphics.vectorgraphics.Brush fill;
+    property public final float fillAlpha;
+    property public final androidx.ui.graphics.vectorgraphics.PathNode![] pathNodes;
+    property public final androidx.ui.graphics.vectorgraphics.Brush stroke;
+    property public final float strokeAlpha;
+    property public final androidx.ui.painting.StrokeCap strokeLineCap;
+    property public final androidx.ui.painting.StrokeJoin strokeLineJoin;
+    property public final float strokeLineMiter;
+    property public final float strokeLineWidth;
+  }
+
+  public final class PathDelegate {
+    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
+    method public kotlin.jvm.functions.Function1<androidx.ui.graphics.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
+  }
+
+  public final class PathNode {
+    ctor public PathNode(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public androidx.ui.graphics.vectorgraphics.PathCommand component1();
+    method public float[] component2();
+    method public androidx.ui.graphics.vectorgraphics.PathNode copy(androidx.ui.graphics.vectorgraphics.PathCommand command, float[] args);
+    method public float[] getArgs();
+    method public androidx.ui.graphics.vectorgraphics.PathCommand getCommand();
+  }
+
+  public final class PathNodeKt {
+    ctor public PathNodeKt();
+    method public static operator StringBuilder plus(StringBuilder, androidx.ui.graphics.vectorgraphics.PathNode node);
+  }
+
+  public final class PathParser {
+    ctor public PathParser();
+    method public androidx.ui.graphics.vectorgraphics.PathParser addPathNodes(androidx.ui.graphics.vectorgraphics.PathNode![] nodes);
+    method public void clear();
+    method public androidx.ui.graphics.vectorgraphics.PathParser parsePathString(String pathData);
+    method public androidx.ui.graphics.vectorgraphics.PathNode![] toNodes();
+    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = androidx.ui.painting.Path());
+  }
+
+  public final class PathParserKt {
+    ctor public PathParserKt();
+  }
+
+  public final class RadialGradient implements androidx.ui.graphics.vectorgraphics.Brush {
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.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.painting.TileMode tileMode);
+  }
+
+  public final class SolidColor implements androidx.ui.graphics.vectorgraphics.Brush {
+    ctor public SolidColor(androidx.ui.graphics.Color value);
+    method public void applyBrush(androidx.ui.painting.Paint p);
+    method public androidx.ui.graphics.vectorgraphics.SolidColor copy(androidx.ui.graphics.Color value);
+  }
+
+  public abstract sealed class VNode {
+    method public abstract void draw(androidx.ui.painting.Canvas canvas);
+  }
+
+  public final class VectorComponent extends androidx.ui.graphics.vectorgraphics.VNode {
+    ctor public VectorComponent(String name, float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight);
+    method public void draw(androidx.ui.painting.Canvas canvas);
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.graphics.vectorgraphics.GroupComponent getRoot();
+    method public int getSize();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public void setDefaultHeight(androidx.ui.core.Px p);
+    method public void setDefaultWidth(androidx.ui.core.Px p);
+    method public void setViewportHeight(float p);
+    method public void setViewportWidth(float p);
+    property public final androidx.ui.graphics.vectorgraphics.GroupComponent root;
+    property public final int size;
+  }
+
+  public final class VectorKt {
+    ctor public VectorKt();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] createPath(Object? pathData);
+    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
+    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
+    method public static androidx.ui.graphics.vectorgraphics.PathNode![] getEmptyPath();
+    field public static final float DefaultAlpha = 1.0f;
+    field public static final String DefaultGroupName = "";
+    field public static final String DefaultPathName = "";
+    field public static final float DefaultPivotX = 0.0f;
+    field public static final float DefaultPivotY = 0.0f;
+    field public static final float DefaultRotation = 0.0f;
+    field public static final float DefaultScaleX = 1.0f;
+    field public static final float DefaultScaleY = 1.0f;
+    field public static final float DefaultStrokeLineMiter = 4.0f;
+    field public static final float DefaultStrokeLineWidth = 0.0f;
+    field public static final float DefaultTranslationX = 0.0f;
+    field public static final float DefaultTranslationY = 0.0f;
+  }
+
+}
+
 package androidx.ui.painting {
 
   public final class AndroidCanvasKt {
@@ -1441,7 +1692,7 @@
 
   public static final class Gradient.Companion {
     method public androidx.ui.painting.Gradient linear(androidx.ui.engine.geometry.Offset from, androidx.ui.engine.geometry.Offset to, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float>? colorStops = null, androidx.ui.painting.TileMode tileMode = TileMode.clamp);
-    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4, androidx.ui.engine.geometry.Offset? focal, float focalRadius);
+    method public androidx.ui.painting.Gradient radial(androidx.ui.engine.geometry.Offset center, float radius, java.util.List<androidx.ui.graphics.Color> color, java.util.List<java.lang.Float>? colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, androidx.ui.vectormath64.Matrix4 matrix4);
     method public androidx.ui.painting.Gradient sweep(androidx.ui.engine.geometry.Offset center, java.util.List<androidx.ui.graphics.Color> colors, java.util.List<java.lang.Float> colorStops, androidx.ui.painting.TileMode tileMode = TileMode.clamp, float startAngle, float endAngle = 6.2831855f, androidx.ui.vectormath64.Matrix4 matrix4);
   }
 
@@ -1685,6 +1936,7 @@
     method public static androidx.ui.core.PointerInputChange consume(androidx.ui.core.PointerInputChange, float dx = 0f, float dy = 0f, boolean downChange = false);
     method public static androidx.ui.core.PointerInputChange down(int id = 0, androidx.ui.core.Timestamp timestamp = 0.millisecondsToTimestamp(), float x = 0f, float y = 0f);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges);
+    method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverAllPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, androidx.ui.core.PointerInputChange... pointerInputChanges);
     method public static java.util.List<androidx.ui.core.PointerInputChange> invokeOverPasses(kotlin.jvm.functions.Function2<? super java.util.List<androidx.ui.core.PointerInputChange>,? super androidx.ui.core.PointerEventPass,? extends java.util.List<androidx.ui.core.PointerInputChange>>, java.util.List<androidx.ui.core.PointerInputChange> pointerInputChanges, androidx.ui.core.PointerEventPass... pointerEventPasses);
     method public static androidx.ui.core.PointerInputChange moveBy(androidx.ui.core.PointerInputChange, androidx.ui.core.Duration duration, float dx = 0f, float dy = 0f);
     method public static androidx.ui.core.PointerInputChange moveTo(androidx.ui.core.PointerInputChange, androidx.ui.core.Timestamp timestamp, float x = 0f, float y = 0f);
diff --git a/ui/ui-core/src/main/java/androidx/ui/core/Px.kt b/ui/ui-core/src/main/java/androidx/ui/core/Px.kt
index 9985605..5295cf3 100644
--- a/ui/ui-core/src/main/java/androidx/ui/core/Px.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/core/Px.kt
@@ -117,6 +117,11 @@
          * Infinite px dimension.
          */
         val Infinity = Px(value = Float.POSITIVE_INFINITY)
+
+        /**
+         * Zero px dimension
+         */
+        val Zero = Px(0.0f)
     }
 }
 
diff --git a/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Brush.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Brush.kt
new file mode 100644
index 0000000..3243120
--- /dev/null
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Brush.kt
@@ -0,0 +1,344 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.ui.graphics.vectorgraphics
+
+import androidx.ui.core.Px
+import androidx.ui.engine.geometry.Offset
+import androidx.ui.graphics.Color
+import androidx.ui.painting.Gradient
+import androidx.ui.painting.Paint
+import androidx.ui.painting.TileMode
+import androidx.ui.vectormath64.Matrix4
+
+val EmptyBrush = object : Brush {
+    override fun applyBrush(p: Paint) {
+        // NO-OP
+    }
+}
+
+interface Brush {
+    fun applyBrush(p: Paint)
+}
+
+data class SolidColor(private val value: Color) : Brush {
+    override fun applyBrush(p: Paint) {
+        p.color = value
+    }
+}
+
+typealias ColorStop = Pair<Float, Color>
+
+/**
+ * Obtains actual Brush instance from Union type, throws an IllegalArgumentException
+ * if the type is other than Int, Color, Brush or null
+ */
+fun obtainBrush(brush: Any?): Brush {
+    return when (brush) {
+        is Int -> SolidColor(Color(brush))
+        is Color -> SolidColor(brush)
+        is Brush -> brush
+        null -> EmptyBrush
+        else -> throw IllegalArgumentException(brush.javaClass.simpleName +
+                "Brush must be either a Color long, LinearGradient or RadialGradient")
+    }
+}
+
+/**
+ * Creates a linear gradient with the provided colors along the given start and end coordinates.
+ * The colors are
+ *
+ * ```
+ *  LinearGradient(
+ *      0.0f to Color.Aqua,
+ *      0.3f to Color.Lime,
+ *      1.0f to Color.Fuchsia,
+ *      startX = Px.Zero,
+ *      startY = Px(50.0f),
+ *      endY = Px.Zero,
+ *      endY = Px(100.0f)
+ * )
+ * ```
+ */
+fun LinearGradient(
+    vararg colors: Color,
+    startX: Px,
+    startY: Px,
+    endX: Px,
+    endY: Px,
+    tileMode: TileMode = TileMode.clamp
+): LinearGradient {
+    return LinearGradient(
+        colors.asList(),
+        null,
+        startX,
+        startY,
+        endX,
+        endY,
+        tileMode)
+}
+
+/**
+ * Creates a linear gradient with the provided colors along the given start and end coordinates.
+ * The colors are dispersed at the provided offset defined in the [ColorStop]
+ *
+ * ```
+ *  LinearGradient(
+ *      0.0f to Color.Aqua,
+ *      0.3f to Color.Lime,
+ *      1.0f to Color.Fuchsia,
+ *      startX = Px.Zero,
+ *      startY = Px(50.0f),
+ *      endY = Px.Zero,
+ *      endY = Px(100.0f)
+ * )
+ * ```
+ */
+fun LinearGradient(
+    vararg colorStops: ColorStop,
+    startX: Px,
+    startY: Px,
+    endX: Px,
+    endY: Px,
+    tileMode: TileMode = TileMode.clamp
+): LinearGradient {
+    return LinearGradient(
+        List<Color>(colorStops.size) { i -> colorStops[i].second },
+        List<Float>(colorStops.size) { i -> colorStops[i].first },
+        startX,
+        startY,
+        endX,
+        endY,
+        tileMode)
+}
+
+/**
+ * Creates a radial gradient with the given colors at the provided offset defined in the [ColorStop]
+ * ```
+ * RadialGradient(
+ *      0.0f to Color.Navy,
+ *      0.3f to Color.Olive,
+ *      1.0f to Color.Teal,
+ *      centerX = side1 / 2.0f,
+ *      centerY = side2 / 2.0f,
+ *      radius = side1 / 2.0f,
+ *      tileMode = TileMode.repeated
+ * )
+ * ```
+ */
+fun RadialGradient(
+    vararg colorStops: ColorStop,
+    centerX: Float,
+    centerY: Float,
+    radius: Float,
+    tileMode: TileMode = TileMode.clamp
+): RadialGradient {
+    return RadialGradient(
+        List<Color>(colorStops.size) { i -> colorStops[i].second },
+        List<Float>(colorStops.size) { i -> colorStops[i].first },
+        centerX,
+        centerY,
+        radius,
+        tileMode
+    )
+}
+
+/**
+ * Creates a radial gradient with the given colors evenly dispersed within the gradient
+ * ```
+ * RadialGradient(
+ *      Color.Navy,
+ *      Color.Olive,
+ *      Color.Teal,
+ *      centerX = side1 / 2.0f,
+ *      centerY = side2 / 2.0f,
+ *      radius = side1 / 2.0f,
+ *      tileMode = TileMode.repeated
+ * )
+ * ```
+ */
+fun RadialGradient(
+    vararg colors: Color,
+    centerX: Float,
+    centerY: Float,
+    radius: Float,
+    tileMode: TileMode = TileMode.clamp
+): RadialGradient {
+    return RadialGradient(colors.asList(), null, centerX, centerY, radius, tileMode)
+}
+
+/**
+ * Creates a vertical gradient with the given colors at the provided offset defined in the [ColorStop]
+ * Ex:
+ * ```
+ *  VerticalGradient(
+ *      Color.Aqua,
+ *      Color.Lime,
+ *      Color.Fuchsia,
+ *      startY = Px.Zero,
+ *      endY = Px(100.0f)
+ * )
+ *
+ * ```
+ */
+fun VerticalGradient(
+    vararg colors: Color,
+    startY: Px,
+    endY: Px,
+    tileMode: TileMode = TileMode.clamp
+): LinearGradient {
+    return LinearGradient(
+        colors.asList(),
+        null,
+        startX = Px.Zero,
+        startY = startY,
+        endX = Px.Zero,
+        endY = endY,
+        tileMode = tileMode)
+}
+
+/**
+ * Creates a vertical gradient with the given colors evenly dispersed within the gradient
+ * Ex:
+ * ```
+ *  VerticalGradient(
+ *      Color.Aqua,
+ *      Color.Lime,
+ *      Color.Fuchsia,
+ *      startY = Px.Zero,
+ *      endY = Px(100.0f)
+ * )
+ * ```
+ */
+fun VerticalGradient(
+    vararg colorStops: ColorStop,
+    startY: Px,
+    endY: Px,
+    tileMode: TileMode = TileMode.clamp
+): LinearGradient {
+    return LinearGradient(
+        List<Color>(colorStops.size) { i -> colorStops[i].second },
+        List<Float>(colorStops.size) { i -> colorStops[i].first },
+        startX = Px.Zero,
+        startY = startY,
+        endX = Px.Zero,
+        endY = endY,
+        tileMode = tileMode
+    )
+}
+
+/**
+ * Creates a horizontal gradient with the given colors evenly dispersed within the gradient
+ *
+ * Ex:
+ * ```
+ *  HorizontalGradient(
+ *      Color.Aqua,
+ *      Color.Lime,
+ *      Color.Fuchsia,
+ *      startX = Px(10.0f),
+ *      endX = Px(20.0f)
+ * )
+ * ```
+ */
+fun HorizontalGradient(
+    vararg colors: Color,
+    startX: Px,
+    endX: Px,
+    tileMode: TileMode = TileMode.clamp
+): LinearGradient {
+    return LinearGradient(
+        colors.asList(),
+        null,
+        startX = startX,
+        startY = Px.Zero,
+        endX = endX,
+        endY = Px.Zero,
+        tileMode = tileMode)
+}
+
+/**
+ * Creates a horizontal gradient with the given colors dispersed at the provided offset defined in the [ColorStop]
+ *
+ * Ex:
+ * ```
+ *  HorizontalGradient(
+ *      0.0f to Color.Aqua,
+ *      0.3f to Color.Lime,
+ *      1.0f to Color.Fuchsia,
+ *      startX = Px.Zero,
+ *      endX = Px(100.0f)
+ * )
+ * ```
+ */
+fun HorizontalGradient(
+    vararg colorStops: ColorStop,
+    startX: Px,
+    endX: Px,
+    tileMode: TileMode = TileMode.clamp
+): Brush {
+    return LinearGradient(
+        List<Color>(colorStops.size) { i -> colorStops[i].second },
+        List<Float>(colorStops.size) { i -> colorStops[i].first },
+        startX = startX,
+        startY = Px.Zero,
+        endX = endX,
+        endY = Px.Zero,
+        tileMode = tileMode
+    )
+}
+
+/**
+ * Brush implementation used to apply a linear gradient on a given [Paint]
+ */
+data class LinearGradient internal constructor(
+    val colors: List<Color>,
+    val stops: List<Float>? = null,
+    val startX: Px,
+    val startY: Px,
+    val endX: Px,
+    val endY: Px,
+    val tileMode: TileMode = TileMode.clamp
+) : Brush {
+
+    override fun applyBrush(p: Paint) {
+        p.shader = Gradient.linear(
+            Offset(startX.value, startY.value),
+            Offset(endX.value, endY.value),
+            colors,
+            stops,
+            tileMode)
+    }
+}
+
+/**
+ * Brush implementation used to apply a radial gradient on a given [Paint]
+ */
+data class RadialGradient internal constructor(
+    private val colors: List<Color>,
+    private val stops: List<Float>? = null,
+    private val centerX: Float,
+    private val centerY: Float,
+    private val radius: Float,
+    private val tileMode: TileMode = TileMode.clamp
+) : Brush {
+
+    override fun applyBrush(p: Paint) {
+        p.shader = Gradient.radial(
+            Offset(centerX, centerY),
+            radius, colors, stops, tileMode, Matrix4())
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathBuilder.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathBuilder.kt
similarity index 95%
rename from ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathBuilder.kt
rename to ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathBuilder.kt
index 52cb119..6c634eb 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathBuilder.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathBuilder.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.core.vectorgraphics
+package androidx.ui.graphics.vectorgraphics
 
 class PathBuilder {
 
@@ -93,7 +93,8 @@
         sweepFlag: Float,
         x1: Float,
         y1: Float
-    ) = addNode(PathCommand.ArcTo, horizontalEllipseRadius, verticalEllipseRadius, theta,
+    ) = addNode(
+        PathCommand.ArcTo, horizontalEllipseRadius, verticalEllipseRadius, theta,
                 largeArcFlag, sweepFlag, x1, y1)
 
     fun arcToRelative(
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathCommand.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathCommand.kt
similarity index 96%
rename from ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathCommand.kt
rename to ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathCommand.kt
index 29e3bde..b8e9f1d 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathCommand.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathCommand.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.core.vectorgraphics
+package androidx.ui.graphics.vectorgraphics
 
 enum class PathCommand(private val mKey: Char) {
 
@@ -49,9 +49,7 @@
  * Return the corresponding PathCommand for the given character key if it exists.
  * If the key is unknown then IllegalArgumentException is thrown
  * @return PathCommand that matches the key
- * @throws IllegalArgumentException if the key is invalid
  */
-@Throws(IllegalArgumentException::class)
 fun Char.toPathCommand(): PathCommand = when (this) {
     RelativeCloseKey -> PathCommand.RelativeClose
     CloseKey -> PathCommand.Close
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathNode.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathNode.kt
similarity index 97%
rename from ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathNode.kt
rename to ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathNode.kt
index 4d0accc..57833ca 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathNode.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathNode.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.core.vectorgraphics
+package androidx.ui.graphics.vectorgraphics
 
 import kotlin.text.StringBuilder
 
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathParser.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathParser.kt
similarity index 97%
rename from ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathParser.kt
rename to ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathParser.kt
index 7724ccf..553eb32 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/PathParser.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/PathParser.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.ui.core.vectorgraphics
+package androidx.ui.graphics.vectorgraphics
 
 import android.util.Log
 import androidx.ui.painting.Path
@@ -51,7 +51,11 @@
     private val segmentPoint = PathPoint()
     private val reflectiveCtrlPoint = PathPoint()
 
-    @Throws(java.lang.IllegalArgumentException::class, NumberFormatException::class)
+    /**
+     * Parses the path string to create a collection of PathNode instances with their corresponding
+     * arguments
+     * throws an IllegalArgumentException or NumberFormatException if the parameters are invalid
+     */
     fun parsePathString(pathData: String): PathParser {
         nodes.clear()
 
@@ -348,7 +352,9 @@
         }
 
     private fun reflectiveQuadTo(prevCmd: PathCommand, target: Path, args: FloatArray) {
-        forEachPathArg(args, NUM_REFLECTIVE_QUAD_TO_ARGS) { index ->
+        forEachPathArg(args,
+            NUM_REFLECTIVE_QUAD_TO_ARGS
+        ) { index ->
             val x1 = args[index]
             val y1 = args[index + 1]
             if (prevCmd.isQuad()) {
@@ -368,7 +374,9 @@
     }
 
     private fun relativeReflectiveQuadTo(prevCmd: PathCommand, target: Path, args: FloatArray) {
-        forEachPathArg(args, NUM_REFLECTIVE_QUAD_TO_ARGS) { index ->
+        forEachPathArg(args,
+            NUM_REFLECTIVE_QUAD_TO_ARGS
+        ) { index ->
             val x1 = args[index]
             val y1 = args[index + 1]
             if (prevCmd.isQuad()) {
@@ -448,7 +456,9 @@
             }
 
     private fun reflectiveCurveTo(prevCmd: PathCommand, target: Path, args: FloatArray) {
-        forEachPathArg(args, NUM_REFLECTIVE_CURVE_TO_ARGS) { index ->
+        forEachPathArg(args,
+            NUM_REFLECTIVE_CURVE_TO_ARGS
+        ) { index ->
             val x1 = args[index]
             val y1 = args[index + 1]
             val x2 = args[index + 2]
@@ -472,7 +482,9 @@
     }
 
     private fun relativeReflectiveCurveTo(prevCmd: PathCommand, target: Path, args: FloatArray) {
-        forEachPathArg(args, NUM_REFLECTIVE_CURVE_TO_ARGS) { index ->
+        forEachPathArg(args,
+            NUM_REFLECTIVE_CURVE_TO_ARGS
+        ) { index ->
             val x1 = args[index]
             val y1 = args[index + 1]
             val x2 = args[index + 2]
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Vector.kt b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Vector.kt
similarity index 67%
rename from ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Vector.kt
rename to ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Vector.kt
index 9fd6bb1..920b59e 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Vector.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/graphics/vectorgraphics/Vector.kt
@@ -14,37 +14,33 @@
  * limitations under the License.
  */
 
-package androidx.ui.core.vectorgraphics
+package androidx.ui.graphics.vectorgraphics
 
-import android.graphics.ColorFilter
 import android.graphics.Matrix
-import android.graphics.PixelFormat
-import android.graphics.drawable.Drawable
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
 import androidx.ui.engine.geometry.Offset
 import androidx.ui.painting.Canvas
 import androidx.ui.painting.Image
 import androidx.ui.painting.Paint
 import androidx.ui.painting.PaintingStyle
+import androidx.ui.painting.Path
 import androidx.ui.painting.StrokeCap
 import androidx.ui.painting.StrokeJoin
 import androidx.compose.Children
 import androidx.compose.Composable
 import androidx.compose.Emittable
 import androidx.compose.composer
+import androidx.ui.core.Px
 import androidx.ui.painting.withSave
-import androidx.ui.painting.Path as PaintingPath
+import kotlin.math.ceil
 
 const val DefaultGroupName = ""
-const val DefaultRotate = 0.0f
+const val DefaultRotation = 0.0f
 const val DefaultPivotX = 0.0f
 const val DefaultPivotY = 0.0f
 const val DefaultScaleX = 1.0f
 const val DefaultScaleY = 1.0f
-const val DefaultTranslateX = 0.0f
-const val DefaultTranslateY = 0.0f
+const val DefaultTranslationX = 0.0f
+const val DefaultTranslationY = 0.0f
 
 val EmptyPath = emptyArray<PathNode>()
 
@@ -79,96 +75,23 @@
         PathParser().parsePathString(pathStr).toNodes()
     }
 
-@Composable
-fun vector(
-    name: String = "",
-    viewportWidth: Float,
-    viewportHeight: Float,
-    defaultWidth: Float = viewportWidth,
-    defaultHeight: Float = viewportHeight,
-    @Children children: @Composable() () -> Unit
-) {
-    <Vector name defaultWidth defaultHeight viewportWidth viewportHeight>
-        children()
-    </Vector>
-}
-
-@Composable
-fun group(
-    name: String = DefaultGroupName,
-    rotate: Float = DefaultRotate,
-    pivotX: Float = DefaultPivotX,
-    pivotY: Float = DefaultPivotY,
-    scaleX: Float = DefaultScaleX,
-    scaleY: Float = DefaultScaleY,
-    translateX: Float = DefaultTranslateX,
-    translateY: Float = DefaultTranslateY,
-    clipPathData: PathData = EmptyPath,
-    @Children childNodes: @Composable() () -> Unit
-) {
-
-    val clipPathNodes = createPath(clipPathData)
-    <Group
-        name
-        rotate
-        pivotX
-        pivotY
-        scaleX
-        scaleY
-        translateX
-        translateY
-        clipPathNodes>
-        childNodes()
-    </Group>
-}
-
-@Composable
-fun path(
-    pathData: PathData,
-    name: String = DefaultPathName,
-    fill: BrushType = EmptyBrush,
-    fillAlpha: Float = DefaultAlpha,
-    stroke: BrushType = EmptyBrush,
-    strokeAlpha: Float = DefaultAlpha,
-    strokeLineWidth: Float = DefaultStrokeLineWidth,
-    strokeLineCap: StrokeCap = DefaultStrokeLineCap,
-    strokeLineJoin: StrokeJoin = DefaultStrokeLineJoin,
-    strokeLineMiter: Float = DefaultStrokeLineMiter
-) {
-    val pathNodes = createPath(pathData)
-    val fillBrush: Brush = obtainBrush(fill)
-    val strokeBrush: Brush = obtainBrush(stroke)
-
-    <Path
-        name
-        pathNodes
-        fill=fillBrush
-        fillAlpha
-        stroke=strokeBrush
-        strokeAlpha
-        strokeLineWidth
-        strokeLineCap
-        strokeLineJoin
-        strokeLineMiter />
-}
-
-private sealed class VNode {
+sealed class VNode {
     abstract fun draw(canvas: Canvas)
 }
 
-private class Vector(
+class VectorComponent(
     val name: String = "",
-    val viewportWidth: Float,
-    val viewportHeight: Float,
-    val defaultWidth: Float = viewportWidth,
-    val defaultHeight: Float = viewportHeight
-) : VNode(), Emittable {
+    var viewportWidth: Float,
+    var viewportHeight: Float,
+    var defaultWidth: Px,
+    var defaultHeight: Px
+) : VNode() {
 
-    private val root = Group(this@Vector.name).apply {
+    val root = GroupComponent(this@VectorComponent.name).apply {
         pivotX = 0.0f
         pivotY = 0.0f
-        scaleX = defaultWidth / viewportWidth
-        scaleY = defaultHeight / viewportHeight
+        scaleX = defaultWidth.value / viewportWidth
+        scaleY = defaultHeight.value / viewportHeight
     }
 
     /**
@@ -185,8 +108,8 @@
         var targetImage = cachedImage
         if (targetImage == null) {
             targetImage = Image(
-                kotlin.math.ceil(defaultWidth).toInt(),
-                kotlin.math.ceil(defaultHeight).toInt()
+                ceil(defaultWidth.value).toInt(),
+                ceil(defaultHeight.value).toInt()
             )
             cachedImage = targetImage
             root.draw(Canvas(targetImage))
@@ -204,21 +127,9 @@
             append("\tviewportHeight: ").append(viewportHeight).append("\n")
         }
     }
-
-    override fun emitInsertAt(index: Int, instance: Emittable) {
-        root.emitInsertAt(index, instance)
-    }
-
-    override fun emitMove(from: Int, to: Int, count: Int) {
-        root.emitMove(from, to, count)
-    }
-
-    override fun emitRemoveAt(index: Int, count: Int) {
-        root.emitRemoveAt(index, count)
-    }
 }
 
-private class Path(val name: String) : VNode(), Emittable {
+class PathComponent(val name: String) : VNode() {
 
     var fill: Brush = EmptyBrush
         set(value) {
@@ -292,7 +203,7 @@
 
     private var isPathDirty = true
 
-    private val path = PaintingPath()
+    private val path = Path()
 
     private var fillPaint: Paint? = null
     private var strokePaint: Paint? = null
@@ -366,24 +277,12 @@
         }
     }
 
-    override fun emitInsertAt(index: Int, instance: Emittable) {
-        throw IllegalArgumentException("Unable to insert Emittable into Path")
-    }
-
-    override fun emitMove(from: Int, to: Int, count: Int) {
-        throw IllegalArgumentException("Unable to move Emittable within Path")
-    }
-
-    override fun emitRemoveAt(index: Int, count: Int) {
-        throw IllegalArgumentException("Unable to remove Emittable from Path")
-    }
-
     override fun toString(): String {
         return path.toString()
     }
 }
 
-private class Group(val name: String = DefaultGroupName) : VNode(), Emittable {
+class GroupComponent(val name: String = DefaultGroupName) : VNode() {
 
     private var groupMatrix: Matrix? = null
 
@@ -400,7 +299,7 @@
 
     private var isClipPathDirty = true
 
-    private var clipPath: PaintingPath? = null
+    private var clipPath: Path? = null
     private var parser: PathParser? = null
 
     private fun updateClipPath() {
@@ -415,7 +314,7 @@
 
             var targetClip = clipPath
             if (targetClip == null) {
-                targetClip = PaintingPath()
+                targetClip = Path()
                 clipPath = targetClip
             } else {
                 targetClip.reset()
@@ -425,7 +324,7 @@
         }
     }
 
-    var rotate: Float = DefaultRotate
+    var rotation: Float = DefaultRotation
         set(value) {
             field = value
             isMatrixDirty = true
@@ -455,13 +354,13 @@
             isMatrixDirty = true
         }
 
-    var translateX: Float = DefaultTranslateX
+    var translationX: Float = DefaultTranslationX
         set(value) {
             field = value
             isMatrixDirty = true
         }
 
-    var translateY: Float = DefaultTranslateY
+    var translationY: Float = DefaultTranslationY
         set(value) {
             field = value
             isMatrixDirty = true
@@ -482,23 +381,21 @@
             reset()
             postTranslate(-pivotX, -pivotY)
             postScale(scaleX, scaleY)
-            postRotate(rotate, 0f, 0f)
-            postTranslate(translateX + pivotX,
-                translateY + pivotY)
+            postRotate(rotation, 0f, 0f)
+            postTranslate(translationX + pivotX,
+                translationY + pivotY)
         }
     }
 
-    override fun emitInsertAt(index: Int, instance: Emittable) {
-        if (instance is VNode) {
-            if (index < size) {
-                children[index] = instance
-            } else {
-                children.add(instance)
-            }
+    fun insertAt(index: Int, instance: VNode) {
+        if (index < size) {
+            children[index] = instance
+        } else {
+            children.add(instance)
         }
     }
 
-    override fun emitMove(from: Int, to: Int, count: Int) {
+    fun move(from: Int, to: Int, count: Int) {
         if (from > to) {
             var current = to
             repeat(count) {
@@ -516,7 +413,7 @@
         }
     }
 
-    override fun emitRemoveAt(index: Int, count: Int) {
+    fun remove(index: Int, count: Int) {
         repeat(count) {
             children.removeAt(index)
         }
@@ -563,7 +460,7 @@
     }
 }
 
-private fun createPath(pathData: PathData): Array<PathNode> {
+fun createPath(pathData: PathData): Array<PathNode> {
     @Suppress("UNCHECKED_CAST")
     return when (pathData) {
         is Array<*> -> pathData as Array<PathNode>
@@ -575,39 +472,4 @@
         }
         else -> throw IllegalArgumentException("Must be array of PathNodes or PathDelegate")
     }
-}
-
-// Temporary glue logic to wrap a Vector asset into an ImageView
-fun adoptVectorGraphic(parent: Any?, child: Any?): View? {
-    return if (parent is ViewGroup && child is Vector) {
-        val imageView = ImageView(parent.context)
-        imageView.scaleType = ImageView.ScaleType.FIT_CENTER
-        imageView.setImageDrawable(VectorGraphicDrawable(child))
-        imageView
-    } else {
-        null
-    }
-}
-
-private class VectorGraphicDrawable(private val vector: Vector) : Drawable() {
-
-    override fun getIntrinsicWidth(): Int = Math.round(vector.defaultWidth)
-
-    override fun getIntrinsicHeight(): Int = Math.round(vector.defaultHeight)
-
-    override fun draw(canvas: android.graphics.Canvas) {
-        vector.draw(androidx.ui.painting.Canvas(canvas))
-    }
-
-    override fun setAlpha(alpha: Int) {
-        // TODO support modifying alpha for root of tree down to each node
-        TODO("not implemented")
-    }
-
-    override fun getOpacity(): Int = PixelFormat.UNKNOWN
-
-    override fun setColorFilter(colorFilter: ColorFilter?) {
-        // TODO support color tinting
-        TODO("not implemented")
-    }
-}
+}
\ No newline at end of file
diff --git a/ui/ui-core/src/main/java/androidx/ui/painting/Gradient.kt b/ui/ui-core/src/main/java/androidx/ui/painting/Gradient.kt
index 5094d42..03266c7 100644
--- a/ui/ui-core/src/main/java/androidx/ui/painting/Gradient.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/painting/Gradient.kt
@@ -106,25 +106,19 @@
             color: List<Color>,
             colorStops: List<Float>?,
             tileMode: TileMode = TileMode.clamp,
-            @Suppress("UNUSED_PARAMETER") matrix4: Matrix4,
-            focal: Offset?,
-            focalRadius: Float
+            @Suppress("UNUSED_PARAMETER") matrix4: Matrix4
         ): Gradient {
             _validateColorStops(color, colorStops)
-            if (focal == null || (focal == center && focalRadius == 0.0f)) {
-                TODO("Migration/njawad: add focal support to RadialGradient in framework")
-            } else {
-                // TODO(Migration/njawad use matrix parameter in creation of RadialGradient)
-                val radial = android.graphics.RadialGradient(
-                    center.dx,
-                    center.dy,
-                    radius,
-                    toIntArray(color),
-                    toFloatArray(colorStops),
-                    toFrameworkTileMode(tileMode)
-                )
-                return Gradient(radial)
-            }
+            // TODO(Migration/njawad use matrix parameter in creation of RadialGradient)
+            val radial = android.graphics.RadialGradient(
+                center.dx,
+                center.dy,
+                radius,
+                toIntArray(color),
+                toFloatArray(colorStops),
+                toFrameworkTileMode(tileMode)
+            )
+            return Gradient(radial)
         }
 
         /**
@@ -202,9 +196,9 @@
 
         private fun _validateColorStops(colors: List<Color>, colorStops: List<Float>?) {
             if (colorStops == null) {
-                if (colors.size != 2) {
+                if (colors.size < 2) {
                     throw IllegalArgumentException(
-                        "colors must have length 2 if colorStops " +
+                        "colors must have length of at least 2 if colorStops " +
                                 "is omitted."
                     )
                 }
diff --git a/ui/ui-core/src/main/java/androidx/ui/testutils/PointerInputTestUtil.kt b/ui/ui-core/src/main/java/androidx/ui/testutils/PointerInputTestUtil.kt
index 335e2c9..e00bfbf 100644
--- a/ui/ui-core/src/main/java/androidx/ui/testutils/PointerInputTestUtil.kt
+++ b/ui/ui-core/src/main/java/androidx/ui/testutils/PointerInputTestUtil.kt
@@ -96,3 +96,14 @@
     PointerEventPass.PostUp,
     PointerEventPass.PostDown
 )
+
+fun PointerInputHandler.invokeOverAllPasses(
+    vararg pointerInputChanges: PointerInputChange
+) = invokeOverPasses(
+    pointerInputChanges.toList(),
+    PointerEventPass.InitialDown,
+    PointerEventPass.PreUp,
+    PointerEventPass.PreDown,
+    PointerEventPass.PostUp,
+    PointerEventPass.PostDown
+)
\ No newline at end of file
diff --git a/ui/ui-foundation/api/1.0.0-alpha01.txt b/ui/ui-foundation/api/1.0.0-alpha01.txt
index ec7e422..f0ceb44 100644
--- a/ui/ui-foundation/api/1.0.0-alpha01.txt
+++ b/ui/ui-foundation/api/1.0.0-alpha01.txt
@@ -8,7 +8,7 @@
 
   public final class ColoredRectKt {
     ctor public ColoredRectKt();
-    method public static void ColoredRect(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
+    method public static void ColoredRect(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
     method public static void ColoredRect(androidx.ui.graphics.Color color, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
   }
 
@@ -132,7 +132,7 @@
   public final class DrawShapeKt {
     ctor public DrawShapeKt();
     method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.Color color);
-    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.core.vectorgraphics.Brush brush);
+    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.vectorgraphics.Brush brush);
   }
 
   public final class GenericShape implements androidx.ui.engine.geometry.Shape {
@@ -151,11 +151,11 @@
 package androidx.ui.foundation.shape.border {
 
   public final class Border {
-    ctor public Border(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush component1();
+    ctor public Border(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush component1();
     method public androidx.ui.core.Dp component2();
-    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush getBrush();
+    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush getBrush();
     method public androidx.ui.core.Dp getWidth();
   }
 
diff --git a/ui/ui-foundation/api/current.txt b/ui/ui-foundation/api/current.txt
index ec7e422..f0ceb44 100644
--- a/ui/ui-foundation/api/current.txt
+++ b/ui/ui-foundation/api/current.txt
@@ -8,7 +8,7 @@
 
   public final class ColoredRectKt {
     ctor public ColoredRectKt();
-    method public static void ColoredRect(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
+    method public static void ColoredRect(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
     method public static void ColoredRect(androidx.ui.graphics.Color color, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
   }
 
@@ -132,7 +132,7 @@
   public final class DrawShapeKt {
     ctor public DrawShapeKt();
     method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.Color color);
-    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.core.vectorgraphics.Brush brush);
+    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.vectorgraphics.Brush brush);
   }
 
   public final class GenericShape implements androidx.ui.engine.geometry.Shape {
@@ -151,11 +151,11 @@
 package androidx.ui.foundation.shape.border {
 
   public final class Border {
-    ctor public Border(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush component1();
+    ctor public Border(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush component1();
     method public androidx.ui.core.Dp component2();
-    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush getBrush();
+    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush getBrush();
     method public androidx.ui.core.Dp getWidth();
   }
 
diff --git a/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt b/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
index ec7e422..f0ceb44 100644
--- a/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-foundation/api/restricted_1.0.0-alpha01.txt
@@ -8,7 +8,7 @@
 
   public final class ColoredRectKt {
     ctor public ColoredRectKt();
-    method public static void ColoredRect(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
+    method public static void ColoredRect(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
     method public static void ColoredRect(androidx.ui.graphics.Color color, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
   }
 
@@ -132,7 +132,7 @@
   public final class DrawShapeKt {
     ctor public DrawShapeKt();
     method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.Color color);
-    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.core.vectorgraphics.Brush brush);
+    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.vectorgraphics.Brush brush);
   }
 
   public final class GenericShape implements androidx.ui.engine.geometry.Shape {
@@ -151,11 +151,11 @@
 package androidx.ui.foundation.shape.border {
 
   public final class Border {
-    ctor public Border(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush component1();
+    ctor public Border(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush component1();
     method public androidx.ui.core.Dp component2();
-    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush getBrush();
+    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush getBrush();
     method public androidx.ui.core.Dp getWidth();
   }
 
diff --git a/ui/ui-foundation/api/restricted_current.txt b/ui/ui-foundation/api/restricted_current.txt
index ec7e422..f0ceb44 100644
--- a/ui/ui-foundation/api/restricted_current.txt
+++ b/ui/ui-foundation/api/restricted_current.txt
@@ -8,7 +8,7 @@
 
   public final class ColoredRectKt {
     ctor public ColoredRectKt();
-    method public static void ColoredRect(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
+    method public static void ColoredRect(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
     method public static void ColoredRect(androidx.ui.graphics.Color color, androidx.ui.core.Dp? width = null, androidx.ui.core.Dp? height = null);
   }
 
@@ -132,7 +132,7 @@
   public final class DrawShapeKt {
     ctor public DrawShapeKt();
     method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.Color color);
-    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.core.vectorgraphics.Brush brush);
+    method public static void DrawShape(androidx.ui.engine.geometry.Shape shape, androidx.ui.graphics.vectorgraphics.Brush brush);
   }
 
   public final class GenericShape implements androidx.ui.engine.geometry.Shape {
@@ -151,11 +151,11 @@
 package androidx.ui.foundation.shape.border {
 
   public final class Border {
-    ctor public Border(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush component1();
+    ctor public Border(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush component1();
     method public androidx.ui.core.Dp component2();
-    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.core.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
-    method public androidx.ui.core.vectorgraphics.Brush getBrush();
+    method public androidx.ui.foundation.shape.border.Border copy(androidx.ui.graphics.vectorgraphics.Brush brush, androidx.ui.core.Dp width);
+    method public androidx.ui.graphics.vectorgraphics.Brush getBrush();
     method public androidx.ui.core.Dp getWidth();
   }
 
diff --git a/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/ColoredRectSamples.kt b/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/ColoredRectSamples.kt
index d90e8ac3..5a688a7 100644
--- a/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/ColoredRectSamples.kt
+++ b/ui/ui-foundation/integration-tests/samples/src/main/java/androidx/ui/foundation/samples/ColoredRectSamples.kt
@@ -20,9 +20,9 @@
 import androidx.compose.Composable
 import androidx.compose.composer
 import androidx.ui.core.dp
-import androidx.ui.core.vectorgraphics.SolidColor
 import androidx.ui.foundation.ColoredRect
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.vectorgraphics.SolidColor
 
 @Sampled
 @Composable
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
index 1730ce1..bee68c7 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Clickable.kt
@@ -40,7 +40,7 @@
 fun Clickable(
     onClick: (() -> Unit)? = null,
     consumeDownOnStart: Boolean = false,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Semantics(
         button = true,
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/ColoredRect.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/ColoredRect.kt
index 757de7f..ab71fd2 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/ColoredRect.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/ColoredRect.kt
@@ -20,15 +20,12 @@
 import androidx.compose.composer
 import androidx.compose.trace
 import androidx.ui.core.Dp
-import androidx.ui.core.Draw
-import androidx.ui.core.toRect
-import androidx.ui.core.vectorgraphics.Brush
-import androidx.ui.core.vectorgraphics.SolidColor
 import androidx.ui.foundation.shape.DrawShape
 import androidx.ui.foundation.shape.RectangleShape
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.vectorgraphics.Brush
+import androidx.ui.graphics.vectorgraphics.SolidColor
 import androidx.ui.layout.Container
-import androidx.ui.painting.Paint
 
 /**
  * Component that represents a rectangle painted with the specified [Brush].
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/DeterminateProgressIndicator.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/DeterminateProgressIndicator.kt
index 1182bfe..a40b834 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/DeterminateProgressIndicator.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/DeterminateProgressIndicator.kt
@@ -36,7 +36,7 @@
 @Composable
 fun DeterminateProgressIndicator(
     @FloatRange(from = 0.0, to = 1.0) progress: Float,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     if (progress !in 0f..1f) {
         throw IllegalArgumentException("Progress must be between 0.0 and 1.0")
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
index 8ccc5b6..b6ad191 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/Dialog.kt
@@ -47,7 +47,7 @@
  * @param children The content to be displayed inside the dialog.
  */
 @Composable
-fun Dialog(onCloseRequest: () -> Unit, @Children children: @Composable() () -> Unit) {
+fun Dialog(onCloseRequest: () -> Unit, children: @Composable() () -> Unit) {
     val context = +ambient(ContextAmbient)
 
     val dialog = +memo { DialogWrapper(context, onCloseRequest) }
@@ -72,7 +72,7 @@
         setContentView(frameLayout)
     }
 
-    fun setContent(@Children children: @Composable() () -> Unit) {
+    fun setContent(children: @Composable() () -> Unit) {
         frameLayout.setContent(children)
     }
 
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/MutuallyExclusiveSetItem.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/MutuallyExclusiveSetItem.kt
index af44074..a199158 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/MutuallyExclusiveSetItem.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/MutuallyExclusiveSetItem.kt
@@ -37,7 +37,7 @@
 fun MutuallyExclusiveSetItem(
     selected: Boolean,
     onClick: () -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     // TODO: when semantics can be merged, we should make this use Clickable internally rather
     // than duplicating logic
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
index 6531828..a9f6f7b 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/selection/Toggleable.kt
@@ -28,7 +28,7 @@
 fun Toggleable(
     value: ToggleableState = ToggleableState.Checked,
     onToggle: (() -> Unit)? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val actions = if (onToggle != null) {
         listOf(SemanticsAction(SemanticsActionType.Tap, onToggle))
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/DrawShape.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/DrawShape.kt
index 6a093bb..1cd22be 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/DrawShape.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/DrawShape.kt
@@ -22,12 +22,12 @@
 import androidx.compose.unaryPlus
 import androidx.ui.core.Draw
 import androidx.ui.core.PxSize
-import androidx.ui.core.vectorgraphics.Brush
-import androidx.ui.core.vectorgraphics.SolidColor
 import androidx.ui.engine.geometry.Outline
 import androidx.ui.engine.geometry.Shape
 import androidx.ui.engine.geometry.drawOutline
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.vectorgraphics.Brush
+import androidx.ui.graphics.vectorgraphics.SolidColor
 import androidx.ui.painting.Paint
 
 /**
diff --git a/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/border/Border.kt b/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/border/Border.kt
index 3a66465..62f871a 100644
--- a/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/border/Border.kt
+++ b/ui/ui-foundation/src/main/java/androidx/ui/foundation/shape/border/Border.kt
@@ -17,9 +17,9 @@
 package androidx.ui.foundation.shape.border
 
 import androidx.ui.core.Dp
-import androidx.ui.core.vectorgraphics.Brush
-import androidx.ui.core.vectorgraphics.SolidColor
 import androidx.ui.graphics.Color
+import androidx.ui.graphics.vectorgraphics.Brush
+import androidx.ui.graphics.vectorgraphics.SolidColor
 
 /**
  * A border of a shape.
diff --git a/ui/ui-framework/api/1.0.0-alpha01.txt b/ui/ui-framework/api/1.0.0-alpha01.txt
index 224764c..01e28d9 100644
--- a/ui/ui-framework/api/1.0.0-alpha01.txt
+++ b/ui/ui-framework/api/1.0.0-alpha01.txt
@@ -7,7 +7,7 @@
   }
 
   public final class ComplexLayoutReceiver {
-    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public void maxIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicHeightBlock);
     method public void maxIntrinsicWidth(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicWidthBlock);
     method public void minIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> minIntrinsicHeightBlock);
@@ -43,7 +43,7 @@
 
   public final class LayoutBlockReceiver implements androidx.ui.core.DensityReceiver {
     method public androidx.ui.core.Density getDensity();
-    method public void layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.IntPx maxIntrinsicHeight(androidx.ui.core.Measurable, androidx.ui.core.IntPx w);
     method public androidx.ui.core.IntPx maxIntrinsicWidth(androidx.ui.core.Measurable, androidx.ui.core.IntPx h);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
@@ -67,8 +67,8 @@
   public final class LayoutKt {
     ctor public LayoutKt();
     method public static void ComplexLayout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function1<? super androidx.ui.core.ComplexLayoutReceiver,kotlin.Unit> block);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public static void OnChildPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public static void OnPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned);
     method public static void WithConstraints(kotlin.jvm.functions.Function1<? super androidx.ui.core.Constraints,kotlin.Unit> children);
@@ -77,11 +77,18 @@
   public final class LayoutReceiver implements androidx.ui.core.DensityReceiver {
     method public operator java.util.List<androidx.ui.core.Measurable> get(java.util.List<? extends androidx.ui.core.Measurable>, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public androidx.ui.core.Density getDensity();
-    method public void layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
     property public androidx.ui.core.Density density;
   }
 
+  public final class LayoutResult {
+    field public static final androidx.ui.core.LayoutResult.Companion! Companion;
+  }
+
+  public static final class LayoutResult.Companion {
+  }
+
   public interface Measurable {
     method public Object? getParentData();
     property public abstract Object? parentData;
@@ -148,7 +155,7 @@
 
   public final class TextFieldKt {
     ctor public TextFieldKt();
-    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
+    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onBlur = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
   }
 
   public final class TextKt {
@@ -241,6 +248,11 @@
     method public static androidx.ui.core.Duration getZoomControlsTimeout();
   }
 
+  public final class DoubleTapGestureDetectorKt {
+    ctor public DoubleTapGestureDetectorKt();
+    method public static void DoubleTapGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.PxPosition,kotlin.Unit> onDoubleTap, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class DragGestureDetectorKt {
     ctor public DragGestureDetectorKt();
     method public static void DragGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.Direction,java.lang.Boolean>? canDrag = null, androidx.ui.core.gesture.DragObserver? dragObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit> children);
@@ -334,143 +346,74 @@
 
 package androidx.ui.core.vectorgraphics {
 
-  public interface Brush {
-    method public void applyBrush(androidx.ui.painting.Paint p);
+  public final class VectorAsset {
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.core.vectorgraphics.VectorGroup getRoot();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
   }
 
-  public final class BrushKt {
-    ctor public BrushKt();
-    method public static androidx.ui.core.vectorgraphics.Brush getEmptyBrush();
-    method public static androidx.ui.core.vectorgraphics.Brush obtainBrush(Object? brush);
+  public final class VectorAssetBuilder {
+    ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder addPath(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
+    method public androidx.ui.core.vectorgraphics.VectorAsset build();
+    method public void ensureNotConsumed();
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder popGroup();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder pushGroup(String name = "", float rotate = 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, Object? clipPathData = EmptyPath);
   }
 
-  public final class LinearGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public LinearGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float startX, float startY, float endX, float endY, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-    method public float getEndX();
-    method public float getEndY();
-    method public float getStartX();
-    method public float getStartY();
-    method public androidx.ui.painting.TileMode getTileMode();
+  public final class VectorAssetKt {
+    ctor public VectorAssetKt();
+    method public static void DrawVector(androidx.ui.core.vectorgraphics.VectorAsset vectorImage);
   }
 
-  public final class PathBuilder {
-    ctor public PathBuilder();
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder close();
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
-    method public androidx.ui.core.vectorgraphics.PathNode![] getNodes();
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineTo(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineTo(float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  public final class VectorComposeKt {
+    ctor public VectorComposeKt();
+    method public static void DrawVector(float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth = Px(viewportWidth), androidx.ui.core.Px defaultHeight = Px(viewportHeight), String name = "", kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Group(androidx.ui.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, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Path(androidx.ui.vector.VectorScope, Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
 
-  public enum PathCommand {
-    method public final char toKey();
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand Close;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand CurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand HorizontalLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand LineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand MoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand QuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeClose;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeHorizontalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeMoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeVerticalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand VerticalLineTo;
+  public final class VectorGroup extends androidx.ui.core.vectorgraphics.VectorNode implements java.lang.Iterable<androidx.ui.core.vectorgraphics.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, Object? clipPathData);
+    ctor public VectorGroup();
+    method public operator androidx.ui.core.vectorgraphics.VectorNode get(int index);
+    method public Object? getClipPathData();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public java.util.Iterator<androidx.ui.core.vectorgraphics.VectorNode> iterator();
+    property public final int size;
   }
 
-  public final class PathCommandKt {
-    ctor public PathCommandKt();
-    method public static androidx.ui.core.vectorgraphics.PathCommand toPathCommand(char) throws java.lang.IllegalArgumentException;
+  public abstract sealed class VectorNode {
   }
 
-  public final class PathDelegate {
-    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
-    method public kotlin.jvm.functions.Function1<androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
-  }
-
-  public final class PathNode {
-    ctor public PathNode(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public androidx.ui.core.vectorgraphics.PathCommand component1();
-    method public float[] component2();
-    method public androidx.ui.core.vectorgraphics.PathNode copy(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public float[] getArgs();
-    method public androidx.ui.core.vectorgraphics.PathCommand getCommand();
-  }
-
-  public final class PathNodeKt {
-    ctor public PathNodeKt();
-    method public static operator StringBuilder plus(StringBuilder, androidx.ui.core.vectorgraphics.PathNode node);
-  }
-
-  public final class PathParser {
-    ctor public PathParser();
-    method public androidx.ui.core.vectorgraphics.PathParser addPathNodes(androidx.ui.core.vectorgraphics.PathNode![] nodes);
-    method public void clear();
-    method public androidx.ui.core.vectorgraphics.PathParser parsePathString(String pathData) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException;
-    method public androidx.ui.core.vectorgraphics.PathNode![] toNodes();
-    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = Path());
-  }
-
-  public final class PathParserKt {
-    ctor public PathParserKt();
-  }
-
-  public final class RadialGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public RadialGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class SolidColor implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public SolidColor(androidx.ui.graphics.Color value);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class VectorKt {
-    ctor public VectorKt();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
-    method public static android.view.View? adoptVectorGraphic(Object? parent, Object? child);
-    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
-    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] getEmptyPath();
-    method public static void group(String name = "", float rotate = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translateX = 0.0f, float translateY = 0.0f, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function0<kotlin.Unit> childNodes);
-    method public static void path(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
-    method public static void vector(String name = "", float viewportWidth, float viewportHeight, float defaultWidth = viewportWidth, float defaultHeight = viewportHeight, kotlin.jvm.functions.Function0<kotlin.Unit> children);
-    field public static final float DefaultAlpha = 1.0f;
-    field public static final String DefaultGroupName = "";
-    field public static final String DefaultPathName = "";
-    field public static final float DefaultPivotX = 0.0f;
-    field public static final float DefaultPivotY = 0.0f;
-    field public static final float DefaultRotate = 0.0f;
-    field public static final float DefaultScaleX = 1.0f;
-    field public static final float DefaultScaleY = 1.0f;
-    field public static final float DefaultStrokeLineMiter = 4.0f;
-    field public static final float DefaultStrokeLineWidth = 0.0f;
-    field public static final float DefaultTranslateX = 0.0f;
-    field public static final float DefaultTranslateY = 0.0f;
+  public final class VectorPath extends androidx.ui.core.vectorgraphics.VectorNode {
+    ctor public VectorPath(String name, Object? pathData, Object fill, float fillAlpha, Object stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.painting.StrokeCap strokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin, float strokeLineMiter);
+    method public Object getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public Object? getPathData();
+    method public Object getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
   }
 
 }
@@ -479,7 +422,12 @@
 
   public final class VectorResourceKt {
     ctor public VectorResourceKt();
-    method public static void vectorResource(android.content.res.Resources res, int resId);
+    method public static void VectorResource(int resId);
+    method public static androidx.ui.core.vectorgraphics.VectorAsset loadVectorResource(android.content.res.Resources.Theme? theme = null, android.content.res.Resources res, int resId) throws org.xmlpull.v1.XmlPullParserException;
+  }
+
+  public final class XmlVectorParserKt {
+    ctor public XmlVectorParserKt();
   }
 
 }
diff --git a/ui/ui-framework/api/current.txt b/ui/ui-framework/api/current.txt
index 224764c..01e28d9 100644
--- a/ui/ui-framework/api/current.txt
+++ b/ui/ui-framework/api/current.txt
@@ -7,7 +7,7 @@
   }
 
   public final class ComplexLayoutReceiver {
-    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public void maxIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicHeightBlock);
     method public void maxIntrinsicWidth(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicWidthBlock);
     method public void minIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> minIntrinsicHeightBlock);
@@ -43,7 +43,7 @@
 
   public final class LayoutBlockReceiver implements androidx.ui.core.DensityReceiver {
     method public androidx.ui.core.Density getDensity();
-    method public void layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.IntPx maxIntrinsicHeight(androidx.ui.core.Measurable, androidx.ui.core.IntPx w);
     method public androidx.ui.core.IntPx maxIntrinsicWidth(androidx.ui.core.Measurable, androidx.ui.core.IntPx h);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
@@ -67,8 +67,8 @@
   public final class LayoutKt {
     ctor public LayoutKt();
     method public static void ComplexLayout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function1<? super androidx.ui.core.ComplexLayoutReceiver,kotlin.Unit> block);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public static void OnChildPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public static void OnPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned);
     method public static void WithConstraints(kotlin.jvm.functions.Function1<? super androidx.ui.core.Constraints,kotlin.Unit> children);
@@ -77,11 +77,18 @@
   public final class LayoutReceiver implements androidx.ui.core.DensityReceiver {
     method public operator java.util.List<androidx.ui.core.Measurable> get(java.util.List<? extends androidx.ui.core.Measurable>, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public androidx.ui.core.Density getDensity();
-    method public void layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
     property public androidx.ui.core.Density density;
   }
 
+  public final class LayoutResult {
+    field public static final androidx.ui.core.LayoutResult.Companion! Companion;
+  }
+
+  public static final class LayoutResult.Companion {
+  }
+
   public interface Measurable {
     method public Object? getParentData();
     property public abstract Object? parentData;
@@ -148,7 +155,7 @@
 
   public final class TextFieldKt {
     ctor public TextFieldKt();
-    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
+    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onBlur = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
   }
 
   public final class TextKt {
@@ -241,6 +248,11 @@
     method public static androidx.ui.core.Duration getZoomControlsTimeout();
   }
 
+  public final class DoubleTapGestureDetectorKt {
+    ctor public DoubleTapGestureDetectorKt();
+    method public static void DoubleTapGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.PxPosition,kotlin.Unit> onDoubleTap, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class DragGestureDetectorKt {
     ctor public DragGestureDetectorKt();
     method public static void DragGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.Direction,java.lang.Boolean>? canDrag = null, androidx.ui.core.gesture.DragObserver? dragObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit> children);
@@ -334,143 +346,74 @@
 
 package androidx.ui.core.vectorgraphics {
 
-  public interface Brush {
-    method public void applyBrush(androidx.ui.painting.Paint p);
+  public final class VectorAsset {
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.core.vectorgraphics.VectorGroup getRoot();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
   }
 
-  public final class BrushKt {
-    ctor public BrushKt();
-    method public static androidx.ui.core.vectorgraphics.Brush getEmptyBrush();
-    method public static androidx.ui.core.vectorgraphics.Brush obtainBrush(Object? brush);
+  public final class VectorAssetBuilder {
+    ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder addPath(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
+    method public androidx.ui.core.vectorgraphics.VectorAsset build();
+    method public void ensureNotConsumed();
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder popGroup();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder pushGroup(String name = "", float rotate = 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, Object? clipPathData = EmptyPath);
   }
 
-  public final class LinearGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public LinearGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float startX, float startY, float endX, float endY, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-    method public float getEndX();
-    method public float getEndY();
-    method public float getStartX();
-    method public float getStartY();
-    method public androidx.ui.painting.TileMode getTileMode();
+  public final class VectorAssetKt {
+    ctor public VectorAssetKt();
+    method public static void DrawVector(androidx.ui.core.vectorgraphics.VectorAsset vectorImage);
   }
 
-  public final class PathBuilder {
-    ctor public PathBuilder();
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder close();
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
-    method public androidx.ui.core.vectorgraphics.PathNode![] getNodes();
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineTo(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineTo(float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  public final class VectorComposeKt {
+    ctor public VectorComposeKt();
+    method public static void DrawVector(float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth = Px(viewportWidth), androidx.ui.core.Px defaultHeight = Px(viewportHeight), String name = "", kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Group(androidx.ui.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, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Path(androidx.ui.vector.VectorScope, Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
 
-  public enum PathCommand {
-    method public final char toKey();
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand Close;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand CurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand HorizontalLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand LineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand MoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand QuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeClose;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeHorizontalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeMoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeVerticalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand VerticalLineTo;
+  public final class VectorGroup extends androidx.ui.core.vectorgraphics.VectorNode implements java.lang.Iterable<androidx.ui.core.vectorgraphics.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, Object? clipPathData);
+    ctor public VectorGroup();
+    method public operator androidx.ui.core.vectorgraphics.VectorNode get(int index);
+    method public Object? getClipPathData();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public java.util.Iterator<androidx.ui.core.vectorgraphics.VectorNode> iterator();
+    property public final int size;
   }
 
-  public final class PathCommandKt {
-    ctor public PathCommandKt();
-    method public static androidx.ui.core.vectorgraphics.PathCommand toPathCommand(char) throws java.lang.IllegalArgumentException;
+  public abstract sealed class VectorNode {
   }
 
-  public final class PathDelegate {
-    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
-    method public kotlin.jvm.functions.Function1<androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
-  }
-
-  public final class PathNode {
-    ctor public PathNode(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public androidx.ui.core.vectorgraphics.PathCommand component1();
-    method public float[] component2();
-    method public androidx.ui.core.vectorgraphics.PathNode copy(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public float[] getArgs();
-    method public androidx.ui.core.vectorgraphics.PathCommand getCommand();
-  }
-
-  public final class PathNodeKt {
-    ctor public PathNodeKt();
-    method public static operator StringBuilder plus(StringBuilder, androidx.ui.core.vectorgraphics.PathNode node);
-  }
-
-  public final class PathParser {
-    ctor public PathParser();
-    method public androidx.ui.core.vectorgraphics.PathParser addPathNodes(androidx.ui.core.vectorgraphics.PathNode![] nodes);
-    method public void clear();
-    method public androidx.ui.core.vectorgraphics.PathParser parsePathString(String pathData) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException;
-    method public androidx.ui.core.vectorgraphics.PathNode![] toNodes();
-    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = Path());
-  }
-
-  public final class PathParserKt {
-    ctor public PathParserKt();
-  }
-
-  public final class RadialGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public RadialGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class SolidColor implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public SolidColor(androidx.ui.graphics.Color value);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class VectorKt {
-    ctor public VectorKt();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
-    method public static android.view.View? adoptVectorGraphic(Object? parent, Object? child);
-    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
-    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] getEmptyPath();
-    method public static void group(String name = "", float rotate = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translateX = 0.0f, float translateY = 0.0f, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function0<kotlin.Unit> childNodes);
-    method public static void path(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
-    method public static void vector(String name = "", float viewportWidth, float viewportHeight, float defaultWidth = viewportWidth, float defaultHeight = viewportHeight, kotlin.jvm.functions.Function0<kotlin.Unit> children);
-    field public static final float DefaultAlpha = 1.0f;
-    field public static final String DefaultGroupName = "";
-    field public static final String DefaultPathName = "";
-    field public static final float DefaultPivotX = 0.0f;
-    field public static final float DefaultPivotY = 0.0f;
-    field public static final float DefaultRotate = 0.0f;
-    field public static final float DefaultScaleX = 1.0f;
-    field public static final float DefaultScaleY = 1.0f;
-    field public static final float DefaultStrokeLineMiter = 4.0f;
-    field public static final float DefaultStrokeLineWidth = 0.0f;
-    field public static final float DefaultTranslateX = 0.0f;
-    field public static final float DefaultTranslateY = 0.0f;
+  public final class VectorPath extends androidx.ui.core.vectorgraphics.VectorNode {
+    ctor public VectorPath(String name, Object? pathData, Object fill, float fillAlpha, Object stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.painting.StrokeCap strokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin, float strokeLineMiter);
+    method public Object getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public Object? getPathData();
+    method public Object getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
   }
 
 }
@@ -479,7 +422,12 @@
 
   public final class VectorResourceKt {
     ctor public VectorResourceKt();
-    method public static void vectorResource(android.content.res.Resources res, int resId);
+    method public static void VectorResource(int resId);
+    method public static androidx.ui.core.vectorgraphics.VectorAsset loadVectorResource(android.content.res.Resources.Theme? theme = null, android.content.res.Resources res, int resId) throws org.xmlpull.v1.XmlPullParserException;
+  }
+
+  public final class XmlVectorParserKt {
+    ctor public XmlVectorParserKt();
   }
 
 }
diff --git a/ui/ui-framework/api/restricted_1.0.0-alpha01.txt b/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
index 224764c..01e28d9 100644
--- a/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-framework/api/restricted_1.0.0-alpha01.txt
@@ -7,7 +7,7 @@
   }
 
   public final class ComplexLayoutReceiver {
-    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public void maxIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicHeightBlock);
     method public void maxIntrinsicWidth(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicWidthBlock);
     method public void minIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> minIntrinsicHeightBlock);
@@ -43,7 +43,7 @@
 
   public final class LayoutBlockReceiver implements androidx.ui.core.DensityReceiver {
     method public androidx.ui.core.Density getDensity();
-    method public void layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.IntPx maxIntrinsicHeight(androidx.ui.core.Measurable, androidx.ui.core.IntPx w);
     method public androidx.ui.core.IntPx maxIntrinsicWidth(androidx.ui.core.Measurable, androidx.ui.core.IntPx h);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
@@ -67,8 +67,8 @@
   public final class LayoutKt {
     ctor public LayoutKt();
     method public static void ComplexLayout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function1<? super androidx.ui.core.ComplexLayoutReceiver,kotlin.Unit> block);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public static void OnChildPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public static void OnPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned);
     method public static void WithConstraints(kotlin.jvm.functions.Function1<? super androidx.ui.core.Constraints,kotlin.Unit> children);
@@ -77,11 +77,18 @@
   public final class LayoutReceiver implements androidx.ui.core.DensityReceiver {
     method public operator java.util.List<androidx.ui.core.Measurable> get(java.util.List<? extends androidx.ui.core.Measurable>, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public androidx.ui.core.Density getDensity();
-    method public void layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
     property public androidx.ui.core.Density density;
   }
 
+  public final class LayoutResult {
+    field public static final androidx.ui.core.LayoutResult.Companion! Companion;
+  }
+
+  public static final class LayoutResult.Companion {
+  }
+
   public interface Measurable {
     method public Object? getParentData();
     property public abstract Object? parentData;
@@ -148,7 +155,7 @@
 
   public final class TextFieldKt {
     ctor public TextFieldKt();
-    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
+    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onBlur = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
   }
 
   public final class TextKt {
@@ -241,6 +248,11 @@
     method public static androidx.ui.core.Duration getZoomControlsTimeout();
   }
 
+  public final class DoubleTapGestureDetectorKt {
+    ctor public DoubleTapGestureDetectorKt();
+    method public static void DoubleTapGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.PxPosition,kotlin.Unit> onDoubleTap, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class DragGestureDetectorKt {
     ctor public DragGestureDetectorKt();
     method public static void DragGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.Direction,java.lang.Boolean>? canDrag = null, androidx.ui.core.gesture.DragObserver? dragObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit> children);
@@ -334,143 +346,74 @@
 
 package androidx.ui.core.vectorgraphics {
 
-  public interface Brush {
-    method public void applyBrush(androidx.ui.painting.Paint p);
+  public final class VectorAsset {
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.core.vectorgraphics.VectorGroup getRoot();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
   }
 
-  public final class BrushKt {
-    ctor public BrushKt();
-    method public static androidx.ui.core.vectorgraphics.Brush getEmptyBrush();
-    method public static androidx.ui.core.vectorgraphics.Brush obtainBrush(Object? brush);
+  public final class VectorAssetBuilder {
+    ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder addPath(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
+    method public androidx.ui.core.vectorgraphics.VectorAsset build();
+    method public void ensureNotConsumed();
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder popGroup();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder pushGroup(String name = "", float rotate = 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, Object? clipPathData = EmptyPath);
   }
 
-  public final class LinearGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public LinearGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float startX, float startY, float endX, float endY, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-    method public float getEndX();
-    method public float getEndY();
-    method public float getStartX();
-    method public float getStartY();
-    method public androidx.ui.painting.TileMode getTileMode();
+  public final class VectorAssetKt {
+    ctor public VectorAssetKt();
+    method public static void DrawVector(androidx.ui.core.vectorgraphics.VectorAsset vectorImage);
   }
 
-  public final class PathBuilder {
-    ctor public PathBuilder();
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder close();
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
-    method public androidx.ui.core.vectorgraphics.PathNode![] getNodes();
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineTo(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineTo(float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  public final class VectorComposeKt {
+    ctor public VectorComposeKt();
+    method public static void DrawVector(float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth = Px(viewportWidth), androidx.ui.core.Px defaultHeight = Px(viewportHeight), String name = "", kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Group(androidx.ui.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, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Path(androidx.ui.vector.VectorScope, Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
 
-  public enum PathCommand {
-    method public final char toKey();
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand Close;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand CurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand HorizontalLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand LineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand MoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand QuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeClose;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeHorizontalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeMoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeVerticalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand VerticalLineTo;
+  public final class VectorGroup extends androidx.ui.core.vectorgraphics.VectorNode implements java.lang.Iterable<androidx.ui.core.vectorgraphics.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, Object? clipPathData);
+    ctor public VectorGroup();
+    method public operator androidx.ui.core.vectorgraphics.VectorNode get(int index);
+    method public Object? getClipPathData();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public java.util.Iterator<androidx.ui.core.vectorgraphics.VectorNode> iterator();
+    property public final int size;
   }
 
-  public final class PathCommandKt {
-    ctor public PathCommandKt();
-    method public static androidx.ui.core.vectorgraphics.PathCommand toPathCommand(char) throws java.lang.IllegalArgumentException;
+  public abstract sealed class VectorNode {
   }
 
-  public final class PathDelegate {
-    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
-    method public kotlin.jvm.functions.Function1<androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
-  }
-
-  public final class PathNode {
-    ctor public PathNode(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public androidx.ui.core.vectorgraphics.PathCommand component1();
-    method public float[] component2();
-    method public androidx.ui.core.vectorgraphics.PathNode copy(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public float[] getArgs();
-    method public androidx.ui.core.vectorgraphics.PathCommand getCommand();
-  }
-
-  public final class PathNodeKt {
-    ctor public PathNodeKt();
-    method public static operator StringBuilder plus(StringBuilder, androidx.ui.core.vectorgraphics.PathNode node);
-  }
-
-  public final class PathParser {
-    ctor public PathParser();
-    method public androidx.ui.core.vectorgraphics.PathParser addPathNodes(androidx.ui.core.vectorgraphics.PathNode![] nodes);
-    method public void clear();
-    method public androidx.ui.core.vectorgraphics.PathParser parsePathString(String pathData) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException;
-    method public androidx.ui.core.vectorgraphics.PathNode![] toNodes();
-    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = Path());
-  }
-
-  public final class PathParserKt {
-    ctor public PathParserKt();
-  }
-
-  public final class RadialGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public RadialGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class SolidColor implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public SolidColor(androidx.ui.graphics.Color value);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class VectorKt {
-    ctor public VectorKt();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
-    method public static android.view.View? adoptVectorGraphic(Object? parent, Object? child);
-    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
-    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] getEmptyPath();
-    method public static void group(String name = "", float rotate = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translateX = 0.0f, float translateY = 0.0f, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function0<kotlin.Unit> childNodes);
-    method public static void path(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
-    method public static void vector(String name = "", float viewportWidth, float viewportHeight, float defaultWidth = viewportWidth, float defaultHeight = viewportHeight, kotlin.jvm.functions.Function0<kotlin.Unit> children);
-    field public static final float DefaultAlpha = 1.0f;
-    field public static final String DefaultGroupName = "";
-    field public static final String DefaultPathName = "";
-    field public static final float DefaultPivotX = 0.0f;
-    field public static final float DefaultPivotY = 0.0f;
-    field public static final float DefaultRotate = 0.0f;
-    field public static final float DefaultScaleX = 1.0f;
-    field public static final float DefaultScaleY = 1.0f;
-    field public static final float DefaultStrokeLineMiter = 4.0f;
-    field public static final float DefaultStrokeLineWidth = 0.0f;
-    field public static final float DefaultTranslateX = 0.0f;
-    field public static final float DefaultTranslateY = 0.0f;
+  public final class VectorPath extends androidx.ui.core.vectorgraphics.VectorNode {
+    ctor public VectorPath(String name, Object? pathData, Object fill, float fillAlpha, Object stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.painting.StrokeCap strokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin, float strokeLineMiter);
+    method public Object getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public Object? getPathData();
+    method public Object getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
   }
 
 }
@@ -479,7 +422,12 @@
 
   public final class VectorResourceKt {
     ctor public VectorResourceKt();
-    method public static void vectorResource(android.content.res.Resources res, int resId);
+    method public static void VectorResource(int resId);
+    method public static androidx.ui.core.vectorgraphics.VectorAsset loadVectorResource(android.content.res.Resources.Theme? theme = null, android.content.res.Resources res, int resId) throws org.xmlpull.v1.XmlPullParserException;
+  }
+
+  public final class XmlVectorParserKt {
+    ctor public XmlVectorParserKt();
   }
 
 }
diff --git a/ui/ui-framework/api/restricted_current.txt b/ui/ui-framework/api/restricted_current.txt
index 224764c..01e28d9 100644
--- a/ui/ui-framework/api/restricted_current.txt
+++ b/ui/ui-framework/api/restricted_current.txt
@@ -7,7 +7,7 @@
   }
 
   public final class ComplexLayoutReceiver {
-    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public void layout(kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutBlockReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public void maxIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicHeightBlock);
     method public void maxIntrinsicWidth(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> maxIntrinsicWidthBlock);
     method public void minIntrinsicHeight(kotlin.jvm.functions.Function3<? super androidx.ui.core.IntrinsicMeasurementsReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.IntPx,androidx.ui.core.IntPx> minIntrinsicHeightBlock);
@@ -43,7 +43,7 @@
 
   public final class LayoutBlockReceiver implements androidx.ui.core.DensityReceiver {
     method public androidx.ui.core.Density getDensity();
-    method public void layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layoutResult(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.IntPx maxIntrinsicHeight(androidx.ui.core.Measurable, androidx.ui.core.IntPx w);
     method public androidx.ui.core.IntPx maxIntrinsicWidth(androidx.ui.core.Measurable, androidx.ui.core.IntPx h);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
@@ -67,8 +67,8 @@
   public final class LayoutKt {
     ctor public LayoutKt();
     method public static void ComplexLayout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function1<? super androidx.ui.core.ComplexLayoutReceiver,kotlin.Unit> block);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
-    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,kotlin.Unit> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit> children, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
+    method public static void Layout(kotlin.jvm.functions.Function0<kotlin.Unit>![] childrenArray, kotlin.jvm.functions.Function3<? super androidx.ui.core.LayoutReceiver,? super java.util.List<? extends androidx.ui.core.Measurable>,? super androidx.ui.core.Constraints,androidx.ui.core.LayoutResult> layoutBlock);
     method public static void OnChildPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public static void OnPositioned(kotlin.jvm.functions.Function1<? super androidx.ui.core.LayoutCoordinates,kotlin.Unit> onPositioned);
     method public static void WithConstraints(kotlin.jvm.functions.Function1<? super androidx.ui.core.Constraints,kotlin.Unit> children);
@@ -77,11 +77,18 @@
   public final class LayoutReceiver implements androidx.ui.core.DensityReceiver {
     method public operator java.util.List<androidx.ui.core.Measurable> get(java.util.List<? extends androidx.ui.core.Measurable>, kotlin.jvm.functions.Function0<kotlin.Unit> children);
     method public androidx.ui.core.Density getDensity();
-    method public void layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
+    method public androidx.ui.core.LayoutResult layout(androidx.ui.core.IntPx width, androidx.ui.core.IntPx height, kotlin.jvm.functions.Function1<? super androidx.ui.core.PositioningBlockReceiver,kotlin.Unit> block);
     method public androidx.ui.core.Placeable measure(androidx.ui.core.Measurable, androidx.ui.core.Constraints constraints);
     property public androidx.ui.core.Density density;
   }
 
+  public final class LayoutResult {
+    field public static final androidx.ui.core.LayoutResult.Companion! Companion;
+  }
+
+  public static final class LayoutResult.Companion {
+  }
+
   public interface Measurable {
     method public Object? getParentData();
     property public abstract Object? parentData;
@@ -148,7 +155,7 @@
 
   public final class TextFieldKt {
     ctor public TextFieldKt();
-    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
+    method public static void TextField(androidx.ui.input.EditorModel value, androidx.ui.core.EditorStyle editorStyle, androidx.ui.input.KeyboardType keyboardType = KeyboardType.Text, androidx.ui.input.ImeAction imeAction = ImeAction.Unspecified, kotlin.jvm.functions.Function1<? super androidx.ui.input.EditorModel,kotlin.Unit> onValueChange = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onFocus = {}, kotlin.jvm.functions.Function0<kotlin.Unit> onBlur = {}, kotlin.jvm.functions.Function1<? super androidx.ui.input.ImeAction,kotlin.Unit> onImeActionPerformed = {}, androidx.ui.core.VisualTransformation? visualTransformation = null);
   }
 
   public final class TextKt {
@@ -241,6 +248,11 @@
     method public static androidx.ui.core.Duration getZoomControlsTimeout();
   }
 
+  public final class DoubleTapGestureDetectorKt {
+    ctor public DoubleTapGestureDetectorKt();
+    method public static void DoubleTapGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.PxPosition,kotlin.Unit> onDoubleTap, kotlin.jvm.functions.Function0<kotlin.Unit> children);
+  }
+
   public final class DragGestureDetectorKt {
     ctor public DragGestureDetectorKt();
     method public static void DragGestureDetector(kotlin.jvm.functions.Function1<? super androidx.ui.core.Direction,java.lang.Boolean>? canDrag = null, androidx.ui.core.gesture.DragObserver? dragObserver = null, kotlin.jvm.functions.Function0<kotlin.Unit> children);
@@ -334,143 +346,74 @@
 
 package androidx.ui.core.vectorgraphics {
 
-  public interface Brush {
-    method public void applyBrush(androidx.ui.painting.Paint p);
+  public final class VectorAsset {
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public androidx.ui.core.vectorgraphics.VectorGroup getRoot();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
   }
 
-  public final class BrushKt {
-    ctor public BrushKt();
-    method public static androidx.ui.core.vectorgraphics.Brush getEmptyBrush();
-    method public static androidx.ui.core.vectorgraphics.Brush obtainBrush(Object? brush);
+  public final class VectorAssetBuilder {
+    ctor public VectorAssetBuilder(String name, androidx.ui.core.Px defaultWidth, androidx.ui.core.Px defaultHeight, float viewportWidth, float viewportHeight);
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder addPath(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
+    method public androidx.ui.core.vectorgraphics.VectorAsset build();
+    method public void ensureNotConsumed();
+    method public androidx.ui.core.Px getDefaultHeight();
+    method public androidx.ui.core.Px getDefaultWidth();
+    method public String getName();
+    method public float getViewportHeight();
+    method public float getViewportWidth();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder popGroup();
+    method public androidx.ui.core.vectorgraphics.VectorAssetBuilder pushGroup(String name = "", float rotate = 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, Object? clipPathData = EmptyPath);
   }
 
-  public final class LinearGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public LinearGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float startX, float startY, float endX, float endY, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-    method public float getEndX();
-    method public float getEndY();
-    method public float getStartX();
-    method public float getStartY();
-    method public androidx.ui.painting.TileMode getTileMode();
+  public final class VectorAssetKt {
+    ctor public VectorAssetKt();
+    method public static void DrawVector(androidx.ui.core.vectorgraphics.VectorAsset vectorImage);
   }
 
-  public final class PathBuilder {
-    ctor public PathBuilder();
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcTo(float horizontalEllipseRadius, float verticalEllipseRadius, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder arcToRelative(float a, float b, float theta, float largeArcFlag, float sweepFlag, float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder close();
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveTo(float x1, float y1, float x2, float y2, float x3, float y3);
-    method public androidx.ui.core.vectorgraphics.PathBuilder curveToRelative(float dx1, float dy1, float dx2, float dy2, float dx3, float dy3);
-    method public androidx.ui.core.vectorgraphics.PathNode![] getNodes();
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineTo(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder horizontalLineToRelative(float x);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder lineToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveTo(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder moveToRelative(float x, float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder quadToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveTo(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveCurveToRelative(float x1, float y1, float x2, float y2);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadTo(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder reflectiveQuadToRelative(float x1, float y1);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineTo(float y);
-    method public androidx.ui.core.vectorgraphics.PathBuilder verticalLineToRelative(float y);
+  public final class VectorComposeKt {
+    ctor public VectorComposeKt();
+    method public static void DrawVector(float viewportWidth, float viewportHeight, androidx.ui.core.Px defaultWidth = Px(viewportWidth), androidx.ui.core.Px defaultHeight = Px(viewportHeight), String name = "", kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Group(androidx.ui.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, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function1<? super androidx.ui.vector.VectorScope,kotlin.Unit> children);
+    method public static void Path(androidx.ui.vector.VectorScope, Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
   }
 
-  public enum PathCommand {
-    method public final char toKey();
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand Close;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand CurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand HorizontalLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand LineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand MoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand QuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand ReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeArcTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeClose;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeHorizontalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeLineTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeMoveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveCurveTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeReflectiveQuadTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand RelativeVerticalTo;
-    enum_constant public static final androidx.ui.core.vectorgraphics.PathCommand VerticalLineTo;
+  public final class VectorGroup extends androidx.ui.core.vectorgraphics.VectorNode implements java.lang.Iterable<androidx.ui.core.vectorgraphics.VectorNode> kotlin.jvm.internal.markers.KMappedMarker {
+    ctor public VectorGroup(String name, float rotation, float pivotX, float pivotY, float scaleX, float scaleY, float translationX, float translationY, Object? clipPathData);
+    ctor public VectorGroup();
+    method public operator androidx.ui.core.vectorgraphics.VectorNode get(int index);
+    method public Object? getClipPathData();
+    method public String getName();
+    method public float getPivotX();
+    method public float getPivotY();
+    method public float getRotation();
+    method public float getScaleX();
+    method public float getScaleY();
+    method public int getSize();
+    method public float getTranslationX();
+    method public float getTranslationY();
+    method public java.util.Iterator<androidx.ui.core.vectorgraphics.VectorNode> iterator();
+    property public final int size;
   }
 
-  public final class PathCommandKt {
-    ctor public PathCommandKt();
-    method public static androidx.ui.core.vectorgraphics.PathCommand toPathCommand(char) throws java.lang.IllegalArgumentException;
+  public abstract sealed class VectorNode {
   }
 
-  public final class PathDelegate {
-    ctor public PathDelegate(kotlin.jvm.functions.Function1<? super androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> delegate);
-    method public kotlin.jvm.functions.Function1<androidx.ui.core.vectorgraphics.PathBuilder,kotlin.Unit> getDelegate();
-  }
-
-  public final class PathNode {
-    ctor public PathNode(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public androidx.ui.core.vectorgraphics.PathCommand component1();
-    method public float[] component2();
-    method public androidx.ui.core.vectorgraphics.PathNode copy(androidx.ui.core.vectorgraphics.PathCommand command, float[] args);
-    method public float[] getArgs();
-    method public androidx.ui.core.vectorgraphics.PathCommand getCommand();
-  }
-
-  public final class PathNodeKt {
-    ctor public PathNodeKt();
-    method public static operator StringBuilder plus(StringBuilder, androidx.ui.core.vectorgraphics.PathNode node);
-  }
-
-  public final class PathParser {
-    ctor public PathParser();
-    method public androidx.ui.core.vectorgraphics.PathParser addPathNodes(androidx.ui.core.vectorgraphics.PathNode![] nodes);
-    method public void clear();
-    method public androidx.ui.core.vectorgraphics.PathParser parsePathString(String pathData) throws java.lang.IllegalArgumentException, java.lang.NumberFormatException;
-    method public androidx.ui.core.vectorgraphics.PathNode![] toNodes();
-    method public androidx.ui.painting.Path toPath(androidx.ui.painting.Path target = Path());
-  }
-
-  public final class PathParserKt {
-    ctor public PathParserKt();
-  }
-
-  public final class RadialGradient implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public RadialGradient(kotlin.Pair<androidx.ui.graphics.Color,java.lang.Float>![] colorStops, float centerX, float centerY, float radius, androidx.ui.painting.TileMode tileMode);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class SolidColor implements androidx.ui.core.vectorgraphics.Brush {
-    ctor public SolidColor(androidx.ui.graphics.Color value);
-    method public void applyBrush(androidx.ui.painting.Paint p);
-  }
-
-  public final class VectorKt {
-    ctor public VectorKt();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] addPathNodes(String? pathStr);
-    method public static android.view.View? adoptVectorGraphic(Object? parent, Object? child);
-    method public static androidx.ui.painting.StrokeCap getDefaultStrokeLineCap();
-    method public static androidx.ui.painting.StrokeJoin getDefaultStrokeLineJoin();
-    method public static androidx.ui.core.vectorgraphics.PathNode![] getEmptyPath();
-    method public static void group(String name = "", float rotate = 0.0f, float pivotX = 0.0f, float pivotY = 0.0f, float scaleX = 1.0f, float scaleY = 1.0f, float translateX = 0.0f, float translateY = 0.0f, Object? clipPathData = EmptyPath, kotlin.jvm.functions.Function0<kotlin.Unit> childNodes);
-    method public static void path(Object? pathData, String name = "", Object fill = EmptyBrush, float fillAlpha = 1.0f, Object stroke = EmptyBrush, float strokeAlpha = 1.0f, float strokeLineWidth = 0.0f, androidx.ui.painting.StrokeCap strokeLineCap = DefaultStrokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin = DefaultStrokeLineJoin, float strokeLineMiter = 4.0f);
-    method public static void vector(String name = "", float viewportWidth, float viewportHeight, float defaultWidth = viewportWidth, float defaultHeight = viewportHeight, kotlin.jvm.functions.Function0<kotlin.Unit> children);
-    field public static final float DefaultAlpha = 1.0f;
-    field public static final String DefaultGroupName = "";
-    field public static final String DefaultPathName = "";
-    field public static final float DefaultPivotX = 0.0f;
-    field public static final float DefaultPivotY = 0.0f;
-    field public static final float DefaultRotate = 0.0f;
-    field public static final float DefaultScaleX = 1.0f;
-    field public static final float DefaultScaleY = 1.0f;
-    field public static final float DefaultStrokeLineMiter = 4.0f;
-    field public static final float DefaultStrokeLineWidth = 0.0f;
-    field public static final float DefaultTranslateX = 0.0f;
-    field public static final float DefaultTranslateY = 0.0f;
+  public final class VectorPath extends androidx.ui.core.vectorgraphics.VectorNode {
+    ctor public VectorPath(String name, Object? pathData, Object fill, float fillAlpha, Object stroke, float strokeAlpha, float strokeLineWidth, androidx.ui.painting.StrokeCap strokeLineCap, androidx.ui.painting.StrokeJoin strokeLineJoin, float strokeLineMiter);
+    method public Object getFill();
+    method public float getFillAlpha();
+    method public String getName();
+    method public Object? getPathData();
+    method public Object getStroke();
+    method public float getStrokeAlpha();
+    method public androidx.ui.painting.StrokeCap getStrokeLineCap();
+    method public androidx.ui.painting.StrokeJoin getStrokeLineJoin();
+    method public float getStrokeLineMiter();
+    method public float getStrokeLineWidth();
   }
 
 }
@@ -479,7 +422,12 @@
 
   public final class VectorResourceKt {
     ctor public VectorResourceKt();
-    method public static void vectorResource(android.content.res.Resources res, int resId);
+    method public static void VectorResource(int resId);
+    method public static androidx.ui.core.vectorgraphics.VectorAsset loadVectorResource(android.content.res.Resources.Theme? theme = null, android.content.res.Resources res, int resId) throws org.xmlpull.v1.XmlPullParserException;
+  }
+
+  public final class XmlVectorParserKt {
+    ctor public XmlVectorParserKt();
   }
 
 }
diff --git a/ui/ui-framework/build.gradle b/ui/ui-framework/build.gradle
index 2bf6a35..5d162f6 100644
--- a/ui/ui-framework/build.gradle
+++ b/ui/ui-framework/build.gradle
@@ -40,6 +40,7 @@
     implementation project(":ui:ui-core")
     implementation project(":ui:ui-platform")
     implementation project(":ui:ui-text")
+    implementation project(":ui:ui-vector")
 
     testImplementation(ANDROIDX_TEST_RULES)
     testImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/ui/ui-framework/integration-tests/framework-demos/build.gradle b/ui/ui-framework/integration-tests/framework-demos/build.gradle
index efa06f8..5e42071 100644
--- a/ui/ui-framework/integration-tests/framework-demos/build.gradle
+++ b/ui/ui-framework/integration-tests/framework-demos/build.gradle
@@ -26,6 +26,7 @@
     implementation project(':ui:ui-animation')
     implementation project(':ui:ui-framework')
     implementation project(':ui:ui-material')
+    implementation project(path: ':ui:ui-vector')
 }
 
 android {
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/AndroidManifest.xml b/ui/ui-framework/integration-tests/framework-demos/src/main/AndroidManifest.xml
index 933fee0..77971ae 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/AndroidManifest.xml
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/AndroidManifest.xml
@@ -53,6 +53,14 @@
                 <category android:name="androidx.ui.demos.SAMPLE_CODE" />
             </intent-filter>
         </activity>
+        <activity android:name=".gestures.DoubleTapGestureDetectorDemo"
+                  android:configChanges="orientation|screenSize"
+                  android:label="Gestures/Single GestureDetectors/DoubleTapGestureDetectorDemo">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="androidx.ui.demos.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
         <activity android:name=".gestures.NestedScrollingDemo"
             android:configChanges="orientation|screenSize"
             android:label="Gestures/Complex Demos/Nested Scrolling">
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/MultipleCollect.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/MultipleCollect.kt
index 443fcd6..2d01e25 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/MultipleCollect.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/MultipleCollect.kt
@@ -25,13 +25,13 @@
 import androidx.ui.core.coerceIn
 import androidx.ui.core.ipx
 import androidx.ui.core.toRect
-import androidx.ui.core.vectorgraphics.Brush
-import androidx.ui.core.vectorgraphics.SolidColor
 import androidx.ui.graphics.Color
 import androidx.ui.painting.Paint
 import androidx.compose.Children
 import androidx.compose.Composable
 import androidx.compose.composer
+import androidx.ui.graphics.vectorgraphics.Brush
+import androidx.ui.graphics.vectorgraphics.SolidColor
 
 @Composable
 fun ColoredRect(brush: Brush, width: Dp? = null, height: Dp? = null) {
@@ -63,7 +63,7 @@
 fun HeaderFooterLayout(
     header: @Composable() () -> Unit,
     footer: @Composable() () -> Unit,
-    @Children content: @Composable() () -> Unit
+    content: @Composable() () -> Unit
 ) {
     @Suppress("USELESS_CAST")
     Layout(
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 74904e6..a24fa7b 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
@@ -144,7 +144,7 @@
     onPress: SemanticAction<PxPosition> = SemanticAction(defaultParam = PxPosition.Origin) { },
     onRelease: SemanticAction<Unit> = SemanticAction(defaultParam = Unit) { },
     onCancel: SemanticAction<Unit> = SemanticAction(defaultParam = Unit) { },
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     PressGestureDetector(
         onPress = { onPress.action(ActionParam(ActionCaller.PointerInput, it)) },
@@ -165,7 +165,7 @@
 fun Semantics(
     @Suppress("UNUSED_PARAMETER") properties: Set<SemanticProperty<out Any>> = setOf(),
     actions: Set<SemanticAction<out Any?>> = setOf(),
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Column {
         MaterialTheme {
@@ -275,7 +275,7 @@
  * children or make them visible.
  */
 @Composable
-private fun Collapsable(@Children children: @Composable() () -> Unit) {
+private fun Collapsable(children: @Composable() () -> Unit) {
 
     val collapsedState = +state { CollapseMode.Collapsed }
 
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL2.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL2.kt
index a1aa21f..031632f 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL2.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL2.kt
@@ -28,7 +28,7 @@
     label: String = "",
     visibility: Visibility = Visibility.Undefined,
     actions: Set<SemanticAction<out Any?>> = setOf(),
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val propertySet = mutableSetOf<SemanticProperty<out Any>>()
 
@@ -62,7 +62,7 @@
     defaultParam: T,
     types: Set<ActionType> = setOf(),
     action: (ActionParam<T>) -> Unit,
-    @Children block: @Composable() (SemanticAction<T>) -> Unit
+    block: @Composable() (SemanticAction<T>) -> Unit
 ) {
     val semanticAction = SemanticAction<T>(phrase, defaultParam, types, action)
     block.invoke(semanticAction)
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL3.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL3.kt
index 9b5eed4..565ab99 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL3.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/SemanticsL3.kt
@@ -29,7 +29,7 @@
 @Composable
 fun ClickInteraction(
     click: SemanticActionBuilder<Unit>.() -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val clickAction = SemanticActionBuilder(phrase = "Click", defaultParam = Unit)
         .apply(click)
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 e6288ff..37f6735 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
@@ -17,68 +17,90 @@
 package androidx.ui.framework.demos
 
 import android.app.Activity
-import android.graphics.Color
+import android.graphics.Shader
 import android.os.Bundle
-import android.widget.LinearLayout
-import androidx.ui.core.vectorgraphics.adoptVectorGraphic
-import androidx.ui.core.vectorgraphics.compat.vectorResource
-import androidx.ui.core.vectorgraphics.group
-import androidx.ui.core.vectorgraphics.path
-import androidx.ui.core.vectorgraphics.vector
-import androidx.ui.core.vectorgraphics.PathBuilder
-import androidx.ui.core.vectorgraphics.PathDelegate
+import androidx.compose.Children
 import androidx.compose.Composable
 import androidx.compose.composer
-import androidx.compose.registerAdapter
-import androidx.compose.setViewContent
+import androidx.ui.core.IntPx
+import androidx.ui.core.Layout
+import androidx.ui.core.Px
+import androidx.ui.core.dp
+import androidx.ui.core.px
+import androidx.ui.core.round
+import androidx.ui.core.vectorgraphics.DrawVector
+import androidx.ui.core.vectorgraphics.Group
+import androidx.ui.core.vectorgraphics.Path
+import androidx.ui.graphics.Color
+import androidx.ui.graphics.vectorgraphics.HorizontalGradient
+import androidx.ui.graphics.vectorgraphics.PathBuilder
+import androidx.ui.graphics.vectorgraphics.PathDelegate
+import androidx.ui.graphics.vectorgraphics.RadialGradient
+import androidx.ui.graphics.vectorgraphics.VerticalGradient
+import androidx.ui.layout.Center
+import androidx.ui.layout.Column
+import androidx.ui.layout.Container
+import androidx.ui.painting.TileMode
+import androidx.ui.core.setContent
+import androidx.ui.core.vectorgraphics.compat.VectorResource
+import androidx.ui.vector.VectorScope
 
 class VectorGraphicsActivity : Activity() {
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
 
-        val res = getResources()
-        setViewContent {
-            composer.registerAdapter { parent, child ->
-                adoptVectorGraphic(parent, child)
-            }
+        setContent {
+            Column {
+                Container(width = 480.dp, height = 480.dp) {
+                    VectorResource(resId = R.drawable.ic_crane)
+                }
 
-            LinearLayout(orientation = LinearLayout.VERTICAL) {
-                vectorResource(
-                    res = res,
-                    resId = androidx.ui.framework.demos.R.drawable.ic_crane
-                )
-                vectorShape()
+                Center {
+                    val width = 300.px
+                    val height = 300.px
+                    FixedLayout(width.round(), height.round()) {
+                        vectorShape(width, height)
+                    }
+                }
             }
         }
     }
 
     @Composable
-    fun vectorShape() {
-        val viewportWidth = 300.0f
-        val viewportHeight = 300.0f
-        vector(
+    fun FixedLayout(width: IntPx, height: IntPx, @Children child: @Composable() () -> Unit) {
+        Layout(children = { child() },
+            layoutBlock = { _, _ ->
+                layout(width, height) {}
+            })
+    }
+
+    @Composable
+    fun vectorShape(width: Px, height: Px) {
+        val viewportWidth = width.value
+        val viewportHeight = height.value
+        DrawVector(
             name = "vectorShape",
-            defaultWidth = 300.0f,
-            defaultHeight = 300.0f,
+            defaultWidth = width,
+            defaultHeight = height,
             viewportWidth = viewportWidth,
             viewportHeight = viewportHeight
         ) {
-            group(
+            Group(
                 scaleX = 0.75f,
                 scaleY = 0.75f,
-                rotate = 45.0f,
+                rotation = 45.0f,
                 pivotX = (viewportWidth / 2),
                 pivotY = (viewportHeight / 2)
             ) {
                 backgroundPath(vectorWidth = viewportWidth, vectorHeight = viewportHeight)
                 stripePath(vectorWidth = viewportWidth, vectorHeight = viewportHeight)
-                group(
-                    translateX = 50.0f,
-                    translateY = 50.0f,
+                Group(
+                    translationX = 50.0f,
+                    translationY = 50.0f,
                     pivotX = (viewportWidth / 2),
                     pivotY = (viewportHeight / 2),
-                    rotate = 25.0f
+                    rotation = 25.0f
                 ) {
                     val pathData = PathDelegate {
                         moveTo(viewportWidth / 2 - 100, viewportHeight / 2 - 100)
@@ -87,14 +109,24 @@
                         horizontalLineToRelative(-200.0f)
                         close()
                     }
-                    path(fill = Color.MAGENTA, pathData = pathData)
+                    Path(
+                        fill = HorizontalGradient(
+                            Color.Red,
+                            Color.Blue,
+                            startX = Px.Zero,
+                            endX = Px(viewportWidth / 2 + 100)
+                        ),
+                        pathData = pathData
+                    )
                 }
+                triangle()
+                triangleWithOffsets()
             }
         }
     }
 
     @Composable
-    fun backgroundPath(vectorWidth: Float, vectorHeight: Float) {
+    fun VectorScope.backgroundPath(vectorWidth: Float, vectorHeight: Float) {
         val background = PathDelegate {
             horizontalLineTo(vectorWidth)
             verticalLineTo(vectorHeight)
@@ -102,16 +134,68 @@
             close()
         }
 
-        path(fill = Color.CYAN, pathData = background)
+        Path(
+            fill = VerticalGradient(
+                0.0f to Color.Aqua,
+                0.3f to Color.Lime,
+                1.0f to Color.Fuchsia,
+                startY = Px.Zero,
+                endY = Px(vectorHeight)
+            ),
+            pathData = background
+        )
     }
 
     @Composable
-    fun stripePath(vectorWidth: Float, vectorHeight: Float) {
+    fun VectorScope.triangle() {
+        val length = 150.0f
+        Path(
+            fill = RadialGradient(
+                Color.Navy,
+                Color.Olive,
+                Color.Teal,
+                centerX = length / 2.0f,
+                centerY = length / 2.0f,
+                radius = length / 2.0f,
+                tileMode = TileMode.repeated
+            ),
+            pathData = PathDelegate {
+                verticalLineTo(length)
+                horizontalLineTo(length)
+                close()
+            }
+        )
+    }
+
+    @Composable
+    fun VectorScope.triangleWithOffsets() {
+
+        val side1 = 150.0f
+        val side2 = 150.0f
+        Path(
+            fill = RadialGradient(
+                0.0f to Color.Maroon,
+                0.3f to Color.Cyan,
+                0.8f to Color.Yellow,
+                centerX = side1 / 2.0f,
+                centerY = side2 / 2.0f,
+                radius = side1 / 2.0f
+            ),
+            pathData = PathDelegate {
+                horizontalLineToRelative(side1)
+                verticalLineToRelative(side2)
+                close()
+            }
+        )
+    }
+
+    @Composable
+    fun VectorScope.stripePath(vectorWidth: Float, vectorHeight: Float) {
         val stripeDelegate = PathDelegate {
             stripe(vectorWidth, vectorHeight, 10)
         }
 
-        path(stroke = Color.BLUE, pathData = stripeDelegate)
+        Path(stroke = Color.Blue, pathData = stripeDelegate)
     }
 
     private fun PathBuilder.stripe(vectorWidth: Float, vectorHeight: Float, numLines: Int) {
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/DoubleTapGestureDetectorDemo.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/DoubleTapGestureDetectorDemo.kt
new file mode 100644
index 0000000..7a972c5
--- /dev/null
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/DoubleTapGestureDetectorDemo.kt
@@ -0,0 +1,56 @@
+/*
+ * 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.framework.demos.gestures
+
+import android.app.Activity
+import android.os.Bundle
+import androidx.compose.state
+import androidx.compose.unaryPlus
+import androidx.ui.core.px
+import androidx.ui.core.setContent
+import androidx.compose.composer
+import androidx.ui.core.PxPosition
+import androidx.ui.core.dp
+import androidx.ui.core.gesture.DoubleTapGestureDetector
+
+/**
+ * Simple demo that shows off DragGestureDetector.
+ */
+class DoubleTapGestureDetectorDemo : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        super.onCreate(savedInstanceState)
+        setContent {
+            val color = +state { Colors.random() }
+
+            val onDoubleTap: (PxPosition) -> Unit = {
+                color.value = color.value.anotherRandomColor()
+            }
+
+            DoubleTapGestureDetector(onDoubleTap = onDoubleTap) {
+                MatchParent {
+                    DrawBox(
+                        0.px,
+                        0.px,
+                        96.dp,
+                        96.dp,
+                        color.value
+                    )
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/NestedScrollingDemo.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/NestedScrollingDemo.kt
index dc3feee..ffadb06 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/NestedScrollingDemo.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/NestedScrollingDemo.kt
@@ -41,6 +41,7 @@
 import androidx.compose.composer
 import androidx.ui.core.Draw
 import androidx.ui.core.dp
+import androidx.ui.core.gesture.DoubleTapGestureDetector
 import androidx.ui.core.gesture.PressReleasedGestureDetector
 import androidx.ui.core.round
 import androidx.ui.core.toRect
@@ -80,7 +81,7 @@
  * A very simple ScrollView like implementation that allows for vertical scrolling.
  */
 @Composable
-private fun Draggable(@Children children: @Composable() () -> Unit) {
+private fun Draggable(children: @Composable() () -> Unit) {
     val offset = +state { 0.px }
     val maxOffset = +state { 0.px }
 
@@ -141,27 +142,30 @@
 ) {
 
     val pressedColor = Color(0x1f000000)
-    val itemColor = Color(0xFFFFFFFF.toInt())
+    val defaultColor = Color(0xFFFFFFFF.toInt())
 
-    val color = +state { itemColor }
-    val pressed = +state { false }
+    val color = +state { defaultColor }
+    val showPressed = +state { false }
 
-    val onStart: (PxPosition) -> Unit = {
-        pressed.value = true
-    }
-
-    val onStop = {
-        pressed.value = false
+    val onPress: (PxPosition) -> Unit = {
+        showPressed.value = true
     }
 
     val onRelease = {
+        showPressed.value = false
+    }
+
+    val onTap = {
         color.value = color.value.next()
-        pressed.value = false
+    }
+
+    val onDoubleTap: (PxPosition) -> Unit = {
+        color.value = color.value.prev().prev()
     }
 
     val onLongPress = { _: PxPosition ->
-        color.value = color.value.prev()
-        pressed.value = false
+        color.value = defaultColor
+        showPressed.value = false
     }
 
     val children = @Composable {
@@ -171,7 +175,7 @@
                 Rect(0f, 0f, parentSize.width.value, parentSize.height.value),
                 backgroundPaint
             )
-            if (pressed.value) {
+            if (showPressed.value) {
                 backgroundPaint.color = pressedColor
                 canvas.drawRect(
                     Rect(0f, 0f, parentSize.width.value, parentSize.height.value),
@@ -181,14 +185,16 @@
         }
     }
 
-    PressIndicatorGestureDetector(onStart, onStop, onStop) {
-        PressReleasedGestureDetector(onRelease, false) {
-            LongPressGestureDetector(onLongPress) {
-                Layout(children) { _, constraints ->
-                    layout(
-                        constraints.maxWidth,
-                        height.toIntPx().coerceIn(constraints.minHeight, constraints.maxHeight)
-                    ) {}
+    PressIndicatorGestureDetector(onPress, onRelease, onRelease) {
+        PressReleasedGestureDetector(onTap, false) {
+            DoubleTapGestureDetector(onDoubleTap) {
+                LongPressGestureDetector(onLongPress) {
+                    Layout(children) { _, constraints ->
+                        layout(
+                            constraints.maxWidth,
+                            height.toIntPx().coerceIn(constraints.minHeight, constraints.maxHeight)
+                        ) {}
+                    }
                 }
             }
         }
@@ -215,7 +221,7 @@
  * A simple composable that arranges it's children as vertical list of items.
  */
 @Composable
-private fun Column(@Children children: @Composable() () -> Unit) {
+private fun Column(children: @Composable() () -> Unit) {
     Layout(children) { measurables, constraints ->
         var height = 0.ipx
         val placeables = measurables.map {
diff --git a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/SimpleComposables.kt b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/SimpleComposables.kt
index e49a48e..dc07bc9 100644
--- a/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/SimpleComposables.kt
+++ b/ui/ui-framework/integration-tests/framework-demos/src/main/java/androidx/ui/framework/demos/gestures/SimpleComposables.kt
@@ -35,7 +35,7 @@
  * A simple layout composable that matches the size of it's parent layout.
  */
 @Composable
-internal fun MatchParent(@Children children: @Composable() () -> Unit) {
+internal fun MatchParent(children: @Composable() () -> Unit) {
     Layout({
         children()
     }, { _, constraints ->
@@ -44,7 +44,7 @@
 }
 
 @Composable
-internal fun Center(@Children children: @Composable() () -> Unit) {
+internal fun Center(children: @Composable() () -> Unit) {
     Layout(children) { measurables, constraints ->
         val placeable = measurables.first().measure(constraints)
         layout(constraints.maxWidth, constraints.maxHeight) {
@@ -59,7 +59,7 @@
  * A simple composable that pads items by [padding].
  */
 @Composable
-private fun Padding(padding: Dp?, @Children children: @Composable() () -> Unit) {
+private fun Padding(padding: Dp?, children: @Composable() () -> Unit) {
     Layout(children) { measurables, constraints ->
         val paddingPx = padding?.toIntPx() ?: 0.ipx
         val doublePadding = paddingPx * 2
@@ -90,7 +90,7 @@
  * A simple composable that draws a border around it's children.
  */
 @Composable
-private fun Border(color: Color, width: Dp, @Children children: @Composable() () -> Unit) {
+private fun Border(color: Color, width: Dp, children: @Composable() () -> Unit) {
     Layout(
         children = {
             children()
@@ -140,7 +140,7 @@
     width: Dp,
     height: Dp,
     padding: Dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
 
     val borderWidth: Dp = 2.dp
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
index 2318041..c8866dc 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/AndroidLayoutDrawTest.kt
@@ -426,14 +426,17 @@
                 val header = @Composable {
                     Layout(layoutBlock = { _, constraints ->
                         assertEquals(childConstraints[0], constraints)
+                        layout(0.ipx, 0.ipx) {}
                     }, children = {})
                 }
                 val footer = @Composable {
                     Layout(layoutBlock = { _, constraints ->
                         assertEquals(childConstraints[1], constraints)
+                        layout(0.ipx, 0.ipx) {}
                     }, children = {})
                     Layout(layoutBlock = { _, constraints ->
                         assertEquals(childConstraints[2], constraints)
+                        layout(0.ipx, 0.ipx) {}
                     }, children = {})
                 }
                 @Suppress("USELESS_CAST")
@@ -447,6 +450,7 @@
                     assertEquals(footerChildrenCount, measurables[footer].size)
                     assertSame(measurables[1], measurables[footer][0])
                     assertSame(measurables[2], measurables[footer][1])
+                    layout(0.ipx, 0.ipx) {}
                 }
             }
         }
@@ -458,18 +462,19 @@
             activity.setContent {
                 val header = @Composable {
                     ParentData(data = 0) {
-                        Layout(layoutBlock = { _, _ -> }, children = {})
+                        Layout(layoutBlock = { _, _ -> layout(0.ipx, 0.ipx, {}) }, children = {})
                     }
                 }
                 val footer = @Composable {
                     ParentData(data = 1) {
-                        Layout(layoutBlock = { _, _ -> }, children = {})
+                        Layout(layoutBlock = { _, _ -> layout(0.ipx, 0.ipx, {}) }, children = {})
                     }
                 }
 
                 Layout(childrenArray = arrayOf(header, footer)) { measurables, _ ->
                     assertEquals(0, measurables[0].parentData)
                     assertEquals(1, measurables[1].parentData)
+                    layout(0.ipx, 0.ipx, {})
                 }
             }
         }
@@ -553,7 +558,7 @@
         fun FixedSizeRow(
             width: IntPx,
             height: IntPx,
-            @Children children: @Composable() () -> Unit
+            children: @Composable() () -> Unit
         ) {
             Layout(children = children, layoutBlock = { measurables, constraints ->
                 val resolvedWidth = width.coerceIn(constraints.minWidth, constraints.maxWidth)
@@ -936,7 +941,7 @@
 }
 
 @Composable
-fun AtLeastSize(size: IntPx, @Children children: @Composable() () -> Unit) {
+fun AtLeastSize(size: IntPx, children: @Composable() () -> Unit) {
     Layout(
         layoutBlock = { measurables, constraints ->
             val newConstraints = Constraints(
@@ -964,7 +969,7 @@
 }
 
 @Composable
-fun Align(@Children children: @Composable() () -> Unit) {
+fun Align(children: @Composable() () -> Unit) {
     Layout(
         layoutBlock = { measurables, constraints ->
             val newConstraints = Constraints(
@@ -992,7 +997,7 @@
 }
 
 @Composable
-fun Padding(size: IntPx, @Children children: @Composable() () -> Unit) {
+fun Padding(size: IntPx, children: @Composable() () -> Unit) {
     Layout(
         layoutBlock = { measurables, constraints ->
             val totalDiff = size * 2
@@ -1024,7 +1029,7 @@
 fun TwoMeasureLayout(
     size: IntPx,
     latch: CountDownLatch,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Layout(children = children) { measurables, _ ->
         val testConstraints = Constraints()
@@ -1042,11 +1047,12 @@
             // expected
             latch.countDown()
         }
+        layout(0.ipx, 0.ipx, {})
     }
 }
 
 @Composable
-fun Position(size: IntPx, offset: OffsetModel, @Children children: @Composable() () -> Unit) {
+fun Position(size: IntPx, offset: OffsetModel, children: @Composable() () -> Unit) {
     Layout(children) { measurables, constraints ->
         val placeables = measurables.map { m ->
             m.measure(constraints)
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/TextLayoutTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/TextLayoutTest.kt
index e31200b..ccfa929 100644
--- a/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/TextLayoutTest.kt
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/test/TextLayoutTest.kt
@@ -137,7 +137,7 @@
                     var threw = false
                     try {
                         textMeasurable.minIntrinsicWidth(0.ipx)
-                    } catch(e: UnsupportedOperationException) {
+                    } catch (e: UnsupportedOperationException) {
                         threw = true
                     }
                     assertTrue(threw)
@@ -153,6 +153,8 @@
                     assertEquals(textHeight, textMeasurable.maxIntrinsicHeight(IntPx.Infinity))
 
                     intrinsicsLatch.countDown()
+
+                    layoutResult(0.ipx, 0.ipx) {}
                 }
                 minIntrinsicWidth { _, _ -> 0.ipx }
                 minIntrinsicHeight { _, _ -> 0.ipx }
@@ -163,7 +165,7 @@
         assertTrue(intrinsicsLatch.await(1, TimeUnit.SECONDS))
     }
 
-    private fun show(@Children composable: @Composable() () -> Unit) {
+    private fun show(composable: @Composable() () -> Unit) {
         val runnable: Runnable = object : Runnable {
             override fun run() {
                 activity.setContent {
diff --git a/ui/ui-framework/src/androidTest/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParserTest.kt b/ui/ui-framework/src/androidTest/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParserTest.kt
new file mode 100644
index 0000000..2fcd9a2
--- /dev/null
+++ b/ui/ui-framework/src/androidTest/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParserTest.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.core.vectorgraphics.compat
+
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.ui.core.Px
+
+import androidx.ui.core.vectorgraphics.VectorPath
+import androidx.ui.framework.test.R
+import androidx.ui.graphics.vectorgraphics.PathCommand
+import androidx.ui.graphics.vectorgraphics.PathNode
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class XmlVectorParserTest {
+
+    @Test
+    fun testParseXml() {
+        val res = InstrumentationRegistry.getInstrumentation().targetContext.resources
+        val asset = loadVectorResource(null, res, R.drawable.test_compose_vector)
+        val density = res.displayMetrics.density
+        val expectedSize = Px(density*24)
+        assertEquals(expectedSize, asset.defaultWidth)
+        assertEquals(expectedSize, asset.defaultHeight)
+        assertEquals(24.0f, asset.viewportWidth)
+        assertEquals(24.0f, asset.viewportHeight)
+        assertEquals(1, asset.root.size)
+
+        val node = asset.root.iterator().next() as VectorPath
+        assertEquals(0xFFFF0000.toInt(), node.fill as Int)
+
+        @Suppress("UNCHECKED_CAST")
+        val path = node.pathData as Array<PathNode>
+        assertEquals(3, path.size)
+        assertEquals(PathCommand.MoveTo, path.get(0).command)
+        assertEquals(20.0f, path.get(0).args[0])
+        assertEquals(10.0f, path.get(0).args[1])
+
+        assertEquals(PathCommand.RelativeLineTo, path.get(1).command)
+        assertEquals(6, path.get(1).args.size)
+        assertEquals(10.0f, path.get(1).args[0])
+        assertEquals(0.0f, path.get(1).args[1])
+        assertEquals(0.0f, path.get(1).args[2])
+        assertEquals(10.0f, path.get(1).args[3])
+        assertEquals(-10.0f, path.get(1).args[4])
+        assertEquals(0.0f, path.get(1).args[5])
+
+        assertEquals(PathCommand.RelativeClose, path.get(2).command)
+        assertEquals(0, path.get(2).args.size)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/androidTest/res/drawable/test_compose_vector.xml b/ui/ui-framework/src/androidTest/res/drawable/test_compose_vector.xml
new file mode 100644
index 0000000..05beeb3
--- /dev/null
+++ b/ui/ui-framework/src/androidTest/res/drawable/test_compose_vector.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFF0000"
+        android:pathData="M20,10, l10,0 0,10 -10, 0z"/>
+</vector>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Clip.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Clip.kt
index be6e0ff..294325e 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Clip.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Clip.kt
@@ -27,7 +27,7 @@
  * @param shape the [Shape] used for clipping.
  */
 @Composable
-fun Clip(shape: Shape, @Children children: @Composable() () -> Unit) {
+fun Clip(shape: Shape, children: @Composable() () -> Unit) {
     <RepaintBoundaryNode name=null shape=shape clipToShape=true>
         children()
     </RepaintBoundaryNode>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
index 4686cc3..1295a2c 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Layout.kt
@@ -27,12 +27,22 @@
 import androidx.compose.trace
 import androidx.compose.unaryPlus
 
-internal typealias LayoutBlock = LayoutBlockReceiver.(List<Measurable>, Constraints) -> Unit
+internal typealias LayoutBlock = LayoutBlockReceiver.(List<Measurable>, Constraints) -> LayoutResult
 internal typealias IntrinsicMeasurementBlock = IntrinsicMeasurementsReceiver
     .(List<Measurable>, IntPx) -> IntPx
-internal val LayoutBlockStub: LayoutBlock = { _, _ -> }
+internal val LayoutBlockStub: LayoutBlock = { _, _ -> LayoutResult.instance }
 internal val IntrinsicMeasurementBlockStub: IntrinsicMeasurementBlock = { _, _ -> 0.ipx }
 
+/**
+ * Object returned from [LayoutReceiver.layout] and [LayoutBlockReceiver.layoutResult] to deliver
+ * proof the method was called in the respective layout lambdas.
+ */
+class LayoutResult private constructor() {
+    companion object {
+        internal val instance = LayoutResult()
+    }
+}
+
 internal class ComplexLayoutState(
     internal var layoutBlock: LayoutBlock = LayoutBlockStub,
     internal var minIntrinsicWidthBlock: IntrinsicMeasurementBlock = IntrinsicMeasurementBlockStub,
@@ -315,9 +325,10 @@
         width: IntPx,
         height: IntPx,
         block: PositioningBlockReceiver.() -> Unit
-    ) {
+    ): LayoutResult {
         layoutState.resize(width, height)
         layoutState.positioningBlock = block
+        return LayoutResult.instance
     }
     fun Measurable.minIntrinsicWidth(h: IntPx) =
         (this as ComplexLayoutState).minIntrinsicWidth(h)
@@ -345,7 +356,7 @@
 fun Layout(
     children: @Composable() () -> Unit,
     @Children(composable = false) layoutBlock: LayoutReceiver
-        .(measurables: List<Measurable>, constraints: Constraints) -> Unit
+        .(measurables: List<Measurable>, constraints: Constraints) -> LayoutResult
 ) {
     trace("UI:Layout") {
         ComplexLayout(children = children, block = {
@@ -356,7 +367,7 @@
             )
             layout { measurables, constraints ->
                 layoutReceiver.complexMeasure = LayoutMeasure
-                layoutReceiver.complexLayoutResult = this::layoutResult
+                layoutReceiver.complexLayoutResult = { w, h, block -> layoutResult(w, h, block) }
                 layoutReceiver.layoutBlock(measurables, constraints)
             }
 
@@ -438,7 +449,7 @@
 fun Layout(
     childrenArray: Array<@Composable() () -> Unit>,
     @Children(composable = false) layoutBlock: LayoutReceiver
-        .(measurables: List<Measurable>, constraints: Constraints) -> Unit
+        .(measurables: List<Measurable>, constraints: Constraints) -> LayoutResult
 ) {
     val ChildrenEndMarker = @Composable { children: @Composable() () -> Unit ->
         ParentData(data = ChildrenEndParentData(children)) {
@@ -487,8 +498,13 @@
      * calls to [Placeable.place], defining the positions of the children relative to the current
      * layout.
      */
-    fun layout(width: IntPx, height: IntPx, block: PositioningBlockReceiver.() -> Unit) {
+    fun layout(
+        width: IntPx,
+        height: IntPx,
+        block: PositioningBlockReceiver.() -> Unit
+    ): LayoutResult {
         complexLayoutResult(width, height, block)
+        return LayoutResult.instance
     }
 }
 
@@ -516,7 +532,7 @@
  * Please note that using this widget might be a performance hit, so please use with care.
  */
 @Composable
-fun WithConstraints(@Children children: @Composable() (Constraints) -> Unit) {
+fun WithConstraints(children: @Composable() (Constraints) -> Unit) {
     val ref = +compositionReference()
     val context = +ambient(ContextAmbient)
 
@@ -592,7 +608,7 @@
 @Composable
 fun OnChildPositioned(
     onPositioned: (coordinates: LayoutCoordinates) -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     <DataNode key=OnChildPositionedKey value=onPositioned>
         <children/>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Opacity.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Opacity.kt
index 7399e1a..bc1881a 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Opacity.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Opacity.kt
@@ -33,7 +33,7 @@
 @Composable
 fun Opacity(
     @FloatRange(from = 0.0, to = 1.0) opacity: Float,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     <RepaintBoundaryNode name=null opacity=opacity>
         children()
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/ParentData.kt b/ui/ui-framework/src/main/java/androidx/ui/core/ParentData.kt
index 8ae7c49..081b3daf 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/ParentData.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/ParentData.kt
@@ -53,7 +53,7 @@
  * expanded, which are inflexible and which are flexible.
  */
 @Composable
-fun ParentData(data: Any, @Children children: @Composable() () -> Unit) {
+fun ParentData(data: Any, children: @Composable() () -> Unit) {
     <DataNode key=ParentDataKey value=data>
         <children/>
     </DataNode>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/PointerInputWrapper.kt b/ui/ui-framework/src/main/java/androidx/ui/core/PointerInputWrapper.kt
index ec66af4..d6e0e77 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/PointerInputWrapper.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/PointerInputWrapper.kt
@@ -24,7 +24,7 @@
 @Composable
 fun PointerInputWrapper(
     pointerInputHandler: PointerInputHandler = { event, _ -> event },
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     // Hide the internals of PointerInputNode
     <PointerInputNode pointerInputHandler>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/RepaintBoundary.kt b/ui/ui-framework/src/main/java/androidx/ui/core/RepaintBoundary.kt
index 757e740..cbf1760 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/RepaintBoundary.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/RepaintBoundary.kt
@@ -31,7 +31,7 @@
  * @param children The contained children.
  */
 @Composable
-fun RepaintBoundary(name: String? = null, @Children children: @Composable() () -> Unit) {
+fun RepaintBoundary(name: String? = null, children: @Composable() () -> Unit) {
     <RepaintBoundaryNode name=name>
         <children/>
     </RepaintBoundaryNode>
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Semantics.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Semantics.kt
index baa4ff3..dad6816 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Semantics.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Semantics.kt
@@ -124,7 +124,7 @@
     textDirection: TextDirection? = null,
     testTag: String? = null,
     actions: List<SemanticsAction<*>> = emptyList(),
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val providedTestTag = +ambient(TestTagAmbient)
     <SemanticsComponentNode
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/TestTagProvider.kt b/ui/ui-framework/src/main/java/androidx/ui/core/TestTagProvider.kt
index e69bf03..a75a022 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/TestTagProvider.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/TestTagProvider.kt
@@ -27,6 +27,6 @@
 // Implementation with ambients now for only one semantics inside.
 // replace with mergeable semantics later
 @Composable
-fun TestTag(tag: String, @Children children: @Composable() () -> Unit) {
+fun TestTag(tag: String, children: @Composable() () -> Unit) {
     TestTagAmbient.Provider(value = tag, children = children)
 }
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt b/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
index 7e1680cb..4d0fd2a 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/Text.kt
@@ -97,7 +97,7 @@
     /**
      * Composable TextSpan attached after [text].
      */
-    @Children child: @Composable TextSpanScope.() -> Unit
+    child: @Composable TextSpanScope.() -> Unit
 ) {
     val rootTextSpan = +memo(text) { TextSpan(text = text) }
     val ref = +compositionReference()
@@ -321,7 +321,7 @@
  * styled explicitly.
  */
 @Composable
-fun CurrentTextStyleProvider(value: TextStyle, @Children children: @Composable() () -> Unit) {
+fun CurrentTextStyleProvider(value: TextStyle, children: @Composable() () -> Unit) {
     val style = +ambient(CurrentTextStyleAmbient)
     val mergedStyle = style.merge(value)
     CurrentTextStyleAmbient.Provider(value = mergedStyle) {
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/TextField.kt b/ui/ui-framework/src/main/java/androidx/ui/core/TextField.kt
index 6964f89..656a8a4 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/TextField.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/TextField.kt
@@ -98,6 +98,12 @@
     /** Called when the InputMethodService update the editor state */
     onValueChange: (EditorModel) -> Unit = {},
 
+    /** Called when the input field gains focus. */
+    onFocus: () -> Unit = {},
+
+    /** Called when the input field loses focus. */
+    onBlur: () -> Unit = {},
+
     /** Called when the InputMethod requested an IME action */
     onImeActionPerformed: (ImeAction) -> Unit = {},
 
@@ -157,6 +163,7 @@
                     )
                 }
             }
+            onFocus()
         },
         onBlur = {
             hasFocus.value = false
@@ -164,6 +171,7 @@
                 textInputService,
                 processor,
                 onValueChange)
+            onBlur()
         },
         onDragAt = { TextFieldDelegate.onDragAt(it) },
         onRelease = {
@@ -221,7 +229,7 @@
     onRelease: (PxPosition) -> Unit,
     onFocus: () -> Unit,
     onBlur: () -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val focused = +state { false }
     val focusManager = +ambient(FocusManagerAmbient)
@@ -294,7 +302,7 @@
     onPress: (PxPosition) -> Unit,
     onDragAt: (PxPosition) -> Unit,
     onRelease: (PxPosition) -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val tracker = +state { DragEventTracker() }
     PressGestureDetector(
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/TextSpanCompose.kt b/ui/ui-framework/src/main/java/androidx/ui/core/TextSpanCompose.kt
index 1af1687..8d8a56f 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/TextSpanCompose.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/TextSpanCompose.kt
@@ -256,7 +256,7 @@
 fun TextSpanScope.Span(
     text: String? = null,
     style: TextStyle? = null,
-    @Children child: @Composable TextSpanScope.() -> Unit
+    child: @Composable TextSpanScope.() -> Unit
 ) {
     TextSpan(text = text, style = style) {
         child()
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 45f178a..ed51529 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
@@ -47,7 +47,7 @@
  * [Activity.setContent] or [ViewGroup.setContent] extensions.
  */
 @Composable
-fun ComposeView(@Children children: @Composable() () -> Unit) {
+fun ComposeView(children: @Composable() () -> Unit) {
     val rootRef = +memo { Ref<AndroidCraneView>() }
 
     <AndroidCraneView ref=rootRef>
@@ -100,7 +100,7 @@
  * @param content Composable that will be the content of the activity.
  */
 fun Activity.setContent(
-    @Children content: @Composable() () -> Unit
+    content: @Composable() () -> Unit
 ): CompositionContext? {
     val craneView = window.decorView
         .findViewById<ViewGroup>(android.R.id.content)
@@ -123,7 +123,7 @@
  * @param content Composable that will be the content of the view.
  */
 fun ViewGroup.setContent(
-    @Children content: @Composable() () -> Unit
+    content: @Composable() () -> Unit
 ): CompositionContext? {
     val craneView =
         if (childCount > 0) { getChildAt(0) as? AndroidCraneView } else { removeAllViews(); null }
@@ -144,7 +144,7 @@
     craneView: AndroidCraneView,
     context: Context,
     coroutineContext: CoroutineContext,
-    @Children content: @Composable() () -> Unit
+    content: @Composable() () -> Unit
 ) {
     // TODO(nona): Tie the focus manger lifecycle to Window, otherwise FocusManager won't work
     //             with nested AndroidCraneView case
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DoubleTapGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DoubleTapGestureDetector.kt
new file mode 100644
index 0000000..c887644
--- /dev/null
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DoubleTapGestureDetector.kt
@@ -0,0 +1,112 @@
+/*
+ * 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.core.gesture
+
+import androidx.ui.core.PointerEventPass
+import androidx.ui.core.PointerInputChange
+import androidx.ui.core.changedToDown
+import androidx.compose.Children
+import androidx.compose.Composable
+import androidx.compose.ambient
+import androidx.compose.memo
+import androidx.compose.unaryPlus
+import androidx.ui.core.changedToUp
+import androidx.compose.composer
+import androidx.ui.core.CoroutineContextAmbient
+import androidx.ui.core.PointerInputWrapper
+import androidx.ui.core.PxPosition
+import androidx.ui.core.anyPositionChangeConsumed
+import androidx.ui.core.changedToUpIgnoreConsumed
+import androidx.ui.core.consumeDownChange
+import androidx.ui.temputils.delay
+import kotlinx.coroutines.Job
+import kotlin.coroutines.CoroutineContext
+
+// TODO(b/138605697): This bug tracks the note below: DoubleTapGestureDetector should use the
+//  eventual api that will allow it to temporary block tap.
+// TODO(b/138754591): The behavior of this gesture detector needs to be finalized.
+/**
+ * Responds to pointers going up, down within a small duration, and then up again.
+ *
+ * Note: This is a temporary implementation to unblock dependents.  Once the underlying API that
+ * allows double tap to temporarily block tap from firing is complete, this gesture detector will
+ * not block tap when the first "up" occurs. It will however block the 2nd up from causing tap to
+ * fire.
+ *
+ * Also, given that this gesture detector is so temporary, opting to not write substantial tests.
+ */
+@Composable
+fun DoubleTapGestureDetector(
+    onDoubleTap: (PxPosition) -> Unit,
+    children: @Composable() () -> Unit
+) {
+    val recognizer =
+        +memo { DoubleTapGestureRecognizer(onDoubleTap, +ambient(CoroutineContextAmbient)) }
+    PointerInputWrapper(pointerInputHandler = recognizer.pointerInputHandler) {
+        children()
+    }
+}
+
+internal class DoubleTapGestureRecognizer(
+    val onDoubleTap: (PxPosition) -> Unit,
+    coroutineContext: CoroutineContext
+) {
+
+    private enum class State {
+        Idle, Down, Up, SecondDown, Cancelled
+    }
+
+    var doubleTapTimeout = DoubleTapTimeout
+    private var state = State.Idle
+    private var job: Job? = null
+
+    val pointerInputHandler =
+        { changes: List<PointerInputChange>, pass: PointerEventPass ->
+
+            var changesToReturn = changes
+
+            if (pass == PointerEventPass.PostUp) {
+                if (state == State.Idle && changesToReturn.all { it.changedToDown() }) {
+                    state = State.Down
+                } else if (state == State.Down && changesToReturn.all { it.changedToUp() }) {
+                    state = State.Up
+                    job = delay(doubleTapTimeout, coroutineContext) {
+                        state = State.Idle
+                    }
+                } else if (state == State.Up && changesToReturn.all { it.changedToDown() }) {
+                    job?.cancel()
+                    state = State.SecondDown
+                } else if (state == State.SecondDown && changesToReturn.all { it.changedToUp() }) {
+                    changesToReturn = changesToReturn.map { it.consumeDownChange() }
+                    state = State.Idle
+                    onDoubleTap.invoke(changes[0].previous.position!!)
+                } else if (state == State.Cancelled &&
+                    changesToReturn.all { it.changedToUpIgnoreConsumed() }
+                ) {
+                    state = State.Idle
+                }
+            }
+
+            if (pass == PointerEventPass.PostDown &&
+                changesToReturn.any { it.anyPositionChangeConsumed() }
+            ) {
+                state = State.Cancelled
+            }
+
+            changesToReturn
+        }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DragGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DragGestureDetector.kt
index 95cc8eb..0692d57 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DragGestureDetector.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/DragGestureDetector.kt
@@ -100,7 +100,7 @@
 fun DragGestureDetector(
     canDrag: ((Direction) -> Boolean)? = null,
     dragObserver: DragObserver? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val recognizer = +memo { DragGestureRecognizer() }
     recognizer.canDrag = canDrag
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/LongPressGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/LongPressGestureDetector.kt
index a3f894c..d269572 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/LongPressGestureDetector.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/LongPressGestureDetector.kt
@@ -46,7 +46,7 @@
 @Composable
 fun LongPressGestureDetector(
     onLongPress: (PxPosition) -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val recognizer =
         +memo { LongPressGestureRecognizer(onLongPress, +ambient(CoroutineContextAmbient)) }
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressGestureDetector.kt
index 6d8beb2..e91a1e34 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressGestureDetector.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressGestureDetector.kt
@@ -26,7 +26,7 @@
     onPress: ((PxPosition) -> Unit)? = null,
     onRelease: (() -> Unit)? = null,
     onCancel: (() -> Unit)? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     PressIndicatorGestureDetector(onStart = onPress, onCancel = onCancel) {
         PressReleasedGestureDetector(onRelease = onRelease, consumeDownOnStart = false) {
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressIndicatorGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressIndicatorGestureDetector.kt
index 7705035..423b917 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressIndicatorGestureDetector.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressIndicatorGestureDetector.kt
@@ -53,7 +53,7 @@
     onStart: ((PxPosition) -> Unit)? = null,
     onStop: (() -> Unit)? = null,
     onCancel: (() -> Unit)? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val recognizer = +memo { PressIndicatorGestureRecognizer() }
     recognizer.onStart = onStart
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressReleasedGestureDetector.kt b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressReleasedGestureDetector.kt
index a524b3f..99a0daa 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressReleasedGestureDetector.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/gesture/PressReleasedGestureDetector.kt
@@ -52,7 +52,7 @@
 fun PressReleasedGestureDetector(
     onRelease: (() -> Unit)? = null,
     consumeDownOnStart: Boolean = true,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val recognizer = +memo { PressReleaseGestureRecognizer() }
     recognizer.onRelease = onRelease
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
index a3bd5e5..6dfb42c 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/selection/SelectionContainer.kt
@@ -44,7 +44,7 @@
     onSelectionChange: (Selection?) -> Unit,
     /** Selection mode. The default mode is Vertical. */
     mode: SelectionMode = SelectionMode.Vertical,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val manager = +memo { SelectionManager() }
     // TODO (qqd): After selection widget is fully implemented, evaluate if the following 2 items
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Brush.kt b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Brush.kt
deleted file mode 100644
index b8fd184..0000000
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/Brush.kt
+++ /dev/null
@@ -1,105 +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.ui.core.vectorgraphics
-
-import androidx.ui.engine.geometry.Offset
-import androidx.ui.graphics.Color
-import androidx.ui.painting.Gradient
-import androidx.ui.painting.Paint
-import androidx.ui.painting.TileMode
-import androidx.ui.vectormath64.Matrix4
-
-val EmptyBrush = object : Brush {
-    override fun applyBrush(p: Paint) {
-        // NO-OP
-    }
-}
-
-interface Brush {
-    fun applyBrush(p: Paint)
-}
-
-/* inline */ class SolidColor(private val value: Color) : Brush {
-    override fun applyBrush(p: Paint) {
-        p.color = value
-    }
-}
-
-typealias ColorStop = Pair<Color, Float>
-
-fun obtainBrush(brush: Any?): Brush {
-    return when (brush) {
-        is Int -> SolidColor(Color(brush))
-        is Color -> SolidColor(brush)
-        is Brush -> brush
-        null -> EmptyBrush
-        else -> throw IllegalArgumentException(brush.javaClass.simpleName +
-                "Brush must be either a Color long, LinearGradient or RadialGradient")
-    }
-}
-
-// TODO (njawad) replace with inline color class
-class LinearGradient(
-    vararg colorStops: ColorStop,
-    val startX: Float,
-    val startY: Float,
-    val endX: Float,
-    val endY: Float,
-    val tileMode: TileMode = TileMode.clamp
-) : Brush {
-
-    private val colors: List<Color>
-    private val stops: List<Float>
-
-    init {
-        colors = List(colorStops.size) { i -> colorStops[i].first }
-        stops = List(colorStops.size) { i -> colorStops[i].second }
-    }
-
-    override fun applyBrush(p: Paint) {
-        p.shader = Gradient.linear(
-            Offset(startX, startY),
-            Offset(endX, endY),
-            colors,
-            stops,
-            tileMode)
-    }
-}
-
-class RadialGradient(
-    vararg colorStops: ColorStop,
-    private val centerX: Float,
-    private val centerY: Float,
-    private val radius: Float,
-    private val tileMode: TileMode = TileMode.clamp
-) : Brush {
-
-    private val colors: List<Color>
-    private val stops: List<Float>
-
-    init {
-        colors = List(colorStops.size) { it -> colorStops[it].first }
-        stops = List(colorStops.size) { it -> colorStops[it].second }
-    }
-
-    override fun applyBrush(p: Paint) {
-        p.shader = Gradient.radial(
-            Offset(centerX, centerY),
-            radius, colors, stops, tileMode, Matrix4(),
-            null, 0.0f)
-    }
-}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorAsset.kt b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorAsset.kt
new file mode 100644
index 0000000..80071b1
--- /dev/null
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorAsset.kt
@@ -0,0 +1,439 @@
+/*
+ * 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.core.vectorgraphics
+
+import androidx.compose.Composable
+import androidx.compose.composer
+import androidx.ui.core.Px
+import androidx.ui.graphics.vectorgraphics.BrushType
+import androidx.ui.graphics.vectorgraphics.DefaultAlpha
+import androidx.ui.graphics.vectorgraphics.DefaultGroupName
+import androidx.ui.graphics.vectorgraphics.DefaultPathName
+import androidx.ui.graphics.vectorgraphics.DefaultPivotX
+import androidx.ui.graphics.vectorgraphics.DefaultPivotY
+import androidx.ui.graphics.vectorgraphics.DefaultRotation
+import androidx.ui.graphics.vectorgraphics.DefaultScaleX
+import androidx.ui.graphics.vectorgraphics.DefaultScaleY
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineCap
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineJoin
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineMiter
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineWidth
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationX
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationY
+import androidx.ui.graphics.vectorgraphics.EmptyBrush
+import androidx.ui.graphics.vectorgraphics.EmptyPath
+import androidx.ui.graphics.vectorgraphics.PathData
+import androidx.ui.painting.StrokeCap
+import androidx.ui.painting.StrokeJoin
+import androidx.ui.vector.VectorScope
+import java.util.Stack
+import java.util.function.Consumer
+
+/**
+ * Builder used to construct a Vector graphic tree.
+ * This is useful for caching the result of expensive operations used to construct
+ * a vector graphic for compose.
+ * For example, the vector graphic could be serialized and downloaded from a server and represented
+ * internally in a VectorAsset before it is composed through [DrawVector]
+ * The generated VectorAsset is recommended to be memoized across composition calls to avoid
+ * doing redundant work
+ **/
+class VectorAssetBuilder(
+
+    /**
+     * Name of the vector asset
+     */
+    val name: String = DefaultGroupName,
+
+    /**
+     * Intrinsic width of the Vector in pixels
+     */
+    val defaultWidth: Px,
+
+    /**
+     * Intrinsic height of the Vector in pixels
+     */
+    val defaultHeight: Px,
+
+    /**
+     *  Used to define the width of the viewport space. Viewport is basically the virtual canvas
+     *  where the paths are drawn on.
+     */
+    val viewportWidth: Float,
+
+    /**
+     * Used to define the height of the viewport space. Viewport is basically the virtual canvas
+     * where the paths are drawn on.
+     */
+    val viewportHeight: Float
+) {
+
+    private val nodes = Stack<VectorGroup>()
+
+    private var root = VectorGroup()
+    private var isConsumed = false
+
+    private var currentGroup: VectorGroup = root
+        private set
+        get() = nodes.peek()
+
+    init {
+        nodes.add(root)
+    }
+
+    /**
+     * Create a new group and push it to the front of the stack of VectorAsset nodes
+     * @return This VectorAssetBuilder instance as a convenience for chaining calls
+     */
+    fun pushGroup(
+        name: String = DefaultGroupName,
+        rotate: Float = DefaultRotation,
+        pivotX: Float = DefaultPivotX,
+        pivotY: Float = DefaultPivotY,
+        scaleX: Float = DefaultScaleX,
+        scaleY: Float = DefaultScaleY,
+        translationX: Float = DefaultTranslationX,
+        translationY: Float = DefaultTranslationY,
+        clipPathData: PathData = EmptyPath
+    ): VectorAssetBuilder {
+        ensureNotConsumed()
+        val group = VectorGroup(
+                name,
+                rotate,
+                pivotX,
+                pivotY,
+                scaleX,
+                scaleY,
+                translationX,
+                translationY,
+                clipPathData
+        )
+        nodes.add(group)
+        currentGroup.addNode(group)
+        return this
+    }
+
+    /**
+     * Pops the topmost VectorGroup from this VectorAssetBuilder. This is used to indicate
+     * that no additional VectorAsset nodes will be added to the current VectorGroup
+     * @return This VectorAssetBuilder instance as a convenience for chaining calls
+     */
+    fun popGroup(): VectorAssetBuilder {
+        ensureNotConsumed()
+        nodes.pop()
+        return this
+    }
+
+    /**
+     * Add a path to the VectorAsset graphic. This represents a leaf node in the VectorAsset graphics
+     * tree structure
+     * @return This VectorAssetBuilder instance as a convenience for chaining calls
+     */
+    fun addPath(
+        pathData: PathData,
+        name: String = DefaultPathName,
+        fill: BrushType = EmptyBrush,
+        fillAlpha: Float = DefaultAlpha,
+        stroke: BrushType = EmptyBrush,
+        strokeAlpha: Float = DefaultAlpha,
+        strokeLineWidth: Float = DefaultStrokeLineWidth,
+        strokeLineCap: StrokeCap = DefaultStrokeLineCap,
+        strokeLineJoin: StrokeJoin = DefaultStrokeLineJoin,
+        strokeLineMiter: Float = DefaultStrokeLineMiter
+    ): VectorAssetBuilder {
+        ensureNotConsumed()
+        currentGroup.addNode(
+                VectorPath(
+                        name,
+                        pathData,
+                        fill,
+                        fillAlpha,
+                        stroke,
+                        strokeAlpha,
+                        strokeLineWidth,
+                        strokeLineCap,
+                        strokeLineJoin,
+                        strokeLineMiter
+                )
+        )
+        return this
+    }
+
+    /**
+     * Construct a VectorAsset. This concludes the creation process of a VectorAsset graphic
+     * This builder cannot be re-used to create additional VectorAsset instances
+     * @return Thew newly created VectorAsset instance
+     */
+    fun build(): VectorAsset {
+        ensureNotConsumed()
+        val vectorImage = VectorAsset(
+            name,
+            defaultWidth,
+            defaultHeight,
+            viewportWidth,
+            viewportHeight,
+            root
+        )
+
+        // reset state in case this builder is used again
+        nodes.clear()
+        root = VectorGroup()
+        nodes.add(root)
+
+        isConsumed = true
+
+        return vectorImage
+    }
+
+    /**
+     * Throws IllegalStateException if the VectorAssetBuilder is already been consumed
+     */
+    fun ensureNotConsumed() {
+        if (isConsumed) {
+            throw IllegalStateException("VectorAssetBuilder is single use, create " +
+                    "a new instance to create a new VectorAsset")
+        }
+    }
+}
+
+sealed class VectorNode
+
+/**
+ * Vector graphics object that is generated as a result of [VectorAssetBuilder]]
+ * It can be composed and rendered by passing it as an argument to [DrawVector]
+ */
+class VectorAsset internal constructor(
+
+    /**
+     * Name of the Vector asset
+     */
+    val name: String,
+
+    /**
+     * Intrinsic width of the vector asset in pixels
+     */
+    val defaultWidth: Px,
+
+    /**
+     * Intrinsic height of the vector asset in pixels
+     */
+    val defaultHeight: Px,
+
+    /**
+     *  Used to define the width of the viewport space. Viewport is basically the virtual canvas
+     *  where the paths are drawn on.
+     */
+    val viewportWidth: Float,
+
+    /**
+     * Used to define the height of the viewport space. Viewport is basically the virtual canvas
+     * where the paths are drawn on.
+     */
+    val viewportHeight: Float,
+
+    /**
+     * Root group of the vector asset that contains all the child groups and paths
+     */
+    val root: VectorGroup
+)
+
+/**
+ * Defines a group of paths or subgroups, plus transformation information.
+ * The transformations are defined in the same coordinates as the viewport.
+ * The transformations are applied in the order of scale, rotate then translate.
+ */
+class VectorGroup(
+    /**
+     * Name of the corresponding group
+     */
+    val name: String = DefaultGroupName,
+
+    /**
+     * Rotation of the group in degrees
+     */
+    val rotation: Float = DefaultRotation,
+
+    /**
+     * X coordinate of the pivot point to rotate or scale the group
+     */
+    val pivotX: Float = DefaultPivotX,
+
+    /**
+     * Y coordinate of the pivot point to rotate or scale the group
+     */
+    val pivotY: Float = DefaultPivotY,
+
+    /**
+     * Scale factor in the X-axis to apply to the group
+     */
+    val scaleX: Float = DefaultScaleX,
+
+    /**
+     * Scale factor in the Y-axis to apply to the group
+     */
+    val scaleY: Float = DefaultScaleY,
+
+    /**
+     * Translation in virtual pixels to apply along the x-axis
+     */
+    val translationX: Float = DefaultTranslationX,
+
+    /**
+     * Translation in virtual pixels to apply along the y-axis
+     */
+    val translationY: Float = DefaultTranslationY,
+
+    /**
+     * Path information used to clip the content within the group
+     */
+    val clipPathData: PathData = EmptyPath
+
+) : VectorNode(), Iterable<VectorNode> {
+
+    private val children = ArrayList<VectorNode>()
+
+    internal fun addNode(node: VectorNode) {
+        children.add(node)
+    }
+
+    val size: Int
+        get() = children.size
+
+    operator fun get(index: Int): VectorNode {
+        return children[index]
+    }
+
+    override fun iterator(): Iterator<VectorNode> {
+        return object: Iterator<VectorNode> {
+
+            val it = children.iterator()
+
+            override fun hasNext(): Boolean = it.hasNext()
+
+            override fun next(): VectorNode = it.next()
+        }
+    }
+}
+
+/**
+ * Leaf node of a Vector graphics tree. This specifies a path shape and parameters
+ * to color and style the the shape itself
+ */
+class VectorPath(
+    /**
+     * Name of the corresponding path
+     */
+    val name: String = DefaultPathName,
+
+    /**
+     * Path information to render the shape of the path
+     */
+    val pathData: PathData,
+
+    /**
+     *  Specifies the color or gradient used to fill the path
+     */
+    val fill: BrushType = EmptyBrush,
+
+    /**
+     * Opacity to fill the path
+     */
+    val fillAlpha: Float = DefaultAlpha,
+
+    /**
+     * Specifies the color or gradient used to fill the stroke
+     */
+    val stroke: BrushType = EmptyBrush,
+
+    /**
+     * Opacity to stroke the path
+     */
+    val strokeAlpha: Float = DefaultAlpha,
+
+    /**
+     * Width of the line to stroke the path
+     */
+    val strokeLineWidth: Float = DefaultStrokeLineWidth,
+
+    /**
+     * Specifies the linecap for a stroked path, either butt, round, or square. The default is butt.
+     */
+    val strokeLineCap: StrokeCap = DefaultStrokeLineCap,
+
+    /**
+     * Specifies the linejoin for a stroked path, either miter, round or bevel. The default is miter
+     */
+    val strokeLineJoin: StrokeJoin = DefaultStrokeLineJoin,
+
+    /**
+     * Specifies the miter limit for a stroked path, the default is 4
+     */
+    val strokeLineMiter: Float = DefaultStrokeLineMiter
+) : VectorNode()
+
+/**
+ * Composes a vector graphic into the composition tree based on the specification
+ * provided by given [VectorAsset]
+ */
+@Composable
+fun DrawVector(vectorImage: VectorAsset) {
+    DrawVector(
+        name = vectorImage.name,
+        viewportWidth = vectorImage.viewportWidth,
+        viewportHeight = vectorImage.viewportHeight,
+        defaultWidth = vectorImage.defaultWidth,
+        defaultHeight = vectorImage.defaultHeight) {
+        RenderVectorGroup(group = vectorImage.root)
+    }
+}
+
+/**
+ * Recursive method for creating the vector graphic composition by traversing
+ * the tree structure
+ */
+@Composable
+private fun VectorScope.RenderVectorGroup(group: VectorGroup) {
+    for (vectorNode in group) {
+        if (vectorNode is VectorPath) {
+            Path(
+                pathData = vectorNode.pathData,
+                name = vectorNode.name,
+                fill = vectorNode.fill,
+                fillAlpha = vectorNode.fillAlpha,
+                stroke = vectorNode.stroke,
+                strokeAlpha = vectorNode.strokeAlpha,
+                strokeLineWidth = vectorNode.strokeLineWidth,
+                strokeLineCap = vectorNode.strokeLineCap,
+                strokeLineJoin = vectorNode.strokeLineJoin,
+                strokeLineMiter = vectorNode.strokeLineMiter
+            )
+        } else if (vectorNode is VectorGroup) {
+            Group(
+                name = vectorNode.name,
+                rotation = vectorNode.rotation,
+                scaleX = vectorNode.scaleX,
+                scaleY = vectorNode.scaleY,
+                translationX = vectorNode.translationX,
+                translationY = vectorNode.translationY,
+                pivotX = vectorNode.pivotX,
+                pivotY = vectorNode.pivotY,
+                clipPathData = vectorNode.clipPathData) {
+                RenderVectorGroup(group = vectorNode)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorCompose.kt b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorCompose.kt
new file mode 100644
index 0000000..4e36f04
--- /dev/null
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/VectorCompose.kt
@@ -0,0 +1,153 @@
+/*
+ * 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.core.vectorgraphics
+
+import androidx.compose.Children
+import androidx.compose.Composable
+import androidx.compose.composer
+import androidx.compose.compositionReference
+import androidx.compose.memo
+import androidx.compose.onDispose
+import androidx.compose.onPreCommit
+import androidx.compose.unaryPlus
+
+import androidx.ui.core.Draw
+import androidx.ui.core.Px
+import androidx.ui.graphics.vectorgraphics.Brush
+import androidx.ui.graphics.vectorgraphics.BrushType
+import androidx.ui.graphics.vectorgraphics.DefaultAlpha
+import androidx.ui.graphics.vectorgraphics.DefaultGroupName
+import androidx.ui.graphics.vectorgraphics.DefaultPathName
+import androidx.ui.graphics.vectorgraphics.DefaultPivotX
+import androidx.ui.graphics.vectorgraphics.DefaultPivotY
+import androidx.ui.graphics.vectorgraphics.DefaultRotation
+import androidx.ui.graphics.vectorgraphics.DefaultScaleX
+import androidx.ui.graphics.vectorgraphics.DefaultScaleY
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineCap
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineJoin
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineMiter
+import androidx.ui.graphics.vectorgraphics.DefaultStrokeLineWidth
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationX
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationY
+import androidx.ui.graphics.vectorgraphics.EmptyBrush
+import androidx.ui.graphics.vectorgraphics.EmptyPath
+import androidx.ui.graphics.vectorgraphics.PathData
+import androidx.ui.graphics.vectorgraphics.VectorComponent
+import androidx.ui.graphics.vectorgraphics.GroupComponent
+import androidx.ui.graphics.vectorgraphics.PathComponent
+import androidx.ui.graphics.vectorgraphics.createPath
+import androidx.ui.graphics.vectorgraphics.obtainBrush
+import androidx.ui.painting.StrokeCap
+import androidx.ui.painting.StrokeJoin
+import androidx.ui.vector.VectorScope
+import androidx.ui.vector.composeVector
+import androidx.ui.vector.disposeVector
+import java.util.Vector
+
+
+@Composable
+fun DrawVector(
+    viewportWidth: Float,
+    viewportHeight: Float,
+    defaultWidth: Px = Px(viewportWidth),
+    defaultHeight: Px = Px(viewportHeight),
+    name: String = "",
+    @Children children: @Composable() VectorScope.() -> Unit
+) {
+    val vector = +memo(name, viewportWidth, viewportHeight) {
+        VectorComponent(
+            name,
+            viewportWidth,
+            viewportHeight,
+            defaultWidth,
+            defaultHeight
+        )
+    }
+
+    val ref = +compositionReference()
+    composeVector(vector, ref, children)
+    +onPreCommit(vector) {
+        onDispose { disposeVector(vector, ref) }
+    }
+
+    Draw { canvas, _ ->
+        vector.draw(canvas)
+    }
+}
+
+@Composable
+fun VectorScope.Group(
+    name: String = DefaultGroupName,
+    rotation: Float = DefaultRotation,
+    pivotX: Float = DefaultPivotX,
+    pivotY: Float = DefaultPivotY,
+    scaleX: Float = DefaultScaleX,
+    scaleY: Float = DefaultScaleY,
+    translationX: Float = DefaultTranslationX,
+    translationY: Float = DefaultTranslationY,
+    clipPathData: PathData = EmptyPath,
+    @Children children: @Composable() VectorScope.() -> Unit
+) {
+
+    val clipPathNodes = +memo(clipPathData) {
+        createPath(clipPathData)
+    }
+    <GroupComponent
+        name = name
+        rotation = rotation
+        pivotX = pivotX
+        pivotY = pivotY
+        scaleX = scaleX
+        scaleY = scaleY
+        translationX = translationX
+        translationY = translationY
+        clipPathNodes = clipPathNodes
+    >
+        children()
+    </GroupComponent>
+}
+
+@Composable
+fun VectorScope.Path(
+    pathData: PathData,
+    name: String = DefaultPathName,
+    fill: BrushType = EmptyBrush,
+    fillAlpha: Float = DefaultAlpha,
+    stroke: BrushType = EmptyBrush,
+    strokeAlpha: Float = DefaultAlpha,
+    strokeLineWidth: Float = DefaultStrokeLineWidth,
+    strokeLineCap: StrokeCap = DefaultStrokeLineCap,
+    strokeLineJoin: StrokeJoin = DefaultStrokeLineJoin,
+    strokeLineMiter: Float = DefaultStrokeLineMiter
+) {
+    val pathNodes = createPath(pathData)
+    val fillBrush: Brush = obtainBrush(fill)
+    val strokeBrush: Brush = obtainBrush(stroke)
+
+    <PathComponent
+        name
+        pathNodes
+        fill = fillBrush
+        fillAlpha
+        stroke = strokeBrush
+        strokeAlpha
+        strokeLineWidth
+        strokeLineJoin
+        strokeLineCap
+        strokeLineMiter
+    />
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/VectorResource.kt b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/VectorResource.kt
index c129e97..a886ad0 100644
--- a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/VectorResource.kt
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/VectorResource.kt
@@ -16,395 +16,41 @@
 
 package androidx.ui.core.vectorgraphics.compat
 
+import androidx.compose.composer
 import android.annotation.SuppressLint
 import android.content.res.Resources
-import android.content.res.TypedArray
-import android.util.AttributeSet
-import android.util.Log
 import android.util.Xml
-import androidx.core.content.res.TypedArrayUtils
-import androidx.ui.core.vectorgraphics.addPathNodes
-import androidx.ui.core.vectorgraphics.group
-import androidx.ui.core.vectorgraphics.path
-import androidx.ui.core.vectorgraphics.vector
-import androidx.ui.painting.StrokeCap
-import androidx.ui.painting.StrokeJoin
-import androidx.ui.core.vectorgraphics.DefaultPivotX
-import androidx.ui.core.vectorgraphics.DefaultPivotY
-import androidx.ui.core.vectorgraphics.DefaultRotate
-import androidx.ui.core.vectorgraphics.DefaultScaleX
-import androidx.ui.core.vectorgraphics.DefaultScaleY
-import androidx.ui.core.vectorgraphics.DefaultTranslateX
-import androidx.ui.core.vectorgraphics.DefaultTranslateY
-import androidx.ui.core.vectorgraphics.EmptyBrush
-import androidx.ui.core.vectorgraphics.EmptyPath
-import androidx.ui.core.vectorgraphics.PathNode
-import androidx.compose.Children
 import androidx.compose.Composable
-import androidx.compose.composer
-import org.xmlpull.v1.XmlPullParser
+import androidx.compose.ambient
+import androidx.compose.memo
+import androidx.compose.unaryPlus
+import androidx.ui.core.ContextAmbient
+import androidx.ui.core.vectorgraphics.DrawVector
+import androidx.ui.core.vectorgraphics.VectorAsset
 import org.xmlpull.v1.XmlPullParserException
-import java.io.IOException
-
-private val LINECAP_BUTT = 0
-private val LINECAP_ROUND = 1
-private val LINECAP_SQUARE = 2
-
-private val LINEJOIN_MITER = 0
-private val LINEJOIN_ROUND = 1
-private val LINEJOIN_BEVEL = 2
-
-private val FILL_TYPE_WINDING = 0
-
-private val SHAPE_CLIP_PATH = "clip-VPath"
-private val SHAPE_GROUP = "group"
-private val SHAPE_PATH = "path"
-
-private val LOGTAG = "VectorGraphicCreator"
-
-private fun getStrokeLineCap(id: Int, defValue: StrokeCap = StrokeCap.butt): StrokeCap =
-    when (id) {
-        LINECAP_BUTT -> StrokeCap.butt
-        LINECAP_ROUND -> StrokeCap.round
-        LINECAP_SQUARE -> StrokeCap.square
-        else -> defValue
-    }
-
-private fun getStrokeLineJoin(id: Int, defValue: StrokeJoin = StrokeJoin.miter): StrokeJoin =
-    when (id) {
-        LINEJOIN_MITER -> StrokeJoin.miter
-        LINEJOIN_ROUND -> StrokeJoin.round
-        LINEJOIN_BEVEL -> StrokeJoin.bevel
-        else -> defValue
-    }
 
 @Composable
+fun VectorResource(resId: Int) {
+    val context = +ambient(ContextAmbient)
+    val res = context.resources
+    val theme = context.theme
+    val vectorImage = +memo(resId) {
+        loadVectorResource(theme, res, resId)
+    }
+    DrawVector(vectorImage = vectorImage)
+}
+
+@Throws(XmlPullParserException::class)
 @SuppressWarnings("RestrictedApi")
-private fun inflateGroup(
-    a: TypedArray,
-    parser: XmlPullParser,
-    @Suppress("UNUSED_PARAMETER") theme: Resources.Theme?,
-    @Children childNodes: @Composable() () -> Unit
-) {
-    // Account for any configuration changes.
-    // mChangingConfigurations |= Utils.getChangingConfigurations(a);
+fun loadVectorResource(theme: Resources.Theme? = null, res: Resources, resId: Int): VectorAsset {
 
-    // Extract the theme attributes, if any.
-    // mThemeAttrs = null // TODO TINT THEME Not supported yet a.extractThemeAttrs();
-
-    // This is added in API 11
-    val rotate = TypedArrayUtils.getNamedFloat(
-        a, parser, "rotation",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_ROTATION,
-        DefaultRotate
-    )
-
-    val pivotX = a.getFloat(
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_X,
-        DefaultPivotX
-    )
-    val pivotY = a.getFloat(
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_Y,
-        DefaultPivotY
-    )
-
-    // This is added in API 11
-    val scaleX = TypedArrayUtils.getNamedFloat(
-        a, parser, "scaleX",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_X,
-        DefaultScaleX
-    )
-
-    // This is added in API 11
-    val scaleY = TypedArrayUtils.getNamedFloat(
-        a, parser, "scaleY",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_Y,
-        DefaultScaleY
-    )
-
-    val translateX = TypedArrayUtils.getNamedFloat(
-        a, parser, "translateX",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_X,
-        DefaultTranslateX
-    )
-    val translateY = TypedArrayUtils.getNamedFloat(
-        a, parser, "translateY",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_Y,
-        DefaultTranslateY
-    )
-
-    val name: String =
-        a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_NAME) ?: ""
-
-    parser.next()
-
-    // TODO parse clip path
-    val clipPathData = EmptyPath
-    group(
-        name = name,
-        rotate = rotate,
-        scaleX = scaleX,
-        scaleY = scaleY,
-        translateX = translateX,
-        translateY = translateY,
-        pivotX = pivotX,
-        pivotY = pivotY,
-        clipPathData = clipPathData
-    ) {
-        childNodes()
-    }
-}
-
-@Suppress("UNUSED_PARAMETER")
-@Composable
-private fun inflateClip(
-    a: TypedArray,
-    parser: XmlPullParser,
-    theme: Resources.Theme?,
-    @Children childNodes: @Composable() () -> Unit
-) {
-//    var pathName: String? =
-//        a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_NAME)
-//    if (pathName == null) {
-//        pathName = ""
-//    }
-//    val pathData = a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH_PATH_DATA)
-
-    // TODO (njawad) finish parsing clip paths from xml resources
-}
-
-@Composable
-@SuppressWarnings("RestrictedApi")
-private fun inflatePath(a: TypedArray, parser: XmlPullParser, theme: Resources.Theme?) {
-    val hasPathData = TypedArrayUtils.hasAttribute(parser, "pathData")
-    if (!hasPathData) {
-        // If there is no pathData in the VPath tag, then this is an empty VPath,
-        // nothing need to be drawn.
-        Log.v("VectorPath", "no path data available skipping path")
-        return
-    }
-
-    val name: String = a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_NAME) ?: ""
-
-    val pathStr = a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_PATH_DATA)
-
-    val pathData: Array<PathNode> = addPathNodes(pathStr)
-
-    val fillColor = TypedArrayUtils.getNamedComplexColor(
-        a, parser, theme, "fillColor",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_COLOR, 0
-    )
-    // TODO(njawad): restore these when they are used
-/*    val fillAlpha = TypedArrayUtils.getNamedFloat(
-        a, parser, "fillAlpha",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_ALPHA, 1.0f
-    )
-    val lineCap = TypedArrayUtils.getNamedInt(
-        a, parser, "strokeLineCap",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_CAP, -1
-    )
-    val strokeLineCap =
-        getStrokeLineCap(lineCap, StrokeCap.butt)
-    val lineJoin = TypedArrayUtils.getNamedInt(
-        a, parser, "strokeLineJoin",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_JOIN, -1
-    )
-    val strokeLineJoin =
-        getStrokeLineJoin(lineJoin, StrokeJoin.bevel)
-    val strokeMiterlimit = TypedArrayUtils.getNamedFloat(
-        a, parser, "strokeMiterLimit",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_MITER_LIMIT,
-        1.0f
-    )*/
-    val strokeColor = TypedArrayUtils.getNamedComplexColor(
-        a, parser, theme, "strokeColor",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_COLOR, 0
-    )
-    val strokeAlpha = TypedArrayUtils.getNamedFloat(
-        a, parser, "strokeAlpha",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_ALPHA, 1.0f
-    )
-    val strokeLineWidth = TypedArrayUtils.getNamedFloat(
-        a, parser, "strokeWidth",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_WIDTH, 1.0f
-    )
-    /*val trimPathEnd = TypedArrayUtils.getNamedFloat(
-        a, parser, "trimPathEnd",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_END, 1.0f
-    )
-    val trimPathOffset = TypedArrayUtils.getNamedFloat(
-        a, parser, "trimPathOffset",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_OFFSET,
-        0.0f
-    )
-    val trimPathStart = TypedArrayUtils.getNamedFloat(
-        a, parser, "trimPathStart",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_START,
-        0.0f
-    )
-    val fillRule = TypedArrayUtils.getNamedInt(
-        a, parser, "fillType",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_FILLTYPE,
-        FILL_TYPE_WINDING
-    )*/
-
-    // TODO update path with additional params
-    path(
-        name = name,
-        fill = if (fillColor.willDraw()) fillColor.color else EmptyBrush,
-        strokeAlpha = strokeAlpha,
-        strokeLineWidth = strokeLineWidth,
-        stroke = if (strokeColor.willDraw()) strokeColor.color else EmptyBrush,
-        pathData = pathData
-    )
-}
-
-@Composable
-@SuppressWarnings("RestrictedApi")
-private fun inflateInner(
-    res: Resources,
-    attrs: AttributeSet,
-    theme: Resources.Theme?,
-    innerDepth: Int,
-    parser: XmlPullParser
-) {
-    var eventType = parser.getEventType()
-
-    // Parse everything until the end of the VectorGraphic element.
-    while (eventType != XmlPullParser.END_DOCUMENT &&
-        (parser.getDepth() >= innerDepth || eventType != XmlPullParser.END_TAG)
-    ) {
-        if (eventType == XmlPullParser.START_TAG) {
-            val tagName = parser.getName()
-            if (SHAPE_PATH.equals(tagName)) {
-                Log.v("VectorPath", "parsing path...")
-                val a = TypedArrayUtils.obtainAttributes(
-                    res, theme, attrs,
-                    AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH
-                )
-                inflatePath(a = a, parser = parser, theme = theme)
-                a.recycle()
-            } else if (SHAPE_CLIP_PATH.equals(tagName)) {
-                val a = TypedArrayUtils.obtainAttributes(
-                    res, theme, attrs,
-                    AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_CLIP_PATH
-                )
-                inflateClip(a = a, parser = parser, theme = theme) {
-                    inflateInner(
-                        res = res,
-                        parser = parser,
-                        attrs = attrs,
-                        theme = theme,
-                        innerDepth = innerDepth
-                    )
-                }
-                a.recycle()
-            } else if (SHAPE_GROUP.equals(tagName)) {
-                val a = TypedArrayUtils.obtainAttributes(
-                    res, theme, attrs,
-                    AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP
-                )
-                inflateGroup(a = a, parser = parser, theme = theme) {
-                    inflateInner(
-                        res = res,
-                        parser = parser,
-                        attrs = attrs,
-                        theme = theme,
-                        innerDepth = innerDepth
-                    )
-                }
-                a.recycle()
-            }
-        }
-        eventType = parser.next()
-    }
-}
-
-@Composable
-@SuppressWarnings("RestrictedApi")
-private fun inflate(
-    res: Resources,
-    parser: XmlPullParser,
-    attrs: AttributeSet,
-    theme: Resources.Theme?
-) {
-    val innerDepth = parser.getDepth() + 1
-
-    val vectorAttrs = TypedArrayUtils.obtainAttributes(
-        res, theme, attrs,
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_TYPE_ARRAY
-    )
-
-    // TODO (njawad) handle mirroring here
-//        state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
-//                AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_AUTO_MIRRORED, state.mAutoMirrored)
-
-    val viewportWidth = TypedArrayUtils.getNamedFloat(
-        vectorAttrs, parser, "viewportWidth",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_WIDTH,
-        0.0f
-    )
-
-    val viewportHeight = TypedArrayUtils.getNamedFloat(
-        vectorAttrs, parser, "viewportHeight",
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_HEIGHT,
-        0.0f
-    )
-
-    if (viewportWidth <= 0) {
-        throw XmlPullParserException(
-            vectorAttrs.getPositionDescription() +
-                    "VectorGraphic requires viewportWidth > 0"
-        )
-    } else if (viewportHeight <= 0) {
-        throw XmlPullParserException(
-            vectorAttrs.getPositionDescription() +
-                    "VectorGraphic requires viewportHeight > 0"
-        )
-    }
-
-    val defaultWidth = vectorAttrs.getDimension(
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_WIDTH, 0.0f
-    )
-    val defaultHeight = vectorAttrs.getDimension(
-        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_HEIGHT, 0.0f
-    )
-
-    vector(
-        name = "vector",
-        defaultWidth = defaultWidth,
-        defaultHeight = defaultHeight,
-        viewportWidth = viewportWidth,
-        viewportHeight = viewportHeight
-    ) {
-        inflateInner(
-            res = res,
-            attrs = attrs,
-            theme = theme,
-            innerDepth = innerDepth,
-            parser = parser
-        )
-    }
-}
-
-@Composable
-fun vectorResource(res: Resources, resId: Int) {
     @SuppressLint("ResourceType") val parser = res.getXml(resId)
     val attrs = Xml.asAttributeSet(parser)
-    var type: Int
-    try {
-        type = parser.next()
-        while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
-            // Empty loop
-            type = parser.next()
-        }
-        if (type != XmlPullParser.START_TAG) {
-            throw XmlPullParserException("No start tag found")
-        }
-        inflate(res = res, parser = parser, attrs = attrs, theme = null)
-    } catch (e: XmlPullParserException) {
-        Log.e(LOGTAG, "parser error", e)
-    } catch (e: IOException) {
-        Log.e(LOGTAG, "parser error", e)
+    val builder = parser.seekToStartTag().createVectorImageBuilder(res, theme, attrs)
+
+    while (!parser.isAtEnd()) {
+        parser.parseCurrentVectorNode(res, attrs, theme, builder)
+        parser.next()
     }
-}
+    return builder.build()
+}
\ No newline at end of file
diff --git a/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParser.kt b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParser.kt
new file mode 100644
index 0000000..88749ef
--- /dev/null
+++ b/ui/ui-framework/src/main/java/androidx/ui/core/vectorgraphics/compat/XmlVectorParser.kt
@@ -0,0 +1,394 @@
+/*
+ * 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.core.vectorgraphics.compat
+
+import android.content.res.Resources
+import android.util.AttributeSet
+import androidx.core.content.res.TypedArrayUtils
+import androidx.ui.core.Px
+import androidx.ui.core.vectorgraphics.VectorAssetBuilder
+import androidx.ui.graphics.vectorgraphics.DefaultPivotX
+import androidx.ui.graphics.vectorgraphics.DefaultPivotY
+import androidx.ui.graphics.vectorgraphics.DefaultRotation
+import androidx.ui.graphics.vectorgraphics.DefaultScaleX
+import androidx.ui.graphics.vectorgraphics.DefaultScaleY
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationX
+import androidx.ui.graphics.vectorgraphics.DefaultTranslationY
+import androidx.ui.graphics.vectorgraphics.EmptyBrush
+import androidx.ui.graphics.vectorgraphics.EmptyPath
+import androidx.ui.graphics.vectorgraphics.PathNode
+import androidx.ui.graphics.vectorgraphics.addPathNodes
+import androidx.ui.painting.StrokeCap
+import androidx.ui.painting.StrokeJoin
+import org.xmlpull.v1.XmlPullParser
+import org.xmlpull.v1.XmlPullParserException
+
+private val LINECAP_BUTT = 0
+private val LINECAP_ROUND = 1
+private val LINECAP_SQUARE = 2
+
+private val LINEJOIN_MITER = 0
+private val LINEJOIN_ROUND = 1
+private val LINEJOIN_BEVEL = 2
+
+private val FILL_TYPE_WINDING = 0
+
+private val SHAPE_CLIP_PATH = "clip-VPath"
+private val SHAPE_GROUP = "group"
+private val SHAPE_PATH = "path"
+
+private fun getStrokeLineCap(id: Int, defValue: StrokeCap = StrokeCap.butt): StrokeCap =
+    when (id) {
+        LINECAP_BUTT -> StrokeCap.butt
+        LINECAP_ROUND -> StrokeCap.round
+        LINECAP_SQUARE -> StrokeCap.square
+        else -> defValue
+    }
+
+private fun getStrokeLineJoin(id: Int, defValue: StrokeJoin = StrokeJoin.miter): StrokeJoin =
+    when (id) {
+        LINEJOIN_MITER -> StrokeJoin.miter
+        LINEJOIN_ROUND -> StrokeJoin.round
+        LINEJOIN_BEVEL -> StrokeJoin.bevel
+        else -> defValue
+    }
+
+internal fun XmlPullParser.isAtEnd(): Boolean =
+    eventType == XmlPullParser.END_DOCUMENT ||
+            (depth < 1 && eventType == XmlPullParser.END_TAG)
+
+internal fun XmlPullParser.parseCurrentVectorNode(
+    res: Resources,
+    attrs: AttributeSet,
+    theme: Resources.Theme? = null,
+    builder: VectorAssetBuilder
+) {
+    when (eventType) {
+        XmlPullParser.START_TAG -> {
+            when (name) {
+                SHAPE_PATH -> {
+                    parsePath(res, theme, attrs, builder)
+                }
+                SHAPE_CLIP_PATH -> {
+                    // TODO parse clipping paths
+                }
+                SHAPE_GROUP -> {
+                    parseGroup(res, theme, attrs, builder)
+                }
+            }
+        }
+        XmlPullParser.END_TAG -> {
+            if (SHAPE_GROUP == name) {
+                builder.popGroup()
+            }
+        }
+    }
+}
+
+/**
+ * Helper method to seek to the first tag within the VectorDrawable xml asset
+ */
+@Throws(XmlPullParserException::class)
+internal fun XmlPullParser.seekToStartTag(): XmlPullParser {
+    var type = next()
+    while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
+        // Empty loop
+        type = next()
+    }
+    if (type != XmlPullParser.START_TAG) {
+        throw XmlPullParserException("No start tag found")
+    }
+    return this
+}
+
+@SuppressWarnings("RestrictedApi")
+internal fun XmlPullParser.createVectorImageBuilder(
+    res: Resources,
+    theme: Resources.Theme?,
+    attrs: AttributeSet
+): VectorAssetBuilder {
+    val vectorAttrs = TypedArrayUtils.obtainAttributes(
+        res,
+        theme,
+        attrs,
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_TYPE_ARRAY
+    )
+
+    // TODO (njawad) handle mirroring here
+//        state.mAutoMirrored = TypedArrayUtils.getNamedBoolean(a, parser, "autoMirrored",
+//                AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_AUTO_MIRRORED, state.mAutoMirrored)
+
+    val viewportWidth = TypedArrayUtils.getNamedFloat(
+        vectorAttrs,
+        this,
+        "viewportWidth",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_WIDTH,
+        0.0f
+    )
+
+    val viewportHeight = TypedArrayUtils.getNamedFloat(
+        vectorAttrs,
+        this,
+        "viewportHeight",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_VIEWPORT_HEIGHT,
+        0.0f
+    )
+
+    if (viewportWidth <= 0) {
+        throw XmlPullParserException(
+            vectorAttrs.getPositionDescription() +
+                    "<VectorGraphic> tag requires viewportWidth > 0"
+        )
+    } else if (viewportHeight <= 0) {
+        throw XmlPullParserException(
+            vectorAttrs.getPositionDescription() +
+                    "<VectorGraphic> tag requires viewportHeight > 0"
+        )
+    }
+
+    val defaultWidth = vectorAttrs.getDimension(
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_WIDTH, 0.0f
+    )
+    val defaultHeight = vectorAttrs.getDimension(
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_HEIGHT, 0.0f
+    )
+
+    vectorAttrs.recycle()
+
+    return VectorAssetBuilder(
+        defaultWidth = Px(defaultWidth),
+        defaultHeight = Px(defaultHeight),
+        viewportWidth = viewportWidth,
+        viewportHeight = viewportHeight
+    )
+}
+
+@Throws(IllegalArgumentException::class)
+@SuppressWarnings("RestrictedApi")
+internal fun XmlPullParser.parsePath(
+    res: Resources,
+    theme: Resources.Theme?,
+    attrs: AttributeSet,
+    builder: VectorAssetBuilder
+) {
+    val a = TypedArrayUtils.obtainAttributes(
+        res,
+        theme,
+        attrs,
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH
+    )
+
+    val hasPathData = TypedArrayUtils.hasAttribute(this, "pathData")
+    if (!hasPathData) {
+        // If there is no pathData in the VPath tag, then this is an empty VPath,
+        // nothing need to be drawn.
+        throw IllegalArgumentException("No path data available")
+    }
+
+    val name: String = a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_NAME) ?: ""
+
+    val pathStr = a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_PATH_DATA)
+
+    val pathData: Array<PathNode> = addPathNodes(pathStr)
+
+    val fillColor = TypedArrayUtils.getNamedComplexColor(
+        a,
+        this,
+        theme,
+        "fillColor",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_COLOR, 0
+    )
+    val fillAlpha = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "fillAlpha",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_FILL_ALPHA, 1.0f
+    )
+    val lineCap = TypedArrayUtils.getNamedInt(
+        a,
+        this,
+        "strokeLineCap",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_CAP, -1
+    )
+    val strokeLineCap = getStrokeLineCap(lineCap, StrokeCap.butt)
+    val lineJoin = TypedArrayUtils.getNamedInt(
+        a,
+        this,
+        "strokeLineJoin",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_LINE_JOIN, -1
+    )
+    val strokeLineJoin = getStrokeLineJoin(lineJoin, StrokeJoin.bevel)
+    val strokeMiterLimit = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "strokeMiterLimit",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_MITER_LIMIT,
+        1.0f
+    )
+    val strokeColor = TypedArrayUtils.getNamedComplexColor(
+        a,
+        this,
+        theme,
+        "strokeColor",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_COLOR, 0
+    )
+    val strokeAlpha = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "strokeAlpha",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_ALPHA, 1.0f
+    )
+    val strokeLineWidth = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "strokeWidth",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_STROKE_WIDTH, 1.0f
+    )
+
+    // TODO (njawad) handle trim paths + fill rule
+//    val trimPathEnd = TypedArrayUtils.getNamedFloat(
+//        a, this, "trimPathEnd",
+//        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_END, 1.0f
+//    )
+//    val trimPathOffset = TypedArrayUtils.getNamedFloat(
+//        a, this, "trimPathOffset",
+//        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_OFFSET,
+//        0.0f
+//    )
+//    val trimPathStart = TypedArrayUtils.getNamedFloat(
+//        a, this, "trimPathStart",
+//        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_START,
+//        0.0f
+//    )
+//    val fillRule = TypedArrayUtils.getNamedInt(
+//        a, this, "fillType",
+//        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_PATH_TRIM_PATH_FILLTYPE,
+//        FILL_TYPE_WINDING
+//    )
+
+    a.recycle()
+
+    @Suppress("IMPLICIT_CAST_TO_ANY")
+    val fillBrush = if (fillColor.willDraw()) fillColor.color else EmptyBrush
+
+    @Suppress("IMPLICIT_CAST_TO_ANY")
+    val strokeBrush = if (strokeColor.willDraw()) strokeColor.color else EmptyBrush
+
+    builder.addPath(
+        pathData,
+        name,
+        fillBrush,
+        fillAlpha,
+        strokeBrush,
+        strokeAlpha,
+        strokeLineWidth,
+        strokeLineCap,
+        strokeLineJoin,
+        strokeMiterLimit)
+}
+
+@SuppressWarnings("RestrictedApi")
+internal fun XmlPullParser.parseGroup(
+    res: Resources,
+    theme: Resources.Theme?,
+    attrs: AttributeSet,
+    builder: VectorAssetBuilder
+) {
+    val a = TypedArrayUtils.obtainAttributes(
+        res,
+        theme,
+        attrs,
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP
+    )
+
+    // Account for any configuration changes.
+    // mChangingConfigurations |= Utils.getChangingConfigurations(a);
+
+    // Extract the theme attributes, if any.
+    // mThemeAttrs = null // TODO TINT THEME Not supported yet a.extractThemeAttrs();
+
+    // This is added in API 11
+    val rotate = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "rotation",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_ROTATION,
+        DefaultRotation
+    )
+
+    val pivotX = a.getFloat(
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_X,
+        DefaultPivotX
+    )
+    val pivotY = a.getFloat(
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_PIVOT_Y,
+        DefaultPivotY
+    )
+
+    // This is added in API 11
+    val scaleX = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "scaleX",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_X,
+        DefaultScaleX
+    )
+
+    // This is added in API 11
+    val scaleY = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "scaleY",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_SCALE_Y,
+        DefaultScaleY
+    )
+
+    val translateX = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "translationX",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_X,
+        DefaultTranslationX
+    )
+    val translateY = TypedArrayUtils.getNamedFloat(
+        a,
+        this,
+        "translationY",
+        AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_TRANSLATE_Y,
+        DefaultTranslationY
+    )
+
+    val name: String =
+        a.getString(AndroidVectorResources.STYLEABLE_VECTOR_DRAWABLE_GROUP_NAME) ?: ""
+
+    // TODO parse clip path
+    val clipPathData = EmptyPath
+
+    a.recycle()
+
+    builder.pushGroup(
+        name,
+        rotate,
+        scaleX,
+        scaleY,
+        translateX,
+        translateY,
+        pivotX,
+        pivotY,
+        clipPathData
+    )
+}
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
new file mode 100644
index 0000000..1890b9f
--- /dev/null
+++ b/ui/ui-framework/src/test/java/androidx/ui/core/gesture/DoubleTapGestureDetectorTest.kt
@@ -0,0 +1,522 @@
+/*
+ * 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.core.gesture
+
+import androidx.ui.core.PxPosition
+import androidx.ui.core.consumeDownChange
+import androidx.ui.core.milliseconds
+import androidx.ui.core.millisecondsToTimestamp
+import androidx.ui.core.px
+import androidx.ui.testutils.consume
+import androidx.ui.testutils.down
+import androidx.ui.testutils.invokeOverAllPasses
+import androidx.ui.testutils.moveTo
+import androidx.ui.testutils.up
+import com.google.common.truth.Truth.assertThat
+import com.nhaarman.mockitokotlin2.any
+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
+
+// TODO(shepshapard): Add more tests for:
+//  1. More complex multi-pointer scenarios testing how consumption affects firing events
+//  2. More complex multi-pointer scenarios testing how pointers effect consumption
+
+@ObsoleteCoroutinesApi
+@RunWith(JUnit4::class)
+class DoubleTapGestureDetectorTest {
+
+    private val DoubleTapTimeoutMillis = 100.milliseconds
+    private val testContext = TestCoroutineContext()
+    private val onDoubleTap: (PxPosition) -> Unit = mock()
+    private lateinit var mRecognizer: DoubleTapGestureRecognizer
+
+    @Before
+    fun setup() {
+        mRecognizer = DoubleTapGestureRecognizer(onDoubleTap, testContext)
+        mRecognizer.doubleTapTimeout = DoubleTapTimeoutMillis
+    }
+
+    // Tests that verify conditions under which onDoubleTap will not be called.
+
+    @Test
+    fun pointerInputHandler_down_onDoubleTapNotCalled() {
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(listOf(down()))
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUp_onDoubleTapNotCalled() {
+        val down = down(timestamp = 0L.millisecondsToTimestamp())
+        val up = down.up(timestamp = 1L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownWithinTimeout_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownOutsideTimeout_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        testContext.advanceTimeBy(100, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownOutsideTimeoutUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(100, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downMoveConsumedUpDownInsideTimeoutUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val moveConsumed = down1.moveTo(1L.millisecondsToTimestamp(), x = 1f).consume(dx = 1f)
+        val up1 = moveConsumed.up(timestamp = 2L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(moveConsumed)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownInsideTimeoutMoveConsumedUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+        val moveConsumed = down2.moveTo(101L.millisecondsToTimestamp(), x = 1f).consume(dx = 1f)
+        val up2 = moveConsumed.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(moveConsumed)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_2Down1MoveConsumedUpDownInsideTimeoutUp_onLongPressNotCalled() {
+        val down1A = down(0, timestamp = 0L.millisecondsToTimestamp())
+        val down1B = down(1, timestamp = 0L.millisecondsToTimestamp())
+        val moveConsumed1A = down1A.moveTo(1L.millisecondsToTimestamp(), x = 1f).consume(dx = 1f)
+        val move1B = down1B.moveTo(1L.millisecondsToTimestamp())
+        val up1A = moveConsumed1A.up(timestamp = 2L.millisecondsToTimestamp())
+        val up1B = move1B.up(timestamp = 2L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1A, down1B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(moveConsumed1A, move1B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1A, up1B)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUp2DownInsideTimeout1MoveConsumedUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up2 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2A = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val down2B = down(1, timestamp = 100L.millisecondsToTimestamp())
+        val moveConsumed2A = down2A.moveTo(101L.millisecondsToTimestamp(), x = 1f).consume(dx = 1f)
+        val move2B = down2B.moveTo(101L.millisecondsToTimestamp())
+        val up2A = moveConsumed2A.up(timestamp = 102L.millisecondsToTimestamp())
+        val up2B = move2B.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2A, down2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(moveConsumed2A, move2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2A, up2B)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downConsumedUpDownWithinTimeoutUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp()).consumeDownChange()
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpConsumedDownWithinTimeoutUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp()).consumeDownChange()
+        val down2 = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownConsumedWithinTimeoutUp_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(0, timestamp = 100L.millisecondsToTimestamp()).consumeDownChange()
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownWithinTimeoutUpConsumed_onLongPressNotCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp()).consumeDownChange()
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_2down1Up1DownWithinTimeout1Up_onLongPressNotCalled() {
+        val down1A = down(0, timestamp = 0L.millisecondsToTimestamp())
+        val down1B = down(1, timestamp = 0L.millisecondsToTimestamp())
+        val move1A1 = down1A.moveTo(2L.millisecondsToTimestamp())
+        val up2B = down1B.up(timestamp = 2L.millisecondsToTimestamp())
+        val move1A2 = move1A1.moveTo(101L.millisecondsToTimestamp())
+        val down2 = down(id = 1, timestamp = 101L.millisecondsToTimestamp())
+        val move1A3 = move1A2.moveTo(102L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1A, down1B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move1A1, up2B)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move1A2, down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move1A3, up2)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_1down1Up2DownWithinTimeout1Up_onLongPressNotCalled() {
+        val down1 = down(id = 0, timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2A = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val down2B = down(1, timestamp = 100L.millisecondsToTimestamp())
+        val move2A = down2A.moveTo(timestamp = 101L.millisecondsToTimestamp())
+        val up2B = down2B.up(timestamp = 101L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2A, down2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move2A, up2B)
+
+        verify(onDoubleTap, never()).invoke(any())
+    }
+
+    // Tests that verify conditions under which onDoubleTap will be called.
+
+    @Test
+    fun pointerInputHandler_downUpDownInsideTimeoutUp_onLongPressCalled() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 101L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downMoveUpDownInsideTimeoutUp_onLongPressCalled() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val move = down1.moveTo(1L.millisecondsToTimestamp(), x = 1f)
+        val up1 = move.up(timestamp = 2L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownInsideTimeoutMoveUp_onLongPressCalled() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 10L.millisecondsToTimestamp())
+        val move = down2.moveTo(101L.millisecondsToTimestamp(), x = 1f)
+        val up2 = move.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_2Down1MoveUpDownInsideTimeoutUp_onLongPressCalled() {
+        val down1A = down(0, timestamp = 0L.millisecondsToTimestamp())
+        val down1B = down(1, timestamp = 0L.millisecondsToTimestamp())
+        val move1A = down1A.moveTo(1L.millisecondsToTimestamp(), x = 1f)
+        val move1B = down1B.moveTo(1L.millisecondsToTimestamp())
+        val up1A = move1A.up(timestamp = 2L.millisecondsToTimestamp())
+        val up1B = move1B.up(timestamp = 2L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1A, down1B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move1A, move1B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1A, up1B)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(any())
+    }
+
+    @Test
+    fun pointerInputHandler_downUp2DownInsideTimeout1MoveUp_onLongPressCalled() {
+        val down1 = down(timestamp = 0L.millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2A = down(0, timestamp = 100L.millisecondsToTimestamp())
+        val down2B = down(1, timestamp = 100L.millisecondsToTimestamp())
+        val move2A = down2A.moveTo(101L.millisecondsToTimestamp(), x = 1f)
+        val move2B = down2B.moveTo(101L.millisecondsToTimestamp())
+        val up2A = move2A.up(timestamp = 102L.millisecondsToTimestamp())
+        val up2B = move2B.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2A, down2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move2A, move2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2A, up2B)
+
+        verify(onDoubleTap).invoke(any())
+    }
+
+    // Tests that verify correctness of PxPosition value passed to onDoubleTap
+
+    @Test
+    fun pointerInputHandler_downUpDownUpAllAtOrigin_onDoubleTapCalledWithOrigin() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 101L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(PxPosition.Origin)
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownMoveUp_onDoubleTapCalledWithFinalMovePosition() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+        val move2 = down2.moveTo(101L.millisecondsToTimestamp(), 3f, 5f)
+        val up2 = move2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        verify(onDoubleTap).invoke(PxPosition(3.px, 5.px))
+    }
+
+    @Test
+    fun pointerInputHandler_downUp2Down2Move1UpThen1Up_onDoubleTapCalledWithFinalFingerPosition() {
+        val down1 = down(timestamp = (0L).millisecondsToTimestamp())
+        val up1 = down1.up(timestamp = 1L.millisecondsToTimestamp())
+        val down2A = down(id = 0, timestamp = 100L.millisecondsToTimestamp())
+        val down2B = down(id = 1, timestamp = 100L.millisecondsToTimestamp())
+        val move2A = down2A.moveTo(101L.millisecondsToTimestamp(), 3f, 5f)
+        val move2B1 = down2B.moveTo(101L.millisecondsToTimestamp(), -7f, -11f)
+        val up2A = move2A.up(timestamp = 102L.millisecondsToTimestamp())
+        val move2B2 = move2B1.moveTo(timestamp = 102L.millisecondsToTimestamp(), x = -7f, y = -11f)
+        val up2B = move2B2.up(timestamp = 103L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up1)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2A, down2B)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(move2A, move2B1)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2A, move2B2)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up2B)
+
+        verify(onDoubleTap).invoke(PxPosition((-7).px, (-11).px))
+    }
+
+    // Tests that verify that consumption behavior
+
+    @Test
+    fun pointerInputHandler_down_downNotConsumed() {
+        val down = down()
+        val result = mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        assertThat(result[0].consumed.downChange).isFalse()
+    }
+
+    @Test
+    fun pointerInputHandler_downUp_upNotConsumed() {
+        val down = down()
+        val up = down.up(1L.millisecondsToTimestamp())
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        val result = mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        assertThat(result[0].consumed.downChange).isFalse()
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownInsideTimeout_lastDownNotConsumed() {
+        val down = down()
+        val up = down.up(1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        val result = mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+
+        assertThat(result[0].consumed.downChange).isFalse()
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownOutsideTimeoutUp_lastUpNotConsumed() {
+        val down = down()
+        val up = down.up(1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 101L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 102L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        testContext.advanceTimeBy(100, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        val result = mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        assertThat(result[0].consumed.downChange).isFalse()
+    }
+
+    @Test
+    fun pointerInputHandler_downUpDownInsideTimeoutUp_lastUpConsumed() {
+        val down = down()
+        val up = down.up(1L.millisecondsToTimestamp())
+        val down2 = down(timestamp = 100L.millisecondsToTimestamp())
+        val up2 = down2.up(timestamp = 101L.millisecondsToTimestamp())
+
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(up)
+        testContext.advanceTimeBy(99, TimeUnit.MILLISECONDS)
+        mRecognizer.pointerInputHandler.invokeOverAllPasses(down2)
+        val result = mRecognizer.pointerInputHandler.invokeOverAllPasses(up2)
+
+        assertThat(result[0].consumed.downChange).isTrue()
+    }
+}
\ No newline at end of file
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 52c2f1c..568e0a2 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
@@ -227,7 +227,7 @@
 }
 
 @Composable
-fun SingleCompositionRow(@Children children: @Composable() () -> Unit) {
+fun SingleCompositionRow(children: @Composable() () -> Unit) {
     Layout(layoutBlock = { measurables, constraints ->
         val placeables = measurables.map {
             it.measure(constraints.copy(minWidth = 0.ipx, maxWidth = IntPx.Infinity))
@@ -246,7 +246,7 @@
 }
 
 @Composable
-fun SingleCompositionColumn(@Children children: @Composable() () -> Unit) {
+fun SingleCompositionColumn(children: @Composable() () -> Unit) {
     Layout(layoutBlock = { measurables, constraints ->
         val placeables = measurables.map {
             it.measure(constraints.copy(minHeight = 0.ipx, maxHeight = IntPx.Infinity))
@@ -306,7 +306,7 @@
 }
 
 @Composable
-fun SingleCompositionRowWithIntrinsics(@Children children: @Composable() () -> Unit) {
+fun SingleCompositionRowWithIntrinsics(children: @Composable() () -> Unit) {
     ComplexLayout(children = children, block = {
         layout { measurables, constraints ->
             val placeables = measurables.map { measurable ->
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 1b94f79..c42418b 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
@@ -53,7 +53,7 @@
     width: Dp? = null,
     height: Dp? = null,
     color: Color,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Wrap {
         DrawRectangle(color = color)
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/IntrinsicTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/IntrinsicTest.kt
index dd375d3..556d6b4 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/IntrinsicTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/IntrinsicTest.kt
@@ -500,7 +500,7 @@
     maxIntrinsicWidth: Dp,
     minIntrinsicHeight: Dp,
     height: Dp, maxIntrinsicHeight: Dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     ComplexLayout(children) {
         layout { _, constraints ->
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/LayoutTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/LayoutTest.kt
index 0042948..d8c6eb1 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/LayoutTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/LayoutTest.kt
@@ -70,7 +70,7 @@
         activityTestRule.runOnUiThread(runnable)
     }
 
-    internal fun show(@Children composable: @Composable() () -> Unit) {
+    internal fun show(composable: @Composable() () -> Unit) {
         val runnable: Runnable = object : Runnable {
             override fun run() {
                 activity.setContent(composable)
@@ -149,6 +149,7 @@
                             { w -> measurable.maxIntrinsicHeight(w) }
                         )
                         layoutLatch.countDown()
+                        layoutResult(0.ipx, 0.ipx) {}
                     }
                     minIntrinsicWidth { _, _ -> 0.ipx }
                     maxIntrinsicWidth { _, _ -> 0.ipx }
diff --git a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
index f38837a..deca623 100644
--- a/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
+++ b/ui/ui-layout/src/androidTest/java/androidx/ui/layout/test/OnPositionedTest.kt
@@ -17,6 +17,7 @@
 package androidx.ui.layout.test
 
 import android.widget.FrameLayout
+import androidx.compose.Model
 import androidx.test.filters.SmallTest
 import androidx.compose.composer
 import androidx.ui.core.LayoutCoordinates
@@ -192,4 +193,31 @@
         assertThat(realGlobalPosition).isEqualTo(globalPosition)
         assertThat(realLocalPosition).isEqualTo(localPosition)
     }
+
+    @Test
+    fun justAddedOnPositionedCallbackFiredWithoutLayoutChanges() = withDensity(density) {
+        val needCallback = NeedCallback(false)
+
+        val callbackLatch = CountDownLatch(1)
+        show {
+            Container(expanded = true) {
+                if (needCallback.value) {
+                    OnPositioned(onPositioned = {
+                        callbackLatch.countDown()
+                    })
+                }
+            }
+        }
+
+        activityTestRule.runOnUiThread(object : Runnable {
+            override fun run() {
+                needCallback.value = true
+            }
+        })
+
+        assertThat(callbackLatch.await(1000, TimeUnit.SECONDS)).isEqualTo(true)
+    }
 }
+
+@Model
+private data class NeedCallback(var value: Boolean)
\ No newline at end of file
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Align.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Align.kt
index 07144eb..888706f 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Align.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Align.kt
@@ -69,7 +69,7 @@
  * For a widget that does alignment and tries to be the same size as its child, see [Wrap].
  */
 @Composable
-fun Align(alignment: Alignment, @Children children: @Composable() () -> Unit) {
+fun Align(alignment: Alignment, children: @Composable() () -> Unit) {
     Layout(layoutBlock = { measurables, constraints ->
         val measurable = measurables.firstOrNull()
         // The child cannot be larger than our max constraints, but we ignore min constraints.
@@ -112,6 +112,6 @@
  * }
  */
 @Composable
-fun Center(@Children children: @Composable() () -> Unit) {
+fun Center(children: @Composable() () -> Unit) {
     Align(alignment = Alignment.Center, children = children)
 }
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/AspectRatio.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/AspectRatio.kt
index 8117ad6..2856b4b 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/AspectRatio.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/AspectRatio.kt
@@ -51,7 +51,7 @@
 @Composable
 fun AspectRatio(
     aspectRatio: Float,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Layout(children) { measurables, constraints ->
         val size = listOf(
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/ConstrainedBox.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/ConstrainedBox.kt
index e30c9b3..7ad2633 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/ConstrainedBox.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/ConstrainedBox.kt
@@ -38,7 +38,7 @@
 @Composable
 fun ConstrainedBox(
     constraints: DpConstraints,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     ComplexLayout(children) {
         layout { measurables, incomingConstraints ->
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Container.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Container.kt
index 9027e93..dc48a4b 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Container.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Container.kt
@@ -61,7 +61,7 @@
     constraints: DpConstraints = DpConstraints(),
     width: Dp? = null,
     height: Dp? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     trace("UI:Container") {
         Layout(children = children, layoutBlock = { measurables, incomingConstraints ->
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 4860313..21a9a37 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
@@ -178,7 +178,7 @@
     mainAxisSize: FlexSize = FlexSize.Max,
     crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Center,
     crossAxisSize: FlexSize = FlexSize.Min,
-    @Children block: @Composable() () -> Unit
+    block: @Composable() () -> Unit
 ) {
     FlexRow(
         mainAxisAlignment = mainAxisAlignment,
@@ -214,7 +214,7 @@
     mainAxisSize: FlexSize = FlexSize.Max,
     crossAxisAlignment: CrossAxisAlignment = CrossAxisAlignment.Center,
     crossAxisSize: FlexSize = FlexSize.Min,
-    @Children block: @Composable() () -> Unit
+    block: @Composable() () -> Unit
 ) {
     FlexColumn(
         mainAxisAlignment = mainAxisAlignment,
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Intrinsic.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Intrinsic.kt
index 58b8205..3bd2915 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Intrinsic.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Intrinsic.kt
@@ -42,7 +42,7 @@
  * the [ConstrainedBox]s to use the same width.
  */
 @Composable
-fun MinIntrinsicWidth(@Children children: @Composable() () -> Unit) {
+fun MinIntrinsicWidth(children: @Composable() () -> Unit) {
     ComplexLayout(children) {
         layout { measurables, constraints ->
             val measurable = measurables.firstOrNull()
@@ -87,7 +87,7 @@
  * the divider to use the same height.
  */
 @Composable
-fun MinIntrinsicHeight(@Children children: @Composable() () -> Unit) {
+fun MinIntrinsicHeight(children: @Composable() () -> Unit) {
     ComplexLayout(children) {
         layout { measurables, constraints ->
             val measurable = measurables.firstOrNull()
@@ -132,7 +132,7 @@
  * The sample is a layout containing three widgets having the same width as the widest one.
  */
 @Composable
-fun MaxIntrinsicWidth(@Children children: @Composable() () -> Unit) {
+fun MaxIntrinsicWidth(children: @Composable() () -> Unit) {
     ComplexLayout(children) {
         layout { measurables, constraints ->
             val measurable = measurables.firstOrNull()
@@ -177,7 +177,7 @@
  * and the divider to use the same height.
  */
 @Composable
-fun MaxIntrinsicHeight(@Children children: @Composable() () -> Unit) {
+fun MaxIntrinsicHeight(children: @Composable() () -> Unit) {
     ComplexLayout(children) {
         layout { measurables, constraints ->
             val measurable = measurables.firstOrNull()
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Padding.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Padding.kt
index 8e8bbe45..79225a6 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Padding.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Padding.kt
@@ -53,7 +53,7 @@
 @Composable
 fun Padding(
     padding: EdgeInsets,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Layout(layoutBlock = { measurables, constraints ->
         val measurable = measurables.firstOrNull()
@@ -98,7 +98,7 @@
     top: Dp = 0.dp,
     right: Dp = 0.dp,
     bottom: Dp = 0.dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Padding(
         padding = EdgeInsets(left = left, top = top, right = right, bottom = bottom),
@@ -121,7 +121,7 @@
 @Composable
 fun Padding(
     padding: Dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Padding(padding = EdgeInsets(padding), children = children)
 }
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Scroller.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Scroller.kt
index 69bfe04..677be31 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Scroller.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Scroller.kt
@@ -52,7 +52,7 @@
 private fun VerticalDragGestureDetector(
     max: Px = Px.Infinity,
     offsetChange: (Px) -> Unit,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val offset = +state { 0.px }
     DragGestureDetector(
@@ -105,7 +105,7 @@
     onScrollChanged: (position: Px, maxPosition: Px) -> Unit = { position, _ ->
         scrollerPosition.position = position
     },
-    @Children child: @Composable() () -> Unit
+    child: @Composable() () -> Unit
 ) {
     val maxPosition = +state { 0.px }
     Layout(children = {
diff --git a/ui/ui-layout/src/main/java/androidx/ui/layout/Wrap.kt b/ui/ui-layout/src/main/java/androidx/ui/layout/Wrap.kt
index 5a08cf8..3846114 100644
--- a/ui/ui-layout/src/main/java/androidx/ui/layout/Wrap.kt
+++ b/ui/ui-layout/src/main/java/androidx/ui/layout/Wrap.kt
@@ -35,7 +35,7 @@
  * For a widget that does alignment and tries to be as large as possible, see [Align].
  */
 @Composable
-fun Wrap(alignment: Alignment = Alignment.TopLeft, @Children children: @Composable() () -> Unit) {
+fun Wrap(alignment: Alignment = Alignment.TopLeft, children: @Composable() () -> Unit) {
     Layout(layoutBlock = { measurables, constraints ->
         val measurable = measurables.firstOrNull()
         // The child cannot be larger than our max constraints, but we ignore min constraints.
diff --git a/ui/ui-material/build.gradle b/ui/ui-material/build.gradle
index 0392547..a6cacda 100644
--- a/ui/ui-material/build.gradle
+++ b/ui/ui-material/build.gradle
@@ -42,6 +42,7 @@
     implementation project(":ui:ui-text")
     implementation project(":ui:ui-animation")
     implementation project(":ui:ui-foundation")
+    implementation project(":ui:ui-vector")
 
     testImplementation(ANDROIDX_TEST_RULES)
     testImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/MissingMaterialComponents.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/MissingMaterialComponents.kt
index bc83b65..ff66edf 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/MissingMaterialComponents.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/MissingMaterialComponents.kt
@@ -31,7 +31,7 @@
  */
 
 @Composable
-fun Scaffold(appBar: @Composable() () -> Unit, @Children children: @Composable() () -> Unit) {
+fun Scaffold(appBar: @Composable() () -> Unit, children: @Composable() () -> Unit) {
     FlexColumn {
         inflexible {
             appBar()
diff --git a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyTheme.kt b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyTheme.kt
index e80124f..f1d3435 100644
--- a/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyTheme.kt
+++ b/ui/ui-material/integration-tests/material-studies/src/main/java/androidx/ui/material/studies/rally/RallyTheme.kt
@@ -36,7 +36,7 @@
 val rallyBlue = Color(0xFF72DEFF.toInt())
 
 @Composable
-fun RallyTheme(@Children children: @Composable() () -> Unit) {
+fun RallyTheme(children: @Composable() () -> Unit) {
     val colors = MaterialColors(
         primary = rallyGreen,
         surface = Color(0xFF26282F.toInt()),
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
index d43cd7a..67f7537 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/RadioGroupUiTest.kt
@@ -63,7 +63,7 @@
     private val options = listOf(itemOne, itemTwo, itemThree)
 
     @Composable
-    fun VerticalRadioGroupforTests(@Children children: @Composable() RadioGroupScope.() -> Unit) {
+    fun VerticalRadioGroupforTests(children: @Composable() RadioGroupScope.() -> Unit) {
         RadioGroup {
             Column {
                 children(p1 = this)
diff --git a/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt b/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
index d7707a2..173bb9f 100644
--- a/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
+++ b/ui/ui-material/src/androidTest/java/androidx/ui/material/RippleEffectTest.kt
@@ -192,7 +192,7 @@
     private fun RippleCallback(
         onRippleDrawn: (Matrix4) -> Unit = {},
         onDispose: () -> Unit = {},
-        @Children children: @Composable() () -> Unit
+        children: @Composable() () -> Unit
     ) {
         val theme = RippleTheme(testRippleEffect(onRippleDrawn, onDispose)) { Color(0) }
         CurrentRippleTheme.Provider(value = theme, children = children)
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/Button.kt b/ui/ui-material/src/main/java/androidx/ui/material/Button.kt
index 9ece28d..5137a35 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/Button.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/Button.kt
@@ -74,7 +74,7 @@
     color: Color = +themeColor { primary },
     border: Border? = null,
     elevation: Dp = 0.dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val textStyle = +themeTextStyle { button }
     Surface(shape = shape, color = color, border = border, elevation = elevation) {
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/FloatingActionButton.kt b/ui/ui-material/src/main/java/androidx/ui/material/FloatingActionButton.kt
index 3ce7acf..019eb31 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/FloatingActionButton.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/FloatingActionButton.kt
@@ -64,7 +64,7 @@
     shape: Shape = CircleShape,
     color: Color = +themeColor { primary },
     elevation: Dp = 0.dp, // TODO(Andrey) add the default elevation when it ready b/123215187
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Button(color = color, onClick = onClick, shape = shape, elevation = elevation) {
         Container(constraints = DpConstraints(minWidth = minSize, minHeight = minSize)) {
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/MaterialTheme.kt b/ui/ui-material/src/main/java/androidx/ui/material/MaterialTheme.kt
index 296208b..76ce952 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/MaterialTheme.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/MaterialTheme.kt
@@ -57,7 +57,6 @@
 fun MaterialTheme(
     colors: MaterialColors = MaterialColors(),
     typography: MaterialTypography = MaterialTypography(),
-    @Children
     children: @Composable() () -> Unit
 ) {
     Colors.Provider(value = colors) {
@@ -222,7 +221,7 @@
  * guidelines for descendants
  */
 @Composable
-fun MaterialRippleTheme(@Children children: @Composable() () -> Unit) {
+fun MaterialRippleTheme(children: @Composable() () -> Unit) {
     val materialColors = +ambient(Colors)
     val defaultTheme = +memo {
         RippleTheme(
@@ -287,7 +286,7 @@
  * Applies the default [Shape]s for all the surfaces.
  */
 @Composable
-fun MaterialButtonShapeTheme(@Children children: @Composable() () -> Unit) {
+fun MaterialButtonShapeTheme(children: @Composable() () -> Unit) {
     val value = +withDensity {
         Shapes(
             button = RoundedCornerShape(CornerSizes(4.dp))
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/ProgressIndicator.kt b/ui/ui-material/src/main/java/androidx/ui/material/ProgressIndicator.kt
index a8485a0..e2da5bc 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/ProgressIndicator.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/ProgressIndicator.kt
@@ -282,7 +282,7 @@
 }
 
 @Composable
-private fun CircularIndicatorContainer(@Children children: @Composable() () -> Unit) {
+private fun CircularIndicatorContainer(children: @Composable() () -> Unit) {
     Wrap {
         Padding(CircularIndicatorPadding) {
             Container(width = CircularIndicatorDiameter, height = CircularIndicatorDiameter) {
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/RadioButton.kt b/ui/ui-material/src/main/java/androidx/ui/material/RadioButton.kt
index c3bbe64..ae0f300 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/RadioButton.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/RadioButton.kt
@@ -76,7 +76,7 @@
  *         onOptionSelected = { ... })
  */
 @Composable
-fun RadioGroup(@Children children: @Composable RadioGroupScope.() -> Unit) {
+fun RadioGroup(children: @Composable RadioGroupScope.() -> Unit) {
     val scope = +memo { RadioGroupScope() }
     children(p1 = scope)
 }
@@ -142,7 +142,7 @@
     fun RadioGroupItem(
         selected: Boolean,
         onSelect: () -> Unit,
-        @Children children: @Composable() () -> Unit
+        children: @Composable() () -> Unit
     ) {
         Container {
             Ripple(bounded = true) {
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/ripple/Ripple.kt b/ui/ui-material/src/main/java/androidx/ui/material/ripple/Ripple.kt
index 139a554..382e2ab 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/ripple/Ripple.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/ripple/Ripple.kt
@@ -60,7 +60,7 @@
 fun Ripple(
     bounded: Boolean,
     radius: Dp? = null,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val density = +ambientDensity()
     val rippleSurface = +ambientRippleSurface()
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/ripple/RippleSurface.kt b/ui/ui-material/src/main/java/androidx/ui/material/ripple/RippleSurface.kt
index 48d547f..aa0dd8c 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/ripple/RippleSurface.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/ripple/RippleSurface.kt
@@ -87,7 +87,7 @@
 @Composable
 fun RippleSurface(
     color: Color?,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     val owner = +memo { RippleSurfaceOwnerImpl() }
     owner.backgroundColor = color
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/surface/Card.kt b/ui/ui-material/src/main/java/androidx/ui/material/surface/Card.kt
index 52f1f13f..544666b 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/surface/Card.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/surface/Card.kt
@@ -49,7 +49,7 @@
     color: Color = +themeColor { surface },
     border: Border? = null,
     elevation: Dp = 0.dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     // TODO(Andrey: This currently adds no logic on top of Surface, I just reserve the name
     // for now. We will see what will be the additional Card specific logic later.
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/surface/Surface.kt b/ui/ui-material/src/main/java/androidx/ui/material/surface/Surface.kt
index 0981820..8a75fb3 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/surface/Surface.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/surface/Surface.kt
@@ -84,7 +84,7 @@
     color: Color = +themeColor { surface },
     border: Border? = null,
     elevation: Dp = 0.dp,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     SurfaceLayout {
         DrawShadow(shape = shape, elevation = elevation)
@@ -110,7 +110,7 @@
  * TODO("Andrey: Should be replaced with some basic layout implementation when we have it")
  */
 @Composable
-private fun SurfaceLayout(@Children children: @Composable() () -> Unit) {
+private fun SurfaceLayout(children: @Composable() () -> Unit) {
     Layout(children = children, layoutBlock = { measurables, constraints ->
         if (measurables.size > 1) {
             throw IllegalStateException("Surface can have only one direct measurable child!")
diff --git a/ui/ui-material/src/main/java/androidx/ui/material/surface/TransparentSurface.kt b/ui/ui-material/src/main/java/androidx/ui/material/surface/TransparentSurface.kt
index 29aea48..f68b95c 100644
--- a/ui/ui-material/src/main/java/androidx/ui/material/surface/TransparentSurface.kt
+++ b/ui/ui-material/src/main/java/androidx/ui/material/surface/TransparentSurface.kt
@@ -38,7 +38,7 @@
 @Composable
 fun TransparentSurface(
     shape: Shape = RectangleShape,
-    @Children children: @Composable() () -> Unit
+    children: @Composable() () -> Unit
 ) {
     Surface(shape = shape, children = children, color = Color.Transparent)
 }
diff --git a/ui/ui-platform/build.gradle b/ui/ui-platform/build.gradle
index b6a9b9a..651fc72 100644
--- a/ui/ui-platform/build.gradle
+++ b/ui/ui-platform/build.gradle
@@ -54,6 +54,8 @@
     androidTestImplementation MOCKITO_KOTLIN, {
         exclude group: 'org.mockito' // to keep control on the mockito version
     }
+
+    implementation "androidx.core:core:1.0.0"
 }
 
 androidx {
diff --git a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
index 1bdfbc3..bd000ca 100644
--- a/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
+++ b/ui/ui-platform/src/main/java/androidx/ui/core/ComponentNodes.kt
@@ -777,7 +777,12 @@
  * @property key The key object used to identify the key
  * @property value The value of the data being stored in the hierarchy
  */
-class DataNode<T>(val key: DataNodeKey<T>, var value: T) : ComponentNode()
+class DataNode<T>(val key: DataNodeKey<T>, var value: T) : ComponentNode() {
+    override fun attach(owner: Owner) {
+        super.attach(owner)
+        parentLayoutNode?.requestRemeasure()
+    }
+}
 
 /**
  * Returns [ComponentNode.owner] or throws if it is null.
diff --git a/ui/ui-text/api/1.0.0-alpha01.txt b/ui/ui-text/api/1.0.0-alpha01.txt
index a6e76c9..a37b2f2 100644
--- a/ui/ui-text/api/1.0.0-alpha01.txt
+++ b/ui/ui-text/api/1.0.0-alpha01.txt
@@ -38,10 +38,12 @@
 package androidx.ui.text {
 
   public final class AnnotatedString {
-    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
     method public String component1();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> component2();
-    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> component3();
+    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> getParagraphStyles();
     method public String getText();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> getTextStyles();
   }
@@ -76,6 +78,10 @@
     method public String _canonicalizeRegionCode(String regionCode);
   }
 
+  public final class MultiParagraphKt {
+    ctor public MultiParagraphKt();
+  }
+
   public interface Paragraph {
     method public float getBaseline();
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
@@ -127,6 +133,7 @@
     method public androidx.ui.text.style.TextAlign? getTextAlign();
     method public androidx.ui.text.style.TextDirection? getTextDirection();
     method public androidx.ui.text.style.TextIndent? getTextIndent();
+    method public androidx.ui.text.ParagraphStyle merge(androidx.ui.text.ParagraphStyle? other = null);
   }
 
   public final class TextPainter {
diff --git a/ui/ui-text/api/current.txt b/ui/ui-text/api/current.txt
index a6e76c9..a37b2f2 100644
--- a/ui/ui-text/api/current.txt
+++ b/ui/ui-text/api/current.txt
@@ -38,10 +38,12 @@
 package androidx.ui.text {
 
   public final class AnnotatedString {
-    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
     method public String component1();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> component2();
-    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> component3();
+    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> getParagraphStyles();
     method public String getText();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> getTextStyles();
   }
@@ -76,6 +78,10 @@
     method public String _canonicalizeRegionCode(String regionCode);
   }
 
+  public final class MultiParagraphKt {
+    ctor public MultiParagraphKt();
+  }
+
   public interface Paragraph {
     method public float getBaseline();
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
@@ -127,6 +133,7 @@
     method public androidx.ui.text.style.TextAlign? getTextAlign();
     method public androidx.ui.text.style.TextDirection? getTextDirection();
     method public androidx.ui.text.style.TextIndent? getTextIndent();
+    method public androidx.ui.text.ParagraphStyle merge(androidx.ui.text.ParagraphStyle? other = null);
   }
 
   public final class TextPainter {
diff --git a/ui/ui-text/api/restricted_1.0.0-alpha01.txt b/ui/ui-text/api/restricted_1.0.0-alpha01.txt
index 1b16ca0..d02f68726 100644
--- a/ui/ui-text/api/restricted_1.0.0-alpha01.txt
+++ b/ui/ui-text/api/restricted_1.0.0-alpha01.txt
@@ -52,10 +52,12 @@
 package androidx.ui.text {
 
   public final class AnnotatedString {
-    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
     method public String component1();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> component2();
-    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> component3();
+    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> getParagraphStyles();
     method public String getText();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> getTextStyles();
   }
@@ -90,6 +92,10 @@
     method public String _canonicalizeRegionCode(String regionCode);
   }
 
+  public final class MultiParagraphKt {
+    ctor public MultiParagraphKt();
+  }
+
   public interface Paragraph {
     method public float getBaseline();
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
@@ -141,6 +147,7 @@
     method public androidx.ui.text.style.TextAlign? getTextAlign();
     method public androidx.ui.text.style.TextDirection? getTextDirection();
     method public androidx.ui.text.style.TextIndent? getTextIndent();
+    method public androidx.ui.text.ParagraphStyle merge(androidx.ui.text.ParagraphStyle? other = null);
   }
 
   public final class TextPainter {
diff --git a/ui/ui-text/api/restricted_current.txt b/ui/ui-text/api/restricted_current.txt
index 1b16ca0..d02f68726 100644
--- a/ui/ui-text/api/restricted_current.txt
+++ b/ui/ui-text/api/restricted_current.txt
@@ -52,10 +52,12 @@
 package androidx.ui.text {
 
   public final class AnnotatedString {
-    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    ctor public AnnotatedString(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
     method public String component1();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> component2();
-    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> component3();
+    method public androidx.ui.text.AnnotatedString copy(String text, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> textStyles, java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> paragraphStyles);
+    method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.ParagraphStyle>> getParagraphStyles();
     method public String getText();
     method public java.util.List<androidx.ui.text.AnnotatedString.Item<androidx.ui.text.TextStyle>> getTextStyles();
   }
@@ -90,6 +92,10 @@
     method public String _canonicalizeRegionCode(String regionCode);
   }
 
+  public final class MultiParagraphKt {
+    ctor public MultiParagraphKt();
+  }
+
   public interface Paragraph {
     method public float getBaseline();
     method public androidx.ui.engine.geometry.Rect getCursorRect(int offset);
@@ -141,6 +147,7 @@
     method public androidx.ui.text.style.TextAlign? getTextAlign();
     method public androidx.ui.text.style.TextDirection? getTextDirection();
     method public androidx.ui.text.style.TextIndent? getTextIndent();
+    method public androidx.ui.text.ParagraphStyle merge(androidx.ui.text.ParagraphStyle? other = null);
   }
 
   public final class TextPainter {
diff --git a/ui/ui-text/build.gradle b/ui/ui-text/build.gradle
index feccef84..9772691 100644
--- a/ui/ui-text/build.gradle
+++ b/ui/ui-text/build.gradle
@@ -40,6 +40,7 @@
     implementation project(":compose:compose-runtime")
     implementation project(":ui:ui-android-text")
     implementation project(":ui:ui-core")
+    implementation project(":ui:ui-vector")
 
     testImplementation(ANDROIDX_TEST_RULES)
     testImplementation(ANDROIDX_TEST_RUNNER)
diff --git a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
index faaf76d..a0e9bda 100644
--- a/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
+++ b/ui/ui-text/integration-tests/text-demos/src/main/java/androidx/ui/text/demos/CraneText.kt
@@ -47,6 +47,8 @@
 import androidx.ui.text.style.TextOverflow
 import androidx.ui.core.Sp
 import androidx.ui.core.sp
+import androidx.ui.text.AnnotatedString
+import androidx.ui.text.style.TextIndent
 
 val displayText = "Text Demo"
 val displayTextChinese = "文本演示"
@@ -99,6 +101,16 @@
             TextDemoComposableTextSpan()
             TagLine(tag = "fontSizeScale")
             TextDemoFontSizeScale()
+            TagLine(tag = "multiple paragraphs basic")
+            TextDemoParagraph()
+            TagLine(tag = "multiple paragraphs TextAlign")
+            TextDemoParagraphTextAlign()
+            TagLine(tag = "multiple paragraphs line height")
+            TextDemoParagraphLineHeight()
+            TagLine(tag = "multiple paragraphs TextIndent")
+            TextDemoParagraphIndent()
+            TagLine(tag = "multiple paragraphs TextDirection")
+            TextDemoParagraphTextDirection()
         }
     }
 }
@@ -685,3 +697,131 @@
         }
     }
 }
+
+@Composable
+fun TextDemoParagraph() {
+    val text1 = "paragraph1 paragraph1 paragraph1 paragraph1 paragraph1"
+    val text2 = "paragraph2 paragraph2 paragraph2 paragraph2 paragraph2"
+    Text(
+        text = AnnotatedString(
+            text = text1 + text2,
+            textStyles = listOf(),
+            paragraphStyles = listOf(
+                AnnotatedString.Item(ParagraphStyle(), text1.length, text1.length)
+            )
+        ),
+        style = TextStyle(fontSize = fontSize8)
+    )
+}
+
+@Composable
+fun TextDemoParagraphTextAlign() {
+    var text = ""
+    val paragraphStyles = mutableListOf<AnnotatedString.Item<ParagraphStyle>>()
+    TextAlign.values().map { textAlign ->
+        val str = List(4) { "TextAlign.$textAlign" }.joinToString(" ")
+        val paragraphStyle = ParagraphStyle(textAlign = textAlign)
+        Pair(str, paragraphStyle)
+    }.forEach { (str, paragraphStyle) ->
+        paragraphStyles.add(
+            AnnotatedString.Item(
+                paragraphStyle,
+                text.length,
+                text.length + str.length
+            )
+        )
+        text += str
+    }
+
+    Text(
+        text = AnnotatedString(
+            text = text,
+            textStyles = listOf(),
+            paragraphStyles = paragraphStyles
+        ),
+        style = TextStyle(fontSize = fontSize8)
+    )
+}
+
+@Composable
+fun TextDemoParagraphLineHeight() {
+    val text1 = "LineHeight=1.0f LineHeight=1.0f LineHeight=1.0f LineHeight=1.0f"
+    val text2 = "LineHeight=1.5f LineHeight=1.5f LineHeight=1.5f LineHeight=1.5f"
+    val text3 = "LineHeight=3.0f LineHeight=3.0f LineHeight=3.0f LineHeight=3.0f"
+
+    Text(
+        text = AnnotatedString(
+            text = text1 + text2 + text3,
+            textStyles = listOf(),
+            paragraphStyles = listOf(
+                AnnotatedString.Item(
+                    ParagraphStyle(lineHeight = 1.0f),
+                    0,
+                    text1.length
+                ),
+                AnnotatedString.Item(
+                    ParagraphStyle(lineHeight = 1.5f),
+                    text1.length,
+                    text1.length + text2.length
+                ),
+                AnnotatedString.Item(
+                    ParagraphStyle(lineHeight = 2f),
+                    text1.length + text2.length,
+                    text1.length + text2.length + text3.length
+                )
+            )
+        ),
+        style = TextStyle(fontSize = fontSize8)
+    )
+}
+
+@Composable
+fun TextDemoParagraphIndent() {
+    val text1 = "TextIndent firstLine TextIndent firstLine TextIndent firstLine"
+    val text2 = "TextIndent restLine TextIndent restLine TextIndent restLine"
+
+    Text(
+        text = AnnotatedString(
+            text = text1 + text2,
+            textStyles = listOf(),
+            paragraphStyles = listOf(
+                AnnotatedString.Item(
+                    ParagraphStyle(textIndent = TextIndent(firstLine = 100.px)),
+                    0,
+                    text1.length
+                ),
+                AnnotatedString.Item(
+                    ParagraphStyle(textIndent = TextIndent(restLine = 100.px)),
+                    text1.length,
+                    text1.length + text2.length
+                )
+            )
+        ),
+        style = TextStyle(fontSize = fontSize8)
+    )
+}
+
+@Composable
+fun TextDemoParagraphTextDirection() {
+    val ltrText = "Hello World! Hello World! Hello World! Hello World! Hello World!"
+    val rtlText = "مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم مرحبا بالعالم"
+    Text(
+        text = AnnotatedString(
+            text = ltrText + rtlText,
+            textStyles = listOf(),
+            paragraphStyles = listOf(
+                AnnotatedString.Item(
+                    ParagraphStyle(textDirection = TextDirection.Ltr),
+                    0,
+                    ltrText.length
+                ),
+                AnnotatedString.Item(
+                    ParagraphStyle(textDirection = TextDirection.Rtl),
+                    ltrText.length,
+                    ltrText.length + rtlText.length
+                )
+            )
+        ),
+        style = TextStyle(fontSize = fontSize8)
+    )
+}
\ No newline at end of file
diff --git a/ui/ui-text/src/androidTest/java/androidx/ui/text/MultiParagraphIntegrationTest.kt b/ui/ui-text/src/androidTest/java/androidx/ui/text/MultiParagraphIntegrationTest.kt
new file mode 100644
index 0000000..75c21b6
--- /dev/null
+++ b/ui/ui-text/src/androidTest/java/androidx/ui/text/MultiParagraphIntegrationTest.kt
@@ -0,0 +1,1925 @@
+/*
+ * 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.text
+
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import androidx.test.filters.Suppress
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.ui.core.Density
+import androidx.ui.core.PxPosition
+import androidx.ui.core.Sp
+import androidx.ui.core.px
+import androidx.ui.core.sp
+import androidx.ui.core.withDensity
+import androidx.ui.engine.geometry.Rect
+import androidx.ui.text.style.TextDirection
+import androidx.ui.text.FontTestData.Companion.BASIC_MEASURE_FONT
+import androidx.ui.text.font.FontFamily
+import androidx.ui.text.font.asFontFamily
+import androidx.ui.painting.Path
+import androidx.ui.painting.PathOperation
+import androidx.ui.text.style.TextAlign
+import androidx.ui.text.style.TextIndent
+import com.nhaarman.mockitokotlin2.mock
+import org.hamcrest.Matchers.equalTo
+import org.junit.Assert.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+@SmallTest
+class MultiParagraphIntegrationTest {
+    private val fontFamilyMeasureFont = BASIC_MEASURE_FONT.asFontFamily()
+    private val context = InstrumentationRegistry.getInstrumentation().context
+    private val defaultDensity = Density(density = 1f)
+    private val cursorWidth = 4f
+
+    @Test
+    fun empty_string() {
+        withDensity(defaultDensity) {
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val text = ""
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = 100.0f))
+
+            assertThat(paragraph.width, equalTo(100.0f))
+
+            assertThat(paragraph.height, equalTo(fontSizeInPx))
+            // defined in sample_font
+            assertThat(paragraph.baseline, equalTo(fontSizeInPx * 0.8f))
+            assertThat(paragraph.maxIntrinsicWidth, equalTo(0.0f))
+            assertThat(paragraph.minIntrinsicWidth, equalTo(0.0f))
+            // TODO(Migration/siyamed): no baseline query per line?
+            // TODO(Migration/siyamed): no line count?
+        }
+    }
+
+    @Test
+    fun single_line_default_values() {
+        withDensity(defaultDensity) {
+            val fontSize = 50.sp
+            val fontSizeInpx = fontSize.toPx().value
+
+            for (text in arrayOf("xyz", "\u05D0\u05D1\u05D2")) {
+                val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+                // width greater than text width - 150
+                paragraph.layout(ParagraphConstraints(width = 200.0f))
+
+                assertThat(text, paragraph.width, equalTo(200.0f))
+                assertThat(text, paragraph.height, equalTo(fontSizeInpx))
+                // defined in sample_font
+                assertThat(text, paragraph.baseline, equalTo(fontSizeInpx * 0.8f))
+                assertThat(
+                    text,
+                    paragraph.maxIntrinsicWidth,
+                    equalTo(fontSizeInpx * text.length)
+                )
+                assertThat(text, paragraph.minIntrinsicWidth, equalTo(0.0f))
+            }
+        }
+    }
+
+    @Test
+    fun line_break_default_values() {
+        withDensity(defaultDensity) {
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+
+            for (text in arrayOf("abcdef", "\u05D0\u05D1\u05D2\u05D3\u05D4\u05D5")) {
+                val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+                // 3 chars width
+                paragraph.layout(ParagraphConstraints(width = 3 * fontSizeInPx))
+
+                // 3 chars
+                assertThat(text, paragraph.width, equalTo(3 * fontSizeInPx))
+                // 2 lines, 1 line gap
+                assertThat(
+                    text,
+                    paragraph.height,
+                    equalTo(2 * fontSizeInPx + fontSizeInPx / 5.0f)
+                )
+                // defined in sample_font
+                assertThat(text, paragraph.baseline, equalTo(fontSizeInPx * 0.8f))
+                assertThat(
+                    text,
+                    paragraph.maxIntrinsicWidth,
+                    equalTo(fontSizeInPx * text.length)
+                )
+                assertThat(text, paragraph.minIntrinsicWidth, equalTo(0.0f))
+            }
+        }
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesSmallerThanTextLines_returnsTrue() {
+        val text = "aaa\naa"
+        val maxLines = text.lines().size - 1
+        val paragraph = simpleMultiParagraph(text = text, maxLines = maxLines)
+
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+        assertThat(paragraph.didExceedMaxLines, equalTo(true))
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesEqualToTextLines_returnsFalse() {
+        val text = "aaa\naa"
+        val maxLines = text.lines().size
+        val paragraph = simpleMultiParagraph(text = text, maxLines = maxLines)
+
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+        assertThat(paragraph.didExceedMaxLines, equalTo(false))
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesGreaterThanTextLines_returnsFalse() {
+        val text = "aaa\naa"
+        val maxLines = text.lines().size + 1
+        val paragraph = simpleMultiParagraph(text = text, maxLines = maxLines)
+
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+        assertThat(paragraph.didExceedMaxLines, equalTo(false))
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesSmallerThanTextLines_withLineWrap_returnsTrue() {
+        withDensity(defaultDensity) {
+            val text = "aa"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val maxLines = 1
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                maxLines = maxLines
+            )
+
+            // One line can only contain 1 character
+            paragraph.layout(ParagraphConstraints(width = fontSizeInPx))
+            assertThat(paragraph.didExceedMaxLines, equalTo(true))
+        }
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesEqualToTextLines_withLineWrap_returnsFalse() {
+        val text = "a"
+        val maxLines = text.lines().size
+        val paragraph = simpleMultiParagraph(text = text, fontSize = 50.sp, maxLines = maxLines)
+
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+        assertThat(paragraph.didExceedMaxLines, equalTo(false))
+    }
+
+    @Test
+    fun didExceedMaxLines_withMaxLinesGreaterThanTextLines_withLineWrap_returnsFalse() {
+        withDensity(defaultDensity) {
+            val text = "aa"
+            val maxLines = 3
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                maxLines = maxLines
+            )
+
+            // One line can only contain 1 character
+            paragraph.layout(ParagraphConstraints(width = fontSizeInPx))
+            assertThat(paragraph.didExceedMaxLines, equalTo(false))
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_ltr() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+            // test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars 0, 1, 2 ...
+            for (i in 0..text.length) {
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx / 2).px)
+                val offset = paragraph.getOffsetForPosition(position)
+                assertThat(
+                    "offset at index $i, position $position does not match",
+                    offset,
+                    equalTo(i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_rtl() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            // test positions that are 1, fontSize+1, 2fontSize+1 which maps to chars .., 2, 1, 0
+            for (i in 0..text.length) {
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx / 2).px)
+                val offset = paragraph.getOffsetForPosition(position)
+                assertThat(
+                    "offset at index $i, position $position does not match",
+                    offset,
+                    equalTo(text.length - i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_ltr_multiline() {
+        withDensity(defaultDensity) {
+            val firstLine = "abc"
+            val secondLine = "def"
+            val text = firstLine + secondLine
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = firstLine.length * fontSizeInPx))
+
+            // test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
+            // which maps to chars 3, 4, 5
+            for (i in 0..secondLine.length) {
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx * 1.5f).px)
+                val offset = paragraph.getOffsetForPosition(position)
+                assertThat(
+                    "offset at index $i, position $position, second line does not match",
+                    offset,
+                    equalTo(i + firstLine.length)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_rtl_multiline() {
+        withDensity(defaultDensity) {
+            val firstLine = "\u05D0\u05D1\u05D2"
+            val secondLine = "\u05D3\u05D4\u05D5"
+            val text = firstLine + secondLine
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = firstLine.length * fontSizeInPx))
+
+            // test positions are 1, fontSize+1, 2fontSize+1 and always on the second line
+            // which maps to chars 5, 4, 3
+            for (i in 0..secondLine.length) {
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx * 1.5f).px)
+                val offset = paragraph.getOffsetForPosition(position)
+                assertThat(
+                    "offset at index $i, position $position, second line does not match",
+                    offset,
+                    equalTo(text.length - i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_ltr_width_outOfBounds() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            // greater than width
+            var position = PxPosition((fontSizeInPx * text.length * 2).px, (fontSizeInPx / 2).px)
+            var offset = paragraph.getOffsetForPosition(position)
+            assertThat(offset, equalTo(text.length))
+
+            // negative
+            position = PxPosition((-1 * fontSizeInPx).px, (fontSizeInPx / 2).px)
+            offset = paragraph.getOffsetForPosition(position)
+            assertThat(offset, equalTo(0))
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_ltr_height_outOfBounds() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            // greater than height
+            var position = PxPosition((fontSizeInPx / 2).px, (fontSizeInPx * text.length * 2).px)
+            var offset = paragraph.getOffsetForPosition(position)
+            assertThat(offset, equalTo(0))
+
+            // negative
+            position = PxPosition((fontSizeInPx / 2).px, (-1 * fontSizeInPx).px)
+            offset = paragraph.getOffsetForPosition(position)
+            assertThat(offset, equalTo(0))
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_lineBreak() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            assertThat(
+                paragraph.getOffsetForPosition(PxPosition((3 * fontSizeInPx).px, 0.px)),
+                equalTo(3)
+            )
+
+            assertThat(
+                paragraph.getOffsetForPosition(PxPosition(0.px, (fontSizeInPx * 1.5f).px)),
+                equalTo(4)
+            )
+        }
+    }
+
+    @Test
+    fun getOffsetForPosition_multiple_paragraph() {
+        withDensity(defaultDensity) {
+            val text = "abcdef"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                paragraphStyles = listOf(
+                    AnnotatedString.Item(ParagraphStyle(), 0, 3)
+                )
+            )
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0 until 3) {
+                assertThat(
+                    paragraph.getOffsetForPosition(PxPosition((i * fontSizeInPx).px, 0.px)),
+                    equalTo(i)
+                )
+            }
+
+            for (i in 3 until 6) {
+                assertThat(
+                    paragraph.getOffsetForPosition(
+                        PxPosition(((i - 3) * fontSizeInPx).px, fontSizeInPx.px)
+                    ),
+                    equalTo(i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getBoundingBox_ltr_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+            for (i in 0 until text.length) {
+                val box = paragraph.getBoundingBox(i)
+                assertThat(box.left, equalTo(i * fontSizeInPx))
+                assertThat(box.right, equalTo((i + 1) * fontSizeInPx))
+                assertThat(box.top, equalTo(0f))
+                assertThat(box.bottom, equalTo(fontSizeInPx))
+            }
+        }
+    }
+
+    @Test
+    fun getBoundingBox_ltr_multiLines() {
+        withDensity(defaultDensity) {
+            val firstLine = "abc"
+            val secondLine = "def"
+            val text = firstLine + secondLine
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = firstLine.length * fontSizeInPx))
+
+            // test positions are 3, 4, 5 and always on the second line
+            // which maps to chars 3, 4, 5
+            for (i in 0..secondLine.length - 1) {
+                val textPosition = i + firstLine.length
+                val box = paragraph.getBoundingBox(textPosition)
+                assertThat(box.left, equalTo(i * fontSizeInPx))
+                assertThat(box.right, equalTo((i + 1) * fontSizeInPx))
+                assertThat(box.top, equalTo(fontSizeInPx))
+                assertThat(box.bottom, equalTo((2f + 1 / 5f) * fontSizeInPx))
+            }
+        }
+    }
+
+    @Test(expected = java.lang.IndexOutOfBoundsException::class)
+    fun getBoundingBox_ltr_textPosition_negative() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            paragraph.getBoundingBox(-1)
+        }
+    }
+
+    @Suppress
+    @Test(expected = java.lang.IndexOutOfBoundsException::class)
+    fun getBoundingBox_ltr_textPosition_larger_than_length_throw_exception() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            val textPosition = text.length + 1
+            paragraph.getBoundingBox(textPosition)
+        }
+    }
+
+    @Test(expected = java.lang.AssertionError::class)
+    fun getCursorRect_larger_than_length_throw_exception() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            paragraph.getCursorRect(text.length + 1)
+        }
+    }
+
+    @Test(expected = java.lang.AssertionError::class)
+    fun getCursorRect_negative_throw_exception() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            paragraph.getCursorRect(-1)
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0 until text.length) {
+                val cursorRect = paragraph.getCursorRect(i)
+                val cursorXOffset = i * fontSizeInPx
+                assertThat(
+                    cursorRect,
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "abcdef"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val charsPerLine = 3
+
+            paragraph.layout(ParagraphConstraints(width = charsPerLine * fontSizeInPx))
+
+            for (i in 0 until charsPerLine) {
+                val cursorXOffset = i * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+
+            for (i in charsPerLine until text.length) {
+                val cursorXOffset = (i % charsPerLine) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = fontSizeInPx,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx * 2.2f
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0 until text.length) {
+                val cursorXOffset = (text.length - i) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val charsPerLine = 3
+
+            paragraph.layout(ParagraphConstraints(width = charsPerLine * fontSizeInPx))
+
+            for (i in 0 until charsPerLine) {
+                val cursorXOffset = (charsPerLine - i) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+
+            for (i in charsPerLine until text.length) {
+                val cursorXOffset = (charsPerLine - i % charsPerLine) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = fontSizeInPx,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx * 2.2f
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0..text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            for (i in 1 until rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(
+                paragraph.getPrimaryHorizontal(text.length),
+                equalTo(width)
+            )
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_singleLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(width))
+
+            for (i in 1 until text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_singleLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(0f))
+
+            for (i in 1 until text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(width))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            for (i in 1 until rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(
+                paragraph.getPrimaryHorizontal(text.length),
+                equalTo(width)
+            )
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(width))
+            // Notice that abc is
+            for (i in 1 until ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(rtlText.length * fontSizeInPx + i * fontSizeInPx)
+                )
+            }
+
+            for (i in 0..rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(rtlText.length * fontSizeInPx - i * fontSizeInPx)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_newLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_newLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_newLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(width))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_newLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getLineForOffset_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..text.lastIndex) {
+                assertThat(paragraph.getLineForOffset(i), equalTo(0))
+            }
+        }
+    }
+
+    @Test
+    fun getLineForOffset_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "a\nb\nc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..text.lastIndex) {
+                assertThat(paragraph.getLineForOffset(i), equalTo(i / 2))
+            }
+        }
+    }
+
+    @Test
+    fun getLineForOffset_multiParagraph() {
+        withDensity(defaultDensity) {
+            val text = "abcd"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                paragraphStyles = listOf(AnnotatedString.Item(ParagraphStyle(), 0, 2))
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+            assertThat(paragraph.getLineForOffset(0), equalTo(0))
+            assertThat(paragraph.getLineForOffset(1), equalTo(0))
+            assertThat(paragraph.getLineForOffset(2), equalTo(1))
+            assertThat(paragraph.getLineForOffset(3), equalTo(1))
+        }
+    }
+
+    @Test
+    fun getLineForOffset_emptyParagraph() {
+        withDensity(defaultDensity) {
+            val text = "abcd"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                paragraphStyles = listOf(AnnotatedString.Item(ParagraphStyle(), 2, 2))
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+            assertThat(paragraph.getLineForOffset(0), equalTo(0))
+            assertThat(paragraph.getLineForOffset(1), equalTo(0))
+            // The empty paragraph takes one line
+            assertThat(paragraph.getLineForOffset(2), equalTo(2))
+            assertThat(paragraph.getLineForOffset(3), equalTo(2))
+        }
+    }
+
+    @Test(expected = java.lang.IndexOutOfBoundsException::class)
+    fun getLineForOffset_negativeOffset() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            paragraph.getLineForOffset(-1)
+        }
+    }
+
+    @Test(expected = java.lang.IndexOutOfBoundsException::class)
+    fun getLineForOffset_outOfBoundary() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            paragraph.getLineForOffset(text.length)
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineLeft = paragraph.getLineLeft(0)
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(
+                Rect(
+                    lineLeft,
+                    0f,
+                    lineRight - fontSizeInPx,
+                    fontSizeInPx
+                )
+            )
+
+            // Select "ab"
+            val actualPath = paragraph.getPathForRange(0, 2)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "abc\nabc"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val firstLineLeft = paragraph.getLineLeft(0)
+            val secondLineLeft = paragraph.getLineLeft(1)
+            val firstLineRight = paragraph.getLineRight(0)
+            val secondLineRight = paragraph.getLineRight(1)
+            expectedPath.addRect(
+                Rect(
+                    firstLineLeft + fontSizeInPx,
+                    0f,
+                    firstLineRight,
+                    fontSizeInPx
+                )
+            )
+            expectedPath.addRect(
+                Rect(
+                    secondLineLeft,
+                    fontSizeInPx,
+                    secondLineRight - fontSizeInPx,
+                    paragraph.height
+                )
+            )
+
+            // Select "bc\nab"
+            val actualPath = paragraph.getPathForRange(1, 6)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Bidi() {
+        withDensity(defaultDensity) {
+            val textLTR = "Hello"
+            val textRTL = "שלום"
+            val text = textLTR + textRTL
+            val selectionLTRStart = 2
+            val selectionRTLEnd = 2
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineLeft = paragraph.getLineLeft(0)
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(
+                Rect(
+                    lineLeft + selectionLTRStart * fontSizeInPx,
+                    0f,
+                    lineLeft + textLTR.length * fontSizeInPx,
+                    fontSizeInPx
+                )
+            )
+            expectedPath.addRect(
+                Rect(
+                    lineRight - selectionRTLEnd * fontSizeInPx,
+                    0f,
+                    lineRight,
+                    fontSizeInPx
+                )
+            )
+
+            // Select "llo..של"
+            val actualPath =
+                paragraph.getPathForRange(selectionLTRStart, textLTR.length + selectionRTLEnd)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Start_Equals_End_Returns_Empty_Path() {
+        val text = "abc"
+        val paragraph = simpleMultiParagraph(
+            text = text,
+            fontFamily = fontFamilyMeasureFont,
+            fontSize = 20.sp
+        )
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+        val actualPath = paragraph.getPathForRange(1, 1)
+
+        assertThat(actualPath.getBounds(), equalTo(Rect.zero))
+    }
+
+    @Test
+    fun testGetPathForRange_Empty_Text() {
+        val text = ""
+        val paragraph = simpleMultiParagraph(
+            text = text,
+            fontFamily = fontFamilyMeasureFont,
+            fontSize = 20.sp
+        )
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+        val actualPath = paragraph.getPathForRange(0, 0)
+
+        assertThat(actualPath.getBounds(), equalTo(Rect.zero))
+    }
+
+    @Test
+    fun testGetPathForRange_Surrogate_Pair_Start_Middle_Second_Character_Selected() {
+        withDensity(defaultDensity) {
+            val text = "\uD834\uDD1E\uD834\uDD1F"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(Rect(lineRight / 2, 0f, lineRight, fontSizeInPx))
+
+            // Try to select "\uDD1E\uD834\uDD1F", only "\uD834\uDD1F" is selected.
+            val actualPath = paragraph.getPathForRange(1, text.length)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Surrogate_Pair_End_Middle_Second_Character_Selected() {
+        withDensity(defaultDensity) {
+            val text = "\uD834\uDD1E\uD834\uDD1F"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(Rect(lineRight / 2, 0f, lineRight, fontSizeInPx))
+
+            // Try to select "\uDD1E\uD834", actually "\uD834\uDD1F" is selected.
+            val actualPath = paragraph.getPathForRange(1, text.length - 1)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Surrogate_Pair_Start_Middle_End_Same_Character_Returns_Line_Segment() {
+        withDensity(defaultDensity) {
+            val text = "\uD834\uDD1E\uD834\uDD1F"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(Rect(lineRight / 2, 0f, lineRight / 2, fontSizeInPx))
+
+            // Try to select "\uDD1E", get vertical line segment after this character.
+            val actualPath = paragraph.getPathForRange(1, 2)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Emoji_Sequence() {
+        withDensity(defaultDensity) {
+            val text = "\u1F600\u1F603\u1F604\u1F606"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineLeft = paragraph.getLineLeft(0)
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(
+                Rect(
+                    lineLeft + fontSizeInPx,
+                    0f,
+                    lineRight - fontSizeInPx,
+                    fontSizeInPx
+                )
+            )
+
+            // Select "\u1F603\u1F604"
+            val actualPath = paragraph.getPathForRange(1, text.length - 1)
+
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Unicode_200D_Return_Line_Segment() {
+        withDensity(defaultDensity) {
+            val text = "\u200D"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineLeft = paragraph.getLineLeft(0)
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(Rect(lineLeft, 0f, lineRight, fontSizeInPx))
+
+            val actualPath = paragraph.getPathForRange(0, 1)
+
+            assertThat(lineLeft, equalTo(lineRight))
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetPathForRange_Unicode_2066_Return_Line_Segment() {
+        withDensity(defaultDensity) {
+            val text = "\u2066"
+            val fontSize = 20f.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontFamily = fontFamilyMeasureFont,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            val expectedPath = Path()
+            val lineLeft = paragraph.getLineLeft(0)
+            val lineRight = paragraph.getLineRight(0)
+            expectedPath.addRect(Rect(lineLeft, 0f, lineRight, fontSizeInPx))
+
+            val actualPath = paragraph.getPathForRange(0, 1)
+
+            assertThat(lineLeft, equalTo(lineRight))
+            val diff = Path.combine(PathOperation.difference, expectedPath, actualPath).getBounds()
+            assertThat(diff, equalTo(Rect.zero))
+        }
+    }
+
+    @Test
+    fun testGetWordBoundary() {
+        val text = "abc def"
+        val paragraph = simpleMultiParagraph(
+            text = text,
+            fontFamily = fontFamilyMeasureFont,
+            fontSize = 20.sp
+        )
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+        val result = paragraph.getWordBoundary(text.indexOf('a'))
+
+        assertThat(result.start, equalTo(text.indexOf('a')))
+        assertThat(result.end, equalTo(text.indexOf(' ')))
+    }
+
+    @Test
+    fun testGetWordBoundary_Bidi() {
+        val text = "abc \u05d0\u05d1\u05d2 def"
+        val paragraph = simpleMultiParagraph(
+            text = text,
+            fontFamily = fontFamilyMeasureFont,
+            fontSize = 20.sp
+        )
+        paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+        val resultEnglish = paragraph.getWordBoundary(text.indexOf('a'))
+        val resultHebrew = paragraph.getWordBoundary(text.indexOf('\u05d1'))
+
+        assertThat(resultEnglish.start, equalTo(text.indexOf('a')))
+        assertThat(resultEnglish.end, equalTo(text.indexOf(' ')))
+        assertThat(resultHebrew.start, equalTo(text.indexOf('\u05d0')))
+        assertThat(resultHebrew.end, equalTo(text.indexOf('\u05d2') + 1))
+    }
+
+    @Test
+    fun width_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.width, equalTo(0.0f))
+    }
+
+    @Test
+    fun height_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.height, equalTo(0.0f))
+    }
+
+    @Test
+    fun minIntrinsicWidth_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.minIntrinsicWidth, equalTo(0.0f))
+    }
+
+    @Test
+    fun maxIntrinsicWidth_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.maxIntrinsicWidth, equalTo(0.0f))
+    }
+
+    @Test
+    fun alphabeticBaseline_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.baseline, equalTo(0.0f))
+    }
+
+    @Test
+    fun didExceedMaxLines_default_value() {
+        val paragraph = simpleMultiParagraph()
+
+        assertThat(paragraph.didExceedMaxLines, equalTo(false))
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun paint_throws_exception_if_layout_is_not_called() {
+        val paragraph = simpleMultiParagraph()
+
+        paragraph.paint(mock())
+    }
+
+    @Test(expected = IllegalStateException::class)
+    fun getPositionForOffset_throws_exception_if_layout_is_not_called() {
+        val paragraph = simpleMultiParagraph()
+
+        paragraph.getOffsetForPosition(PxPosition.Origin)
+    }
+
+    @Test(expected = AssertionError::class)
+    fun getPathForRange_throws_exception_if_start_larger_than_end() {
+        val text = "ab"
+        val textStart = 0
+        val textEnd = text.length
+        val paragraph = simpleMultiParagraph(text = text)
+
+        paragraph.getPathForRange(textEnd, textStart)
+    }
+
+    @Test(expected = AssertionError::class)
+    fun getPathForRange_throws_exception_if_start_is_smaller_than_zero() {
+        val text = "ab"
+        val textStart = 0
+        val textEnd = text.length
+        val paragraph = simpleMultiParagraph(text = text)
+
+        paragraph.getPathForRange(textStart - 2, textEnd - 1)
+    }
+
+    @Test(expected = AssertionError::class)
+    fun getPathForRange_throws_exception_if_end_is_larger_than_text_length() {
+        val text = "ab"
+        val textStart = 0
+        val textEnd = text.length
+        val paragraph = simpleMultiParagraph(text = text)
+
+        paragraph.getPathForRange(textStart, textEnd + 1)
+    }
+
+    @Test
+    fun textAlign_defaultValue_alignsStart() {
+        withDensity(defaultDensity) {
+            val textLTR = "aa"
+            val textRTL = "\u05D0\u05D0"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+
+            val paragraphLTR = simpleMultiParagraph(
+                text = textLTR,
+                fontSize = fontSize
+            )
+            val layoutLTRWidth = (textLTR.length + 2) * fontSizeInPx
+            paragraphLTR.layout(ParagraphConstraints(width = layoutLTRWidth))
+
+            val paragraphRTL = simpleMultiParagraph(
+                text = textRTL,
+                fontSize = fontSize
+            )
+            val layoutRTLWidth = (textRTL.length + 2) * fontSizeInPx
+            paragraphRTL.layout(ParagraphConstraints(width = layoutRTLWidth))
+
+            // When textAlign is TextAlign.start, LTR aligns to left, RTL aligns to right.
+            assertThat(paragraphLTR.getLineLeft(0), equalTo(0.0f))
+            assertThat(paragraphRTL.getLineRight(0), equalTo(layoutRTLWidth))
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignLeft_returnsZeroForGetLineLeft() {
+        withDensity(defaultDensity) {
+            val texts = listOf("aa", "\u05D0\u05D0")
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+
+            texts.map { text ->
+                val paragraph = simpleMultiParagraph(
+                    text = text,
+                    textAlign = TextAlign.Left,
+                    fontSize = fontSize
+                )
+                val layoutWidth = (text.length + 2) * fontSizeInPx
+                paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+                assertThat(paragraph.getLineLeft(0), equalTo(0.0f))
+            }
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignRight_returnsLayoutWidthForGetLineRight() {
+        withDensity(defaultDensity) {
+            val texts = listOf("aa", "\u05D0\u05D0")
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+
+            texts.map { text ->
+                val paragraph = simpleMultiParagraph(
+                    text = text,
+                    textAlign = TextAlign.Right,
+                    fontSize = fontSize
+                )
+                val layoutWidth = (text.length + 2) * fontSizeInPx
+                paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+                assertThat(paragraph.getLineRight(0), equalTo(layoutWidth))
+            }
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignCenter_textIsCentered() {
+        withDensity(defaultDensity) {
+            val texts = listOf("aa", "\u05D0\u05D0")
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+
+            texts.map { text ->
+                val paragraph = simpleMultiParagraph(
+                    text = text,
+                    textAlign = TextAlign.Center,
+                    fontSize = fontSize
+                )
+                val layoutWidth = (text.length + 2) * fontSizeInPx
+                paragraph.layout(ParagraphConstraints(width = layoutWidth))
+                val textWidth = text.length * fontSizeInPx
+
+                assertThat(
+                    paragraph.getLineLeft(0),
+                    equalTo(layoutWidth / 2 - textWidth / 2)
+                )
+                assertThat(
+                    paragraph.getLineRight(0),
+                    equalTo(layoutWidth / 2 + textWidth / 2)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignStart_withLTR_returnsZeroForGetLineLeft() {
+        withDensity(defaultDensity) {
+            val text = "aa"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = (text.length + 2) * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textAlign = TextAlign.Start,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.getLineLeft(0), equalTo(0.0f))
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignEnd_withLTR_returnsLayoutWidthForGetLineRight() {
+        withDensity(defaultDensity) {
+            val text = "aa"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = (text.length + 2) * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textAlign = TextAlign.End,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.getLineRight(0), equalTo(layoutWidth))
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignStart_withRTL_returnsLayoutWidthForGetLineRight() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D0"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = (text.length + 2) * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textAlign = TextAlign.Start,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.getLineRight(0), equalTo(layoutWidth))
+        }
+    }
+
+    @Test
+    fun textAlign_whenAlignEnd_withRTL_returnsZeroForGetLineLeft() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D0"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = (text.length + 2) * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textAlign = TextAlign.End,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.getLineLeft(0), equalTo(0.0f))
+        }
+    }
+
+    @Test
+    @SdkSuppress(minSdkVersion = 28)
+    // We have to test justification above API 28 because of this bug b/68009059, where devices
+    // before API 28 may have an extra space at the end of line.
+    fun textAlign_whenAlignJustify_justifies() {
+        withDensity(defaultDensity) {
+            val text = "a a a"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = ("a a".length + 1) * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textAlign = TextAlign.Justify,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.getLineLeft(0), equalTo(0.0f))
+            assertThat(paragraph.getLineRight(0), equalTo(layoutWidth))
+            // Last line should align start
+            assertThat(paragraph.getLineLeft(1), equalTo(0.0f))
+        }
+    }
+
+    @Test
+    fun textDirection_whenLTR_dotIsOnRight() {
+        withDensity(defaultDensity) {
+            val text = "a.."
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = text.length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textDirection = TextDirection.Ltr,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+            // The position of the last character in display order.
+            val position = PxPosition(("a.".length * fontSizeInPx + 1).px, (fontSizeInPx / 2).px)
+            val charIndex = paragraph.getOffsetForPosition(position)
+            assertThat(charIndex, equalTo(2))
+        }
+    }
+
+    @Test
+    fun textDirection_whenRTL_dotIsOnLeft() {
+        withDensity(defaultDensity) {
+            val text = "a.."
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = text.length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textDirection = TextDirection.Rtl,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+            // The position of the first character in display order.
+            val position = PxPosition((fontSizeInPx / 2 + 1).px, (fontSizeInPx / 2).px)
+            val charIndex = paragraph.getOffsetForPosition(position)
+            assertThat(charIndex, equalTo(2))
+        }
+    }
+
+    @Test
+    fun textDirection_whenDefault_withoutStrongChar_directionIsLTR() {
+        withDensity(defaultDensity) {
+            val text = "..."
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = text.length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+            for (i in 0..text.length) {
+                // The position of the i-th character in display order.
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx / 2).px)
+                val charIndex = paragraph.getOffsetForPosition(position)
+                assertThat(charIndex, equalTo(i))
+            }
+        }
+    }
+
+    @Test
+    fun textDirection_whenDefault_withFirstStrongCharLTR_directionIsLTR() {
+        withDensity(defaultDensity) {
+            val text = "a\u05D0."
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = text.length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+            for (i in 0 until text.length) {
+                // The position of the i-th character in display order.
+                val position = PxPosition((i * fontSizeInPx + 1).px, (fontSizeInPx / 2).px)
+                val charIndex = paragraph.getOffsetForPosition(position)
+                assertThat(charIndex, equalTo(i))
+            }
+        }
+    }
+
+    @Test
+    fun textDirection_whenDefault_withFirstStrongCharRTL_directionIsRTL() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0a."
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = text.length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+            // The first character in display order should be '.'
+            val position = PxPosition((fontSizeInPx / 2 + 1).px, (fontSizeInPx / 2).px)
+            val index = paragraph.getOffsetForPosition(position)
+            assertThat(index, equalTo(2))
+        }
+    }
+
+    @Test
+    fun lineHeight_returnsSameAsGiven() {
+        withDensity(defaultDensity) {
+            val text = "abcdefgh"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            // Make the layout 4 lines
+            val layoutWidth = text.length * fontSizeInPx / 4
+            val lineHeight = 1.5f
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                lineHeight = lineHeight
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            assertThat(paragraph.lineCount, equalTo(4))
+            // TODO(Migration/haoyuchang): Due to bug b/120530738, the height of the first line is
+            // wrong in the framework. Will fix it when the lineHeight in TextSpan is implemented.
+            for (i in 1 until paragraph.lineCount - 1) {
+                val actualHeight = paragraph.getLineHeight(i)
+                // In the sample_font.ttf, the height of the line should be
+                // fontSize + 0.2f * fontSize(line gap)
+                assertThat(
+                    "line number $i",
+                    actualHeight,
+                    equalTo(1.2f * fontSizeInPx * lineHeight)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun lineHeight_hasNoEffectOnLastLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val layoutWidth = (text.length - 1) * fontSizeInPx
+            val lineHeight = 1.5f
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                fontSize = fontSize,
+                lineHeight = lineHeight
+            )
+            paragraph.layout(ParagraphConstraints(width = layoutWidth))
+
+            val lastLine = paragraph.lineCount - 1
+            // In the sample_font.ttf, the height of the line should be
+            // fontSize + 0.2 * fontSize(line gap)
+            assertThat(paragraph.getLineHeight(lastLine), equalTo(1.2f * fontSizeInPx))
+        }
+    }
+
+    @Test
+    fun textIndent_onSingleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val indent = 20.0f
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textIndent = TextIndent(firstLine = indent.px),
+                fontSize = fontSize,
+                fontFamily = fontFamilyMeasureFont
+            )
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            // This position should point to the first character 'a' if indent is applied.
+            // Otherwise this position will point to the second character 'b'.
+            val position = PxPosition((indent + 1).px, (fontSizeInPx / 2).px)
+            // The offset corresponding to the position should be the first char 'a'.
+            assertThat(paragraph.getOffsetForPosition(position), equalTo(0))
+        }
+    }
+
+    @Test
+    fun textIndent_onFirstLine() {
+        withDensity(defaultDensity) {
+            val text = "abcdef"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val indent = 20.0f
+            val paragraphWidth = "abcd".length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textIndent = TextIndent(firstLine = indent.px),
+                fontSize = fontSize,
+                fontFamily = fontFamilyMeasureFont
+            )
+            paragraph.layout(ParagraphConstraints(width = paragraphWidth))
+
+            assertThat(paragraph.lineCount, equalTo(2))
+            // This position should point to the first character of the first line if indent is
+            // applied. Otherwise this position will point to the second character of the second line.
+            val position = PxPosition((indent + 1).px, (fontSizeInPx / 2).px)
+            // The offset corresponding to the position should be the first char 'a'.
+            assertThat(paragraph.getOffsetForPosition(position), equalTo(0))
+        }
+    }
+
+    @Test
+    fun textIndent_onRestLine() {
+        withDensity(defaultDensity) {
+            val text = "abcde"
+            val fontSize = 20.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val indent = 20.0f
+            val paragraphWidth = "abc".length * fontSizeInPx
+
+            val paragraph = simpleMultiParagraph(
+                text = text,
+                textIndent = TextIndent(
+                    firstLine = 0.px,
+                    restLine = indent.px
+                ),
+                fontSize = fontSize,
+                fontFamily = fontFamilyMeasureFont
+            )
+            paragraph.layout(ParagraphConstraints(width = paragraphWidth))
+
+            // This position should point to the first character of the second line if indent is
+            // applied. Otherwise this position will point to the second character of the second line.
+            val position = PxPosition((indent + 1).px, (fontSizeInPx / 2 + fontSizeInPx).px)
+            // The offset corresponding to the position should be the 'd' in the second line.
+            assertThat(
+                paragraph.getOffsetForPosition(position),
+                equalTo("abcd".length - 1)
+            )
+        }
+    }
+
+    private fun simpleMultiParagraph(
+        text: String = "",
+        textIndent: TextIndent? = null,
+        textAlign: TextAlign? = null,
+        textDirection: TextDirection? = null,
+        fontSize: Sp? = null,
+        maxLines: Int? = null,
+        lineHeight: Float? = null,
+        textStyles: List<AnnotatedString.Item<TextStyle>> = listOf(),
+        paragraphStyles: List<AnnotatedString.Item<ParagraphStyle>> = listOf(),
+        fontFamily: FontFamily = fontFamilyMeasureFont,
+        locale: Locale? = null,
+        textStyle: TextStyle? = null,
+        density: Density? = null
+    ): MultiParagraph {
+        return MultiParagraph(
+            annotatedString = AnnotatedString(
+                text = text,
+                textStyles = textStyles,
+                paragraphStyles = paragraphStyles
+            ),
+            textStyle = TextStyle(
+                fontFamily = fontFamily,
+                fontSize = fontSize,
+                locale = locale
+            ).merge(textStyle),
+            paragraphStyle = ParagraphStyle(
+                textIndent = textIndent,
+                textAlign = textAlign,
+                textDirection = textDirection,
+                lineHeight = lineHeight
+            ),
+            maxLines = maxLines,
+            density = density ?: defaultDensity,
+            resourceLoader = TestFontResourceLoader(context)
+        )
+    }
+}
diff --git a/ui/ui-text/src/androidTest/java/androidx/ui/text/ParagraphIntegrationTest.kt b/ui/ui-text/src/androidTest/java/androidx/ui/text/ParagraphIntegrationTest.kt
index 841eb1b..9718437 100644
--- a/ui/ui-text/src/androidTest/java/androidx/ui/text/ParagraphIntegrationTest.kt
+++ b/ui/ui-text/src/androidTest/java/androidx/ui/text/ParagraphIntegrationTest.kt
@@ -62,6 +62,8 @@
 
     private val resourceLoader = TestFontResourceLoader(context)
 
+    private val cursorWidth = 4f
+
     @Test
     fun empty_string() {
         withDensity(defaultDensity) {
@@ -430,6 +432,566 @@
         }
     }
 
+    @Test(expected = java.lang.AssertionError::class)
+    fun getCursorRect_larger_than_length_throw_exception() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            paragraph.getCursorRect(text.length + 1)
+        }
+    }
+
+    @Test(expected = java.lang.AssertionError::class)
+    fun getCursorRect_negative_throw_exception() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            paragraph.getCursorRect(-1)
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0 until text.length) {
+                val cursorRect = paragraph.getCursorRect(i)
+                val cursorXOffset = i * fontSizeInPx
+                assertThat(
+                    cursorRect,
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "abcdef"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val charsPerLine = 3
+
+            paragraph.layout(ParagraphConstraints(width = charsPerLine * fontSizeInPx))
+
+            for (i in 0 until charsPerLine) {
+                val cursorXOffset = i * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+
+            for (i in charsPerLine until text.length) {
+                val cursorXOffset = (i % charsPerLine) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = fontSizeInPx,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx * 2.2f
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_newLine() {
+        withDensity(defaultDensity) {
+            val text = "abc\ndef"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            // Cursor before '\n'
+            assertThat(
+                paragraph.getCursorRect(3),
+                equalTo(Rect(
+                    left = 3 * fontSizeInPx - cursorWidth / 2,
+                    top = 0f,
+                    right = 3 * fontSizeInPx + cursorWidth / 2,
+                    bottom = fontSizeInPx
+                ))
+            )
+
+            // Cursor after '\n'
+            assertThat(
+                paragraph.getCursorRect(4),
+                equalTo(Rect(
+                    left = -cursorWidth / 2,
+                    top = fontSizeInPx,
+                    right = cursorWidth / 2,
+                    bottom = fontSizeInPx * 2.2f
+                ))
+            )
+        }
+    }
+
+    @Test
+    fun getCursorRect_ltr_newLine_last_char() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = Float.MAX_VALUE))
+
+            // Cursor before '\n'
+            assertThat(
+                paragraph.getCursorRect(3),
+                equalTo(Rect(
+                    left = 3 * fontSizeInPx - cursorWidth / 2,
+                    top = 0f,
+                    right = 3 * fontSizeInPx + cursorWidth / 2,
+                    bottom = fontSizeInPx
+                ))
+            )
+
+            // Cursor after '\n'
+            assertThat(
+                paragraph.getCursorRect(4),
+                equalTo(Rect(
+                    left = -cursorWidth / 2,
+                    top = fontSizeInPx,
+                    right = cursorWidth / 2,
+                    bottom = fontSizeInPx * 2.2f
+                ))
+            )
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_singleLine() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0 until text.length) {
+                val cursorXOffset = (text.length - i) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_multiLines() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val charsPerLine = 3
+
+            paragraph.layout(ParagraphConstraints(width = charsPerLine * fontSizeInPx))
+
+            for (i in 0 until charsPerLine) {
+                val cursorXOffset = (charsPerLine - i) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = 0f,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx
+                    ))
+                )
+            }
+
+            for (i in charsPerLine until text.length) {
+                val cursorXOffset = (charsPerLine - i % charsPerLine) * fontSizeInPx
+                assertThat(
+                    paragraph.getCursorRect(i),
+                    equalTo(Rect(
+                        left = cursorXOffset - cursorWidth / 2,
+                        top = fontSizeInPx,
+                        right = cursorXOffset + cursorWidth / 2,
+                        bottom = fontSizeInPx * 2.2f
+                    ))
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_newLine() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = 3 * fontSizeInPx))
+
+            // Cursor before '\n'
+            assertThat(
+                paragraph.getCursorRect(3),
+                equalTo(Rect(
+                    left = 0 - cursorWidth / 2,
+                    top = 0f,
+                    right = 0 + cursorWidth / 2,
+                    bottom = fontSizeInPx
+                ))
+            )
+
+            // Cursor after '\n'
+            assertThat(
+                paragraph.getCursorRect(4),
+                equalTo(Rect(
+                    left = 3 * fontSizeInPx - cursorWidth / 2,
+                    top = fontSizeInPx,
+                    right = 3 * fontSizeInPx + cursorWidth / 2,
+                    bottom = fontSizeInPx * 2.2f
+                ))
+            )
+        }
+    }
+
+    @Test
+    fun getCursorRect_rtl_newLine_last_char() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = 3 * fontSizeInPx))
+
+            // Cursor before '\n'
+            assertThat(
+                paragraph.getCursorRect(3),
+                equalTo(Rect(
+                    left = 0 - cursorWidth / 2,
+                    top = 0f,
+                    right = 0 + cursorWidth / 2,
+                    bottom = fontSizeInPx
+                ))
+            )
+
+            // Cursor after '\n'
+            assertThat(
+                paragraph.getCursorRect(4),
+                equalTo(Rect(
+                    left = -cursorWidth / 2,
+                    top = fontSizeInPx,
+                    right = +cursorWidth / 2,
+                    bottom = fontSizeInPx * 2.2f
+                ))
+            )
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+
+            paragraph.layout(ParagraphConstraints(width = text.length * fontSizeInPx))
+
+            for (i in 0..text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            for (i in 1 until rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(
+                paragraph.getPrimaryHorizontal(text.length),
+                equalTo(width)
+            )
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_singleLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val text = "abc"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(width))
+
+            for (i in 1 until text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_singleLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(0f))
+
+            for (i in 1 until text.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(width))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            for (i in 0..ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(fontSizeInPx * i)
+                )
+            }
+
+            for (i in 1 until rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(width - fontSizeInPx * i)
+                )
+            }
+
+            assertThat(
+                paragraph.getPrimaryHorizontal(text.length),
+                equalTo(width)
+            )
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_bidi_singleLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val ltrText = "abc"
+            val rtlText = "\u05D0\u05D1\u05D2"
+            val text = ltrText + rtlText
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(0), equalTo(width))
+            for (i in 1 until ltrText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i),
+                    equalTo(rtlText.length * fontSizeInPx + i * fontSizeInPx)
+                )
+            }
+
+            for (i in 0..rtlText.length) {
+                assertThat(
+                    paragraph.getPrimaryHorizontal(i + ltrText.length),
+                    equalTo(rtlText.length * fontSizeInPx - i * fontSizeInPx)
+                )
+            }
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_newLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_newLine_textDirectionDefault() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(text = text, fontSize = fontSize)
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_ltr_newLine_textDirectionRtl() {
+        withDensity(defaultDensity) {
+            val text = "abc\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Rtl
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(width))
+        }
+    }
+
+    @Test
+    fun getPrimaryHorizontal_rtl_newLine_textDirectionLtr() {
+        withDensity(defaultDensity) {
+            val text = "\u05D0\u05D1\u05D2\n"
+            val fontSize = 50.sp
+            val fontSizeInPx = fontSize.toPx().value
+            val paragraph = simpleParagraph(
+                text = text,
+                fontSize = fontSize,
+                textDirection = TextDirection.Ltr
+            )
+            val width = text.length * fontSizeInPx
+
+            paragraph.layout(ParagraphConstraints(width))
+
+            assertThat(paragraph.getPrimaryHorizontal(text.length), equalTo(0f))
+        }
+    }
+
     @Test
     fun locale_withCJK_shouldNotDrawSame() {
         withDensity(defaultDensity) {
diff --git a/ui/ui-text/src/androidTest/java/androidx/ui/text/TextPainterIntegrationTest.kt b/ui/ui-text/src/androidTest/java/androidx/ui/text/TextPainterIntegrationTest.kt
index 41f1cf3..3b17aae 100644
--- a/ui/ui-text/src/androidTest/java/androidx/ui/text/TextPainterIntegrationTest.kt
+++ b/ui/ui-text/src/androidTest/java/androidx/ui/text/TextPainterIntegrationTest.kt
@@ -26,7 +26,6 @@
 import androidx.ui.core.px
 import androidx.ui.core.sp
 import androidx.ui.core.withDensity
-import androidx.ui.engine.geometry.Offset
 import androidx.ui.engine.geometry.Rect
 import androidx.ui.engine.geometry.Size
 import androidx.ui.text.FontTestData.Companion.BASIC_MEASURE_FONT
@@ -291,7 +290,7 @@
 
         textPainter.layout(Constraints(0.ipx, 20.ipx))
 
-        assertThat(textPainter.paragraph).isNotNull()
+        assertThat(textPainter.multiParagraph).isNotNull()
     }
 
     @Test
@@ -460,10 +459,10 @@
             val defaultSelectionColor = Color(0x6633B5E5)
             expectedPaint.color = defaultSelectionColor
 
-            val firstLineLeft = textPainter.paragraph?.getLineLeft(0)
-            val secondLineLeft = textPainter.paragraph?.getLineLeft(1)
-            val firstLineRight = textPainter.paragraph?.getLineRight(0)
-            val secondLineRight = textPainter.paragraph?.getLineRight(1)
+            val firstLineLeft = textPainter.multiParagraph?.getLineLeft(0)
+            val secondLineLeft = textPainter.multiParagraph?.getLineLeft(1)
+            val firstLineRight = textPainter.multiParagraph?.getLineRight(0)
+            val secondLineRight = textPainter.multiParagraph?.getLineRight(1)
             expectedCanvas.drawRect(
                 Rect(firstLineLeft!!, 0f, firstLineRight!!, fontSizeInPx),
                 expectedPaint
@@ -473,7 +472,7 @@
                     secondLineLeft!!,
                     fontSizeInPx,
                     secondLineRight!!,
-                    textPainter.paragraph!!.height
+                    textPainter.multiParagraph!!.height
                 ),
                 expectedPaint
             )
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/AnnotatedString.kt b/ui/ui-text/src/main/java/androidx/ui/text/AnnotatedString.kt
index 97fda37..28140c5 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/AnnotatedString.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/AnnotatedString.kt
@@ -21,8 +21,23 @@
  */
 data class AnnotatedString(
     val text: String,
-    val textStyles: List<Item<TextStyle>> = listOf()
+    val textStyles: List<Item<TextStyle>> = listOf(),
+    val paragraphStyles: List<Item<ParagraphStyle>> = listOf()
 ) {
+
+    init {
+        var lastStyleEnd = -1
+        for (paragraphStyle in paragraphStyles) {
+            if (paragraphStyle.start < lastStyleEnd) {
+                throw IllegalArgumentException("ParagraphStyle should not overlap")
+            }
+            if (paragraphStyle.end > text.length) {
+                throw IllegalArgumentException("ParagraphStyle range " +
+                        "[${paragraphStyle.start}, ${paragraphStyle.end}) is out of boundary")
+            }
+            lastStyleEnd = paragraphStyle.end
+        }
+    }
     /**
      * The information attached on the text such as a TextStyle.
      *
@@ -31,5 +46,11 @@
      * @param end The end of the range where [style] takes effect. It's exclusive.
      */
     // TODO(haoyuchang): Check some other naming options.
-    data class Item<T>(val style: T, val start: Int, val end: Int)
+    data class Item<T>(val style: T, val start: Int, val end: Int) {
+        init {
+            if (start > end) {
+                throw IllegalArgumentException("Reversed range is not supported")
+            }
+        }
+    }
 }
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/MultiParagraph.kt b/ui/ui-text/src/main/java/androidx/ui/text/MultiParagraph.kt
new file mode 100644
index 0000000..830a776
--- /dev/null
+++ b/ui/ui-text/src/main/java/androidx/ui/text/MultiParagraph.kt
@@ -0,0 +1,634 @@
+/*
+ * 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.text
+
+import androidx.ui.core.Density
+import androidx.ui.core.Px
+import androidx.ui.core.PxPosition
+import androidx.ui.core.px
+import androidx.ui.engine.geometry.Offset
+import androidx.ui.engine.geometry.Rect
+import androidx.ui.painting.Canvas
+import androidx.ui.painting.Path
+import androidx.ui.text.font.Font
+import java.lang.IllegalStateException
+import kotlin.math.max
+
+/**
+ * The class that renders multiple paragraphs at once.
+ *
+ * It's designed to support multiple [ParagraphStyle]s in single text widget.
+ */
+internal class MultiParagraph(
+    val annotatedString: AnnotatedString,
+    private val textStyle: TextStyle = TextStyle(),
+    private val paragraphStyle: ParagraphStyle = ParagraphStyle(),
+    val maxLines: Int? = null,
+    val ellipsis: Boolean? = null,
+    val density: Density,
+    val resourceLoader: Font.ResourceLoader
+) {
+    /**
+     * The minimum width that this paragraph could be without failing to paint
+     * its contents within itself.
+     *
+     * Valid only after [layout] has been called.
+     */
+    val minIntrinsicWidth: Float
+        get() = paragraphInfoList.foldRight(0f) { paragraphInfo, minWidth ->
+            max(paragraphInfo.paragraph.minIntrinsicWidth, minWidth)
+        }
+
+    /**
+     * Returns the smallest width beyond which increasing the width never
+     * decreases the height.
+     *
+     * Valid only after [layout] has been called.
+     */
+    val maxIntrinsicWidth: Float
+        get() = paragraphInfoList.foldRight(0f) { paragraphInfo, maxWidth ->
+            max(paragraphInfo.paragraph.maxIntrinsicWidth, maxWidth)
+        }
+
+    /**
+     * True if there is more vertical content, but the text was truncated, either
+     * because we reached `maxLines` lines of text or because the `maxLines` was
+     * null, `ellipsis` was not null, and one of the lines exceeded the width
+     * constraint.
+     *
+     * See the discussion of the `maxLines` and `ellipsis` arguments at [ParagraphStyle].
+     */
+    var didExceedMaxLines: Boolean = false
+        private set
+
+    /**
+     * The amount of horizontal space this paragraph occupies.
+     *
+     * Valid only after [layout] has been called.
+     */
+    var width: Float = 0f
+        private set
+
+    /**
+     * The amount of vertical space this paragraph occupies.
+     *
+     * Valid only after [layout] has been called.
+     */
+    var height: Float = 0f
+        private set
+
+    /**
+     * The distance from the top of the paragraph to the alphabetic
+     * baseline of the first line, in logical pixels.
+     */
+    val baseline: Float
+        get() = if (paragraphInfoList.isEmpty()) 0f else paragraphInfoList[0].paragraph.baseline
+
+    /** The total number of lines in the text. */
+    var lineCount: Int = 0
+        private set
+
+    private var needLayout = true
+
+    private val paragraphInfoList: List<ParagraphInfo>
+
+    init {
+        val paragraphStyles = fillInParagraphRanges(annotatedString, this.paragraphStyle)
+        this.paragraphInfoList = paragraphStyles.map { (style, start, end) ->
+            // TODO(haoyuchang): Change substring to Paragraph receiving text and range.
+            val textInParagraph = if (start != end) {
+                annotatedString.text.substring(start, end)
+            } else {
+                ""
+            }
+            val textStylesInParagraph = annotatedString.getLocalStyles(start, end)
+
+            // TODO(haoyuchang): remove the top and bottom padding between two paragraphs
+            val paragraph = Paragraph(
+                textInParagraph,
+                this.textStyle,
+                style,
+                textStylesInParagraph,
+                maxLines,
+                ellipsis,
+                density,
+                resourceLoader
+            )
+
+            ParagraphInfo(
+                paragraph = paragraph,
+                startIndex = start,
+                endIndex = end
+            )
+        }
+    }
+
+    /**
+     * Computes the size and position of each glyph in the paragraph.
+     *
+     * The [ParagraphConstraints] control how wide the text is allowed to be.
+     */
+    fun layout(constraints: ParagraphConstraints) {
+        this.needLayout = false
+        this.width = constraints.width
+        this.didExceedMaxLines = false
+
+        var currentLineCount = 0
+        var currentHeight = 0f
+
+        for ((index, paragraphInfo) in paragraphInfoList.withIndex()) {
+            val paragraph = paragraphInfo.paragraph
+            paragraph.layout(constraints)
+
+            paragraphInfo.startLineIndex = currentLineCount
+            paragraphInfo.endLineIndex = currentLineCount + paragraph.lineCount
+            currentLineCount = paragraphInfo.endLineIndex
+
+            paragraphInfo.top = currentHeight.px
+            paragraphInfo.bottom = (currentHeight + paragraph.height).px
+            currentHeight += paragraph.height
+
+            // TODO(haoyuchang): solve the corner case where the ellipsis won't be applied when
+            //  currentLineNum == maxLines but there are still more paragraphs
+            if (paragraph.didExceedMaxLines ||
+                (currentLineCount == maxLines && index != this.paragraphInfoList.lastIndex)
+            ) {
+                this.didExceedMaxLines = true
+                break
+            }
+        }
+        this.lineCount = currentLineCount
+        this.height = currentHeight
+    }
+
+    /** Paint the paragraphs to canvas. */
+    fun paint(canvas: Canvas) {
+        assertNeedLayout()
+
+        canvas.save()
+        paragraphInfoList.forEach {
+            it.paragraph.paint(canvas)
+            canvas.translate(0f, it.paragraph.height)
+        }
+        canvas.restore()
+    }
+
+    /** Returns path that enclose the given text range. */
+    fun getPathForRange(start: Int, end: Int): Path {
+        if (start !in 0..end || end > annotatedString.text.length) {
+            throw AssertionError(
+                "Start($start) or End($end) is out of range [0..${annotatedString.text.length})," +
+                        " or start > end!"
+            )
+        }
+        assertNeedLayout()
+
+        if (start == end) return Path()
+
+        val paragraphIndex = findParagraphByIndex(paragraphInfoList, start)
+        val path = Path()
+
+        paragraphInfoList.drop(paragraphIndex)
+            .takeWhile { it.startIndex < end }
+            .filterNot { it.startIndex == it.endIndex }
+            .forEach {
+                with(it) {
+                    path.addPath(
+                        path = paragraph.getPathForRange(
+                            start = start.toLocalIndex(),
+                            end = end.toLocalIndex()
+                        ).toGlobal()
+                    )
+                }
+            }
+        return path
+    }
+
+    /** Returns the character offset closest to the given graphical position. */
+    fun getOffsetForPosition(position: PxPosition): Int {
+        assertNeedLayout()
+        val paragraphIndex = when {
+            position.y.value <= 0f -> 0
+            position.y.value >= height -> paragraphInfoList.lastIndex
+            else -> findParagraphByY(paragraphInfoList, position.y)
+        }
+        return with(paragraphInfoList[paragraphIndex]) {
+            if (length == 0) {
+                max(0, startIndex - 1)
+            } else {
+                paragraph.getOffsetForPosition(position.toLocal()).toGlobalIndex()
+            }
+        }
+    }
+
+    /**
+     * Returns the bounding box as Rect of the character for given character offset. Rect
+     * includes the top, bottom, left and right of a character.
+     */
+    fun getBoundingBox(offset: Int): Rect {
+        assertNeedLayout()
+        assertIndexInRange(offset)
+
+        val paragraphIndex = findParagraphByIndex(paragraphInfoList, offset)
+        return with(paragraphInfoList[paragraphIndex]) {
+            val localOffset = offset.toLocalIndex()
+            paragraph.getBoundingBox(localOffset).toGlobal()
+        }
+    }
+
+    /** Get the primary horizontal position for the specified text offset. */
+    fun getPrimaryHorizontal(offset: Int): Float {
+        assertNeedLayout()
+        if (offset !in 0..annotatedString.text.length) {
+            throw AssertionError("offset($offset) is out of bounds " +
+                    "(0,${annotatedString.text.length}")
+        }
+
+        val paragraphIndex = if (offset == annotatedString.text.length) {
+            paragraphInfoList.lastIndex
+        } else {
+            findParagraphByIndex(paragraphInfoList, offset)
+        }
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getPrimaryHorizontal(offset.toLocalIndex())
+        }
+    }
+
+    /**
+     * Returns the TextRange of the word at the given character offset. Characters not
+     * part of a word, such as spaces, symbols, and punctuation, have word breaks
+     * on both sides. In such cases, this method will return TextRange(offset, offset+1).
+     * Word boundaries are defined more precisely in Unicode Standard Annex #29
+     * http://www.unicode.org/reports/tr29/#Word_Boundaries
+     */
+    fun getWordBoundary(offset: Int): TextRange {
+        assertNeedLayout()
+        assertIndexInRange(offset)
+
+        val paragraphIndex = findParagraphByIndex(paragraphInfoList, offset)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getWordBoundary(offset.toLocalIndex()).toGlobal()
+        }
+    }
+
+    /** Returns rectangle of the cursor area. */
+    fun getCursorRect(offset: Int): Rect {
+        assertNeedLayout()
+        if (offset !in 0..annotatedString.text.length) {
+            throw AssertionError("offset($offset) is out of bounds " +
+                    "(0,${annotatedString.text.length}")
+        }
+
+        val paragraphIndex = if (offset == annotatedString.text.length) {
+            paragraphInfoList.lastIndex
+        } else {
+            findParagraphByIndex(paragraphInfoList, offset)
+        }
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getCursorRect(offset.toLocalIndex()).toGlobal()
+        }
+    }
+
+    /**
+     * Returns the line number on which the specified text offset appears.
+     * If you ask for a position before 0, you get 0; if you ask for a position
+     * beyond the end of the text, you get the last line.
+     */
+    fun getLineForOffset(offset: Int): Int {
+        assertNeedLayout()
+        assertIndexInRange(offset)
+
+        val paragraphIndex = findParagraphByIndex(paragraphInfoList, offset)
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineForOffset(offset.toLocalIndex()).toGlobalLineIndex()
+        }
+    }
+
+    /** Returns the left x Coordinate of the given line. */
+    fun getLineLeft(lineIndex: Int): Float {
+        assertNeedLayout()
+        assertLineIndexInRange(lineIndex)
+
+        val paragraphIndex = findParagraphByLineIndex(paragraphInfoList, lineIndex)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineLeft(lineIndex.toLocalLineIndex())
+        }
+    }
+
+    /** Returns the right x Coordinate of the given line. */
+    fun getLineRight(lineIndex: Int): Float {
+        assertNeedLayout()
+        assertLineIndexInRange(lineIndex)
+
+        val paragraphIndex = findParagraphByLineIndex(paragraphInfoList, lineIndex)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineRight(lineIndex.toLocalLineIndex())
+        }
+    }
+
+    /** Returns the bottom y coordinate of the given line. */
+    fun getLineBottom(lineIndex: Int): Float {
+        assertNeedLayout()
+        assertLineIndexInRange(lineIndex)
+
+        val paragraphIndex = findParagraphByLineIndex(paragraphInfoList, lineIndex)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineBottom(lineIndex.toLocalLineIndex())
+        }
+    }
+
+    /** Returns the height of the given line. */
+    fun getLineHeight(lineIndex: Int): Float {
+        assertNeedLayout()
+        assertLineIndexInRange(lineIndex)
+
+        val paragraphIndex = findParagraphByLineIndex(paragraphInfoList, lineIndex)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineHeight(lineIndex.toLocalLineIndex())
+        }
+    }
+
+    /** Returns the width of the given line. */
+    fun getLineWidth(lineIndex: Int): Float {
+        assertNeedLayout()
+        assertLineIndexInRange(lineIndex)
+
+        val paragraphIndex = findParagraphByLineIndex(paragraphInfoList, lineIndex)
+
+        return with(paragraphInfoList[paragraphIndex]) {
+            paragraph.getLineWidth(lineIndex.toLocalLineIndex())
+        }
+    }
+
+    private fun assertNeedLayout() {
+        if (needLayout) {
+            throw IllegalStateException("")
+        }
+    }
+
+    private fun assertIndexInRange(offset: Int) {
+        if (offset !in (0 until annotatedString.text.length)) {
+            throw IndexOutOfBoundsException("offset($offset) is out of bounds" +
+                    " [0, ${annotatedString.text.length})")
+        }
+    }
+
+    private fun assertLineIndexInRange(lineIndex: Int) {
+        if (lineIndex !in (0 until lineCount)) {
+            throw IndexOutOfBoundsException("lineIndex($lineIndex) is out of bounds" +
+                    " [0, $lineIndex)")
+        }
+    }
+}
+
+/**
+ * Given an character index of [MultiParagraph.annotatedString], find the corresponding
+ * [ParagraphInfo] which covers the provided index.
+ *
+ * @param paragraphInfoList The list of [ParagraphInfo] containing the information of each
+ *  paragraph in the [MultiParagraph].
+ * @param index The target index in the [MultiParagraph]. It should be in the range of
+ *  [0, text.length)
+ * @return The index of the target [ParagraphInfo] in [paragraphInfoList].
+ */
+private fun findParagraphByIndex(paragraphInfoList: List<ParagraphInfo>, index: Int): Int {
+    return paragraphInfoList.binarySearch { paragraphInfo ->
+        when {
+            paragraphInfo.startIndex > index -> 1
+            paragraphInfo.endIndex <= index -> -1
+            else -> 0
+        }
+    }
+}
+
+/**
+ * Given the y graphical position relative to this [MultiParagraph], find the index of the
+ * corresponding [ParagraphInfo] which occupies the provided position.
+ *
+ * @param paragraphInfoList The list of [ParagraphInfo] containing the information of each
+ *  paragraph in the [MultiParagraph].
+ * @param y The y coordinate position relative to the [MultiParagraph]. It should be in the range
+ *  of [0, [MultiParagraph.height]].
+ * @return The index of the target [ParagraphInfo] in [paragraphInfoList].
+ */
+private fun findParagraphByY(paragraphInfoList: List<ParagraphInfo>, y: Px): Int {
+    return paragraphInfoList.binarySearch { paragraphInfo ->
+        when {
+            paragraphInfo.top > y -> 1
+            paragraphInfo.bottom <= y -> -1
+            else -> 0
+        }
+    }
+}
+
+/**
+ * Given an line index in [MultiParagraph], find the corresponding [ParagraphInfo] which
+ * covers the provided line index.
+ *
+ * @param paragraphInfoList The list of [ParagraphInfo] containing the information of each
+ *  paragraph in the [MultiParagraph].
+ * @param lineIndex The target line index in the [MultiParagraph], it should be in the range of
+ *  [0, [MultiParagraph.lineCount])
+ * @return The index of the target [ParagraphInfo] in [paragraphInfoList].
+ */
+private fun findParagraphByLineIndex(paragraphInfoList: List<ParagraphInfo>, lineIndex: Int): Int {
+    return paragraphInfoList.binarySearch { paragraphInfo ->
+        when {
+            paragraphInfo.startLineIndex > lineIndex -> 1
+            paragraphInfo.endLineIndex <= lineIndex -> -1
+            else -> 0
+        }
+    }
+}
+
+/**
+ * A helper function used to determine the paragraph boundaries in [MultiParagraph].
+ *
+ * It reads paragraph information from [AnnotatedString.paragraphStyles] where only some parts of
+ * text has [ParagraphStyle] specified, and unspecified parts(gaps between specified paragraphs)
+ * are considered as default paragraph with default [ParagraphStyle].
+ * For example, the following string with a specified paragraph denoted by "[]"
+ *      "Hello WorldHi!"
+ *      [          ]
+ * The result paragraphs are "Hello World" and "Hi!".
+ *
+ * @param annotatedString: The [AnnotatedString] on which the paragraph boundaries need to be
+ *  determined.
+ * @param defaultParagraphStyle The default [ParagraphStyle]. It's used for both unspecified
+ *  default paragraphs and specified paragraph. When a specified paragraph's [ParagraphStyle] has
+ *  a null attribute, the default one will be used instead.
+ */
+internal fun fillInParagraphRanges(
+    annotatedString: AnnotatedString,
+    defaultParagraphStyle: ParagraphStyle
+): List<AnnotatedString.Item<ParagraphStyle>> {
+    val length = annotatedString.text.length
+    val paragraphStyles = annotatedString.paragraphStyles
+
+    var lastOffset = 0
+    val result = mutableListOf<AnnotatedString.Item<ParagraphStyle>>()
+    for ((style, start, end) in paragraphStyles) {
+        if (start != lastOffset) {
+            result.add(AnnotatedString.Item(defaultParagraphStyle, lastOffset, start))
+        }
+        result.add(AnnotatedString.Item(defaultParagraphStyle.merge(style), start, end))
+        lastOffset = end
+    }
+    if (lastOffset != length) {
+        result.add(AnnotatedString.Item(defaultParagraphStyle, lastOffset, length))
+    }
+    // This is a corner case where annotatedString is an empty string without any ParagraphStyle.
+    // In this case, a dummy ParagraphStyle is created.
+    if (result.isEmpty()) {
+        result.add(AnnotatedString.Item(defaultParagraphStyle, 0, 0))
+    }
+    return result
+}
+
+/**
+ * Helper function used to find the [TextStyle]s in the given paragraph range and also convert the
+ * range of those [TextStyle]s to paragraph local range.
+ *
+ * @param start The start index of the paragraph range, inclusive.
+ * @param end The end index of the paragraph range, exclusive.
+ * @return The list of converted [TextStyle]s in the given paragraph range.
+ */
+private fun AnnotatedString.getLocalStyles(
+    start: Int,
+    end: Int
+): List<AnnotatedString.Item<TextStyle>> {
+    if (start == end) {
+        return listOf()
+    }
+    // If the given range covers the whole AnnotatedString, return textStyles without conversion.
+    if (start == 0 && end >= this.text.length) {
+        return textStyles
+    }
+    return textStyles.filter { it.start < end && it.end > start }
+        .map {
+            AnnotatedString.Item(
+                it.style,
+                it.start.coerceIn(start, end) - start,
+                it.end.coerceIn(start, end) - start
+            )
+        }
+}
+
+/**
+ * This is a helper data structure to store the information of a single [Paragraph] in an
+ * [MultiParagraph]. It's mainly used to convert a global index, lineNumber and [Offset] to the
+ * local ones inside the [paragraph], and vice versa.
+ *
+ * @param paragraph The [Paragraph] object corresponding to this [ParagraphInfo].
+ * @param startIndex The start index of this paragraph in the parent [MultiParagraph], inclusive.
+ * @param endIndex The end index of this paragraph in the parent [MultiParagraph], exclusive.
+ * @param startLineIndex The start line index of this paragraph in the parent [MultiParagraph],
+ *  inclusive.
+ * @param endLineIndex The end line index of this paragraph in the parent [MultiParagraph],
+ *  exclusive.
+ * @param top The top position of the [paragraph] relative to the parent [MultiParagraph].
+ * @param bottom The bottom position of the [paragraph] relative to the parent [MultiParagraph].
+ */
+internal data class ParagraphInfo(
+    val paragraph: Paragraph,
+    val startIndex: Int,
+    val endIndex: Int,
+    var startLineIndex: Int = -1,
+    var endLineIndex: Int = -1,
+    var top: Px = (-1).px,
+    var bottom: Px = (-1).px
+) {
+
+    /**
+     * The length of the text in the covered by this paragraph.
+     */
+    val length
+        get() = endIndex - startIndex
+
+    /**
+     * Convert an index in the parent [MultiParagraph] to the local index in the [paragraph].
+     */
+    fun Int.toLocalIndex(): Int {
+        return this.coerceIn(startIndex, endIndex) - startIndex
+    }
+
+    /**
+     * Convert a local index in the [paragraph] to the global index in the parent [MultiParagraph].
+     */
+    fun Int.toGlobalIndex(): Int {
+        return this + startIndex
+    }
+
+    /**
+     * Convert a line index in the parent [MultiParagraph] to the local line index in the
+     * [paragraph].
+     *
+     */
+    fun Int.toLocalLineIndex(): Int {
+        return this - startLineIndex
+    }
+
+    /**
+     * Convert a local line index in the [paragraph] to the global line index in the parent
+     * [MultiParagraph].
+     */
+    fun Int.toGlobalLineIndex(): Int {
+        return this + startLineIndex
+    }
+
+    /**
+     * Convert a [PxPosition] relative to the parent [MultiParagraph] to the local [PxPosition]
+     * relative to the [paragraph].
+     */
+    fun PxPosition.toLocal(): PxPosition {
+        return copy(y = y - top)
+    }
+
+    /**
+     * Convert a [Rect] relative to the [paragraph] to the [Rect] relative to the parent
+     * [MultiParagraph].
+     */
+    fun Rect.toGlobal(): Rect {
+        return shift(Offset(dx = 0f, dy = this@ParagraphInfo.top.value))
+    }
+
+    /**
+     * Convert a [Path] relative to the [paragraph] to the [Path] relative to the parent
+     * [MultiParagraph].
+     *
+     * Notice that this function changes the input value.
+     */
+    fun Path.toGlobal(): Path {
+        shift(Offset(dx = 0f, dy = top.value))
+        return this
+    }
+
+    /**
+     * Convert a [TextRange] in to the [paragraph] to the [TextRange] in the parent
+     * [MultiParagraph].
+     */
+    fun TextRange.toGlobal(): TextRange {
+        return TextRange(start = start.toGlobalIndex(), end = end.toGlobalIndex())
+    }
+}
\ No newline at end of file
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 dd7c248..4fd974e 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
@@ -47,19 +47,20 @@
         }
     }
     // TODO(siyamed) uncomment
-//    /**
-//     * Returns a new paragraph style that is a combination of this style and the given [other] style.
-//     *
-//     * If the given paragraph style is null, returns this paragraph style.
-//     */
-//    fun merge(other: ParagraphStyle? = null): ParagraphStyle {
-//        if (other == null) return this
-//
-//        return ParagraphStyle(
-//            lineHeight = other.lineHeight ?: this.lineHeight,
-//            textIndent = other.textIndent ?: this.textIndent,
-//            textAlign = other.textAlign ?: this.textAlign,
-//            textDirection = other.textDirection ?: this.textDirection
-//        )
-//    }
+    /**
+     * Returns a new paragraph style that is a combination of this style and the given [other]
+     * style.
+     *
+     * If the given paragraph style is null, returns this paragraph style.
+     */
+    fun merge(other: ParagraphStyle? = null): ParagraphStyle {
+        if (other == null) return this
+
+        return ParagraphStyle(
+            lineHeight = other.lineHeight ?: this.lineHeight,
+            textIndent = other.textIndent ?: this.textIndent,
+            textAlign = other.textAlign ?: this.textAlign,
+            textDirection = other.textDirection ?: this.textDirection
+        )
+    }
 }
\ No newline at end of file
diff --git a/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt b/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
index 7880c2d..0a5d93a 100644
--- a/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
+++ b/ui/ui-text/src/main/java/androidx/ui/text/TextPainter.kt
@@ -118,7 +118,7 @@
     }
 
     @VisibleForTesting
-    internal var paragraph: Paragraph? = null
+    internal var multiParagraph: MultiParagraph? = null
         private set
 
     @VisibleForTesting
@@ -143,7 +143,7 @@
         set(value) {
             if (field == value) return
             field = value
-            paragraph = null
+            multiParagraph = null
             needsLayout = true
         }
 
@@ -219,7 +219,7 @@
     val minIntrinsicWidth: Float
         get() {
             assertNeedsLayout("minIntrinsicWidth")
-            return applyFloatingPointHack(paragraph!!.minIntrinsicWidth)
+            return applyFloatingPointHack(multiParagraph!!.minIntrinsicWidth)
         }
 
     /**
@@ -230,7 +230,7 @@
     val maxIntrinsicWidth: Float
         get() {
             assertNeedsLayout("maxIntrinsicWidth")
-            return applyFloatingPointHack(paragraph!!.maxIntrinsicWidth)
+            return applyFloatingPointHack(multiParagraph!!.maxIntrinsicWidth)
         }
 
     /**
@@ -281,7 +281,7 @@
     val didExceedMaxLines: Boolean
         get() {
             assertNeedsLayout("didExceedMaxLines")
-            return paragraph!!.didExceedMaxLines
+            return multiParagraph!!.didExceedMaxLines
         }
 
     /**
@@ -308,25 +308,25 @@
 
         if (!needsLayout && minWidth == lastMinWidth && finalMaxWidth == lastMaxWidth) return
         needsLayout = false
-        if (paragraph == null) {
-            paragraph = Paragraph(
-                text = text!!.text,
-                style = createTextStyle(),
-                paragraphStyle = createParagraphStyle(),
-                textStyles = text!!.textStyles,
-                maxLines = maxLines,
-                ellipsis = isEllipsis,
-                density = density,
-                resourceLoader = resourceLoader
+
+        if (multiParagraph == null) {
+            multiParagraph = MultiParagraph(
+                text!!,
+                createTextStyle(),
+                paragraphStyle ?: ParagraphStyle(),
+                maxLines,
+                isEllipsis,
+                density,
+                resourceLoader
             )
         }
         lastMinWidth = minWidth
         lastMaxWidth = finalMaxWidth
-        paragraph!!.layout(ParagraphConstraints(width = finalMaxWidth))
+        multiParagraph!!.layout(ParagraphConstraints(width = finalMaxWidth))
         if (minWidth != finalMaxWidth) {
             val newWidth = maxIntrinsicWidth.coerceIn(minWidth, finalMaxWidth)
-            if (newWidth != paragraph!!.width) {
-                paragraph!!.layout(ParagraphConstraints(width = newWidth))
+            if (newWidth != multiParagraph!!.width) {
+                multiParagraph!!.layout(ParagraphConstraints(width = newWidth))
             }
         }
     }
@@ -336,11 +336,11 @@
 
         val didOverflowHeight = didExceedMaxLines
         size = constraints.constrain(
-            IntPxSize(paragraph!!.width.px.round(), paragraph!!.height.px.round())
+            IntPxSize(multiParagraph!!.width.px.round(), multiParagraph!!.height.px.round())
         ).let {
             Size(it.width.value.toFloat(), it.height.value.toFloat())
         }
-        val didOverflowWidth = size.width < paragraph!!.width
+        val didOverflowWidth = size.width < multiParagraph!!.width
         // TODO(abarth): We're only measuring the sizes of the line boxes here. If
         // the glyphs draw outside the line boxes, we might think that there isn't
         // visual overflow when there actually is visual overflow. This can become
@@ -356,8 +356,8 @@
                 resourceLoader = resourceLoader
             )
             fadeSizePainter.layoutText()
-            val fadeWidth = fadeSizePainter.paragraph!!.width
-            val fadeHeight = fadeSizePainter.paragraph!!.height
+            val fadeWidth = fadeSizePainter.multiParagraph!!.width
+            val fadeHeight = fadeSizePainter.multiParagraph!!.height
             if (didOverflowWidth) {
                 val (fadeStart, fadeEnd) = if (textDirection == TextDirection.Rtl) {
                     Pair(fadeWidth, 0.0f)
@@ -426,7 +426,8 @@
             }
             canvas.clipRect(bounds)
         }
-        paragraph!!.paint(canvas)
+
+        multiParagraph!!.paint(canvas)
         if (hasVisualOverflow) {
             if (overflowShader != null) {
                 val bounds = Rect.fromLTWH(0f, 0f, size.width, size.height)
@@ -452,7 +453,7 @@
     fun paintBackground(start: Int, end: Int, color: Color, canvas: Canvas) {
         assert(!needsLayout)
         if (start == end) return
-        val selectionPath = paragraph!!.getPathForRange(start, end)
+        val selectionPath = multiParagraph!!.getPathForRange(start, end)
         // TODO(haoyuchang): check if move this paint to parameter is better
         canvas.drawPath(selectionPath, Paint().apply { this.color = color })
     }
@@ -467,7 +468,7 @@
      */
     fun paintCursor(offset: Int, canvas: Canvas) {
         assert(!needsLayout)
-        val cursorRect = paragraph!!.getCursorRect(offset)
+        val cursorRect = multiParagraph!!.getCursorRect(offset)
         canvas.drawRect(cursorRect, Paint().apply { this.color = Color.Black })
     }
 
@@ -479,7 +480,7 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     fun getLineBottom(lineIndex: Int): Float {
         assert(!needsLayout)
-        return paragraph!!.getLineBottom(lineIndex)
+        return multiParagraph!!.getLineBottom(lineIndex)
     }
 
     /**
@@ -492,7 +493,7 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     fun getLineForOffset(offset: Int): Int {
         assert(!needsLayout)
-        return paragraph!!.getLineForOffset(offset)
+        return multiParagraph!!.getLineForOffset(offset)
     }
 
     /**
@@ -503,13 +504,13 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     fun getPrimaryHorizontal(offset: Int): Float {
         assert(!needsLayout)
-        return paragraph!!.getPrimaryHorizontal(offset)
+        return multiParagraph!!.getPrimaryHorizontal(offset)
     }
 
     /** Returns the character offset closest to the given graphical position. */
     fun getOffsetForPosition(position: PxPosition): Int {
         assert(!needsLayout)
-        return paragraph!!.getOffsetForPosition(position)
+        return multiParagraph!!.getOffsetForPosition(position)
     }
 
     /**
@@ -523,7 +524,7 @@
     @RestrictTo(RestrictTo.Scope.LIBRARY)
     fun getBoundingBox(offset: Int): Rect {
         assert(!needsLayout)
-        return paragraph!!.getBoundingBox(offset)
+        return multiParagraph!!.getBoundingBox(offset)
     }
 
     /**
@@ -536,6 +537,6 @@
      */
     fun getWordBoundary(offset: Int): TextRange {
         assert(!needsLayout)
-        return paragraph!!.getWordBoundary(offset)
+        return multiParagraph!!.getWordBoundary(offset)
     }
 }
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/MultiParagraphTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/MultiParagraphTest.kt
new file mode 100644
index 0000000..ce472ad
--- /dev/null
+++ b/ui/ui-text/src/test/java/androidx/ui/text/MultiParagraphTest.kt
@@ -0,0 +1,107 @@
+/*
+ * 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.text
+
+import androidx.ui.text.style.TextAlign
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@RunWith(JUnit4::class)
+class MultiParagraphTest {
+    @Test
+    fun `test fillInParagraphRanges`() {
+        val text = "Hello World"
+        val paragraphStyle = ParagraphStyle(textAlign = TextAlign.Center)
+        val paragraphStyles = listOf(AnnotatedString.Item(paragraphStyle, 0, 5))
+        val annotatedString = AnnotatedString(text = text, paragraphStyles = paragraphStyles)
+        val defaultParagraphStyle = ParagraphStyle(lineHeight = 2.0f)
+
+        val paragraphs = fillInParagraphRanges(annotatedString, defaultParagraphStyle)
+
+        assertThat(paragraphs.size).isEqualTo(2)
+
+        assertThat(paragraphs[0].style).isEqualTo(defaultParagraphStyle.merge(paragraphStyle))
+        assertThat(paragraphs[0].start).isEqualTo(0)
+        assertThat(paragraphs[0].end).isEqualTo(5)
+
+        assertThat(paragraphs[1].style).isEqualTo(defaultParagraphStyle)
+        assertThat(paragraphs[1].start).isEqualTo(5)
+        assertThat(paragraphs[1].end).isEqualTo(text.length)
+    }
+
+    @Test
+    fun `test fillInParagraphRanges only string`() {
+        val text = "Hello World"
+        val annotatedString = AnnotatedString(text = text)
+        val defaultParagraphStyle = ParagraphStyle(lineHeight = 2.0f)
+
+        val paragraphs = fillInParagraphRanges(annotatedString, defaultParagraphStyle)
+
+        assertThat(paragraphs.size).isEqualTo(1)
+
+        assertThat(paragraphs[0].style).isEqualTo(defaultParagraphStyle)
+        assertThat(paragraphs[0].start).isEqualTo(0)
+        assertThat(paragraphs[0].end).isEqualTo(text.length)
+    }
+
+    @Test
+    fun `test fillInParagraphRanges empty string`() {
+        val text = ""
+        val annotatedString = AnnotatedString(text = text)
+        val defaultParagraphStyle = ParagraphStyle(lineHeight = 2.0f)
+
+        val paragraphs = fillInParagraphRanges(annotatedString, defaultParagraphStyle)
+
+        assertThat(paragraphs.size).isEqualTo(1)
+
+        assertThat(paragraphs[0].style).isEqualTo(defaultParagraphStyle)
+        assertThat(paragraphs[0].start).isEqualTo(0)
+        assertThat(paragraphs[0].end).isEqualTo(text.length)
+    }
+
+    @Test
+    fun `test fillInParagraphRanges with newLine`() {
+        val text = "Hello\nWorld"
+        val annotatedString = AnnotatedString(text = text)
+        val defaultParagraphStyle = ParagraphStyle(lineHeight = 2.0f)
+
+        val paragraphs = fillInParagraphRanges(annotatedString, defaultParagraphStyle)
+
+        assertThat(paragraphs.size).isEqualTo(1)
+
+        assertThat(paragraphs[0].style).isEqualTo(defaultParagraphStyle)
+        assertThat(paragraphs[0].start).isEqualTo(0)
+        assertThat(paragraphs[0].end).isEqualTo(text.length)
+    }
+
+    @Test
+    fun `test fillInParagraphRanges with only lineFeed`() {
+        val text = "\n"
+        val annotatedString = AnnotatedString(text = text)
+        val defaultParagraphStyle = ParagraphStyle(lineHeight = 2.0f)
+
+        val paragraphs = fillInParagraphRanges(annotatedString, defaultParagraphStyle)
+
+        assertThat(paragraphs.size).isEqualTo(1)
+
+        assertThat(paragraphs[0].style).isEqualTo(defaultParagraphStyle)
+        assertThat(paragraphs[0].start).isEqualTo(0)
+        assertThat(paragraphs[0].end).isEqualTo(1)
+    }
+}
\ No newline at end of file
diff --git a/ui/ui-text/src/test/java/androidx/ui/text/TextPainterTest.kt b/ui/ui-text/src/test/java/androidx/ui/text/TextPainterTest.kt
index 6c07a79..5dcae69 100644
--- a/ui/ui-text/src/test/java/androidx/ui/text/TextPainterTest.kt
+++ b/ui/ui-text/src/test/java/androidx/ui/text/TextPainterTest.kt
@@ -127,7 +127,7 @@
         textPainter.text = text
 
         assertThat(textPainter.text).isEqualTo(text)
-        assertThat(textPainter.paragraph).isNull()
+        assertThat(textPainter.multiParagraph).isNull()
         assertThat(textPainter.needsLayout).isTrue()
     }
 
diff --git a/ui/ui-vector/OWNERS b/ui/ui-vector/OWNERS
new file mode 100644
index 0000000..c3a259b
--- /dev/null
+++ b/ui/ui-vector/OWNERS
@@ -0,0 +1,13 @@
+pavlis@google.com
+adamp@google.com
+mount@google.com
+popam@google.com
+andreykulikov@google.com
+ryanmentley@google.com
+shepshapard@google.com
+njawad@google.com
+haoyuchang@google.com
+nona@google.com
+siyamed@google.com
+qqd@google.com
+sumir@google.com
\ No newline at end of file
diff --git a/ui/ui-vector/build.gradle b/ui/ui-vector/build.gradle
new file mode 100644
index 0000000..014b6cb
--- /dev/null
+++ b/ui/ui-vector/build.gradle
@@ -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.
+ */
+
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.Publish
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+import static androidx.build.dependencies.DependenciesKt.*
+
+plugins {
+    id("AndroidXPlugin")
+    id("com.android.library")
+    id("AndroidXUiPlugin")
+    id("org.jetbrains.kotlin.android")
+}
+
+dependencies {
+    kotlinPlugin project(path: ":compose:compose-compiler", configuration: "embeddablePlugin")
+
+    implementation project(':ui:ui-core')
+    implementation "androidx.collection:collection:1.0.0"
+    implementation project(":compose:compose-runtime")
+    implementation (KOTLIN_COMPOSE_STDLIB)
+
+    // TODO: Non-Kotlin dependency, move to Android-specific code
+//    implementation "androidx.collection:collection:1.0.0-alpha01"
+    // TODO: Non-Kotlin dependency, move to Android-specific code
+    implementation "androidx.core:core:1.0.0"
+}
+
+androidx {
+    name = "AndroidX UI Vector"
+    publish = Publish.SNAPSHOT_AND_RELEASE
+    mavenVersion = LibraryVersions.UI
+    mavenGroup = LibraryGroups.UI
+    inceptionYear = "2019"
+    description = "AndroidX UI Vector"
+}
+
+tasks.withType(KotlinCompile).configureEach {
+    kotlinOptions {
+        // TODO(njawad): Temporary disabled, make it true when IR bug b/129076229 is fixed.
+        useIR = false
+    }
+}
diff --git a/ui/ui-vector/src/androidTest/AndroidManifest.xml b/ui/ui-vector/src/androidTest/AndroidManifest.xml
new file mode 100644
index 0000000..d974f89
--- /dev/null
+++ b/ui/ui-vector/src/androidTest/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest package="androidx.ui.vector" xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
+
diff --git a/ui/ui-vector/src/main/AndroidManifest.xml b/ui/ui-vector/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..d974f89
--- /dev/null
+++ b/ui/ui-vector/src/main/AndroidManifest.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2019 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<manifest package="androidx.ui.vector" xmlns:android="http://schemas.android.com/apk/res/android">
+</manifest>
+
diff --git a/ui/ui-vector/src/main/java/androidx/ui/vector/VectorComposeNonIR.kt b/ui/ui-vector/src/main/java/androidx/ui/vector/VectorComposeNonIR.kt
new file mode 100644
index 0000000..c9fb0acd
--- /dev/null
+++ b/ui/ui-vector/src/main/java/androidx/ui/vector/VectorComposeNonIR.kt
@@ -0,0 +1,214 @@
+/*
+ * 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.vector
+
+import androidx.compose.Applier
+import androidx.compose.ApplyAdapter
+import androidx.compose.Component
+import androidx.compose.Composable
+import androidx.compose.Composer
+import androidx.compose.ComposerUpdater
+import androidx.compose.CompositionContext
+import androidx.compose.CompositionReference
+import androidx.compose.Effect
+import androidx.compose.Recomposer
+import androidx.compose.SlotTable
+import androidx.compose.ViewValidator
+import androidx.compose.cache
+import androidx.ui.graphics.vectorgraphics.GroupComponent
+import androidx.ui.graphics.vectorgraphics.VNode
+import androidx.ui.graphics.vectorgraphics.VectorComponent
+import java.util.WeakHashMap
+
+private val VectorTreeRoots = WeakHashMap<VectorComponent, VectorTree>()
+
+class VectorScope(val composer: VectorComposition)
+
+private fun obtainVectorTree(container: VectorComponent): VectorTree {
+    var vectorTree = VectorTreeRoots[container]
+    if (vectorTree == null) {
+        vectorTree = VectorTree()
+        VectorTreeRoots[container] = vectorTree
+    }
+    return vectorTree
+}
+
+fun composeVector(
+    container: VectorComponent,
+    parent: CompositionReference? = null,
+    composable: @Composable() VectorScope.() -> Unit
+) {
+    var root = VectorTreeRoots[container]
+    if (root == null) {
+        lateinit var composer: VectorComposer
+        root = obtainVectorTree(container)
+        root.context = CompositionContext.prepare(root, parent) {
+            VectorComposer(container.root, this).also { composer = it }
+        }
+        root.scope = VectorScope(VectorComposition(composer))
+    }
+    root.composable = composable
+    root.context.compose()
+}
+
+class VectorComposer(
+    val root: VNode,
+    recomposer: Recomposer
+) : Composer<VNode>(SlotTable(), Applier(root, VectorApplyAdapter()), recomposer)
+
+fun disposeVector(container: VectorComponent, parent: CompositionReference? = null) {
+    composeVector(container, parent) {}
+    VectorTreeRoots.remove(container)
+}
+
+private class VectorTree : Component() {
+
+    lateinit var scope: VectorScope
+    lateinit var composable: @Composable() VectorScope.() -> Unit
+    lateinit var context: CompositionContext
+
+    override fun compose() {
+        with(context.composer) {
+            startGroup(0) // TODO (njawad) what key should be used here?
+            scope.composable()
+            endGroup()
+        }
+    }
+}
+
+@PublishedApi
+internal val VectorGroupKey = Object()
+
+internal class VectorApplyAdapter : ApplyAdapter<VNode> {
+    override fun VNode.start(instance: VNode) {
+        // NO-OP
+    }
+
+    override fun VNode.insertAt(index: Int, instance: VNode) {
+        obtainGroup().insertAt(index, instance)
+    }
+
+    override fun VNode.removeAt(index: Int, count: Int) {
+        obtainGroup().remove(index, count)
+    }
+
+    override fun VNode.move(from: Int, to: Int, count: Int) {
+        obtainGroup().move(from, to, count)
+    }
+
+    override fun VNode.end(instance: VNode, parent: VNode) {
+        // NO-OP
+    }
+
+    fun VNode.obtainGroup(): GroupComponent {
+        return when (this) {
+            is GroupComponent -> this
+            else -> throw IllegalArgumentException("Cannot only insert VNode into Group")
+        }
+    }
+}
+
+typealias VectorUpdater<T> = ComposerUpdater<VNode, T>
+
+class VectorComposition(val composer: VectorComposer) {
+    @Suppress("NOTHING_TO_INLINE")
+    inline operator fun <V> Effect<V>.unaryPlus(): V = resolve(this@VectorComposition.composer)
+
+    inline fun <T: VNode> emit(
+        key: Any,
+        /*crossinline*/
+        ctor: () -> T,
+        update: VectorUpdater<VNode>.() -> Unit
+    ) = with(composer) {
+        startNode(key)
+
+        @Suppress("UNCHECKED_CAST")
+        val node = if (inserting) {
+            ctor().also {
+                emitNode(it)
+            }
+        } else {
+            useNode()
+        }
+
+        VectorUpdater(this, node).update()
+        endNode()
+    }
+
+    inline fun emit(
+        key: Any,
+        /*crossinline*/
+        ctor: () -> GroupComponent,
+        update: VectorUpdater<GroupComponent>.() -> Unit,
+        children: () -> Unit
+    ) = with(composer) {
+        startNode(key)
+
+        @Suppress("UNCHECKED_CAST")
+        val node = if (inserting) {
+            ctor().also {
+                emitNode(it)
+            }
+        } else {
+            useNode() as GroupComponent
+        }
+
+        VectorUpdater(this, node).update()
+        children()
+        endNode()
+    }
+
+    @Suppress("NOTHING_TO_INLINE")
+    inline fun joinKey(left: Any, right: Any?): Any = composer.joinKey(left, right)
+
+    inline fun call(
+        key: Any,
+        /*crossinline*/
+        invalid: ViewValidator.() -> Boolean,
+        block: () -> Unit
+    ) = with(composer) {
+        startGroup(key)
+        if (ViewValidator(composer).invalid() || inserting) {
+            startGroup(0)
+            block()
+            endGroup()
+        } else {
+            skipGroup(0)
+        }
+        endGroup()
+    }
+
+    inline fun <T> call(
+        key: Any,
+        /*crossinline*/
+        ctor: () -> T,
+        /*crossinline*/
+        invalid: ViewValidator.(f: T) -> Boolean,
+        block: (f: T) -> Unit
+    ) = with(composer) {
+        startGroup(key)
+        val f = cache(true, ctor)
+        if (ViewValidator(this).invalid(f) || inserting) {
+            startGroup(0)
+            block(f)
+            endGroup()
+        } else {
+            skipGroup(0)
+        }
+        endGroup()
+    }
+}
\ No newline at end of file
diff --git a/viewpager/build.gradle b/viewpager/build.gradle
index f1f7e65..2559de8 100644
--- a/viewpager/build.gradle
+++ b/viewpager/build.gradle
@@ -17,7 +17,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     api(project(":customview"))
 
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/viewpager2/build.gradle b/viewpager2/build.gradle
index 29ea26d..9de6aa7 100644
--- a/viewpager2/build.gradle
+++ b/viewpager2/build.gradle
@@ -27,7 +27,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    implementation("androidx.core:core:1.1.0")
+    implementation("androidx.core:core:1.1.0-rc01")
     api("androidx.fragment:fragment:1.1.0-rc01")
     api("androidx.recyclerview:recyclerview:1.1.0-beta01")
     implementation("androidx.collection:collection:1.1.0")
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
new file mode 100644
index 0000000..a1bc911
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/AdapterDataSetChangeWhileSmoothScrollTest.kt
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.viewpager2.widget
+
+import androidx.test.filters.LargeTest
+import androidx.testutils.LocaleTestUtils
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Event.MarkerEvent
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Event.OnPageScrollStateChangedEvent
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Event.OnPageScrolledEvent
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Event.OnPageSelectedEvent
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Modification.REMOVE_FIRST_VISIBLE
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Modification.SHIFT_FIRST_VISIBLE
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Modification.SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Modification.SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST_AND_LAST
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.Modification.SHIFT_FIRST_VISIBLE_THEN_REMOVE_LAST
+import androidx.viewpager2.widget.AdapterDataSetChangeWhileSmoothScrollTest.TestConfig
+import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
+import androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL
+import androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE
+import androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_SETTLING
+import org.hamcrest.CoreMatchers.equalTo
+import org.hamcrest.Matchers.greaterThan
+import org.junit.Assert.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import java.util.concurrent.TimeUnit.SECONDS
+import kotlin.math.roundToInt
+
+/** Number of pages */
+private const val pageCount = 25
+/** Page where VP2 starts */
+private const val initialPage = 0
+/** Page where we smooth scroll to */
+private const val targetPage = 20
+
+/** Id of the mark we make when modifying the dataset */
+private const val modificationMark = 1
+
+/** How many pages from x before x gets bound? */
+private const val bindThreshold = 2
+/** Value between 0 and 1/pageSizePx */
+private const val epsilon = 0.00001f
+
+@RunWith(Parameterized::class)
+@LargeTest
+class AdapterDataSetChangeWhileSmoothScrollTest(private val config: TestConfig) : BaseTest() {
+    data class TestConfig(
+        @ViewPager2.Orientation val orientation: Int,
+        val rtl: Boolean,
+        val targetBound: Boolean,
+        val modification: Modification,
+        val adapterProvider: AdapterProviderForItems,
+        val expectedFinalPage: Int,
+        val expectedFinalPageText: String
+    )
+
+    companion object {
+        @JvmStatic
+        @Parameterized.Parameters(name = "{0}")
+        fun spec(): List<TestConfig> = createTestSet()
+    }
+
+    enum class Modification {
+        SHIFT_FIRST_VISIBLE,
+        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST,
+        SHIFT_FIRST_VISIBLE_THEN_REMOVE_LAST,
+        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST_AND_LAST,
+        REMOVE_FIRST_VISIBLE
+    }
+
+    // start and end of the window of opportunity to modify the dataset
+    private val windowStart = targetPage - bindThreshold - if (config.targetBound) 0 else 1
+    private val windowEnd = targetPage - if (config.targetBound) 1 else bindThreshold
+
+    private lateinit var test: Context
+    private lateinit var dataSet: MutableList<String>
+
+    override fun setUp() {
+        super.setUp()
+        if (config.rtl) {
+            localeUtil.resetLocale()
+            localeUtil.setLocale(LocaleTestUtils.RTL_LANGUAGE)
+        }
+
+        test = setUpTest(config.orientation)
+        activityTestRule.runOnUiThread { test.viewPager.offscreenPageLimit = 1 }
+        dataSet = stringSequence(pageCount).toMutableList()
+        test.setAdapterSync(config.adapterProvider(dataSet))
+    }
+
+    @Test
+    fun test() {
+        tryNTimes(3, resetBlock = { test.resetViewPagerTo(initialPage) }) {
+            // when we are scrolling to the target
+            val recorder = test.viewPager.addNewRecordingCallback()
+            val idleLatch = test.viewPager.addWaitForIdleLatch()
+
+            scrollToTargetUntilWindowStart()
+
+            // and we remove the first visible item
+            test.modifyDataSetSync {
+                verifyWindowOfOpportunity(recorder.scrollEvents.last())
+                recorder.markModification()
+                makeModification()
+            }
+            idleLatch.await(10, SECONDS)
+
+            // then
+            test.assertBasicState(config.expectedFinalPage, config.expectedFinalPageText)
+            recorder.apply {
+                val removeItemMarkIx = markerIx(modificationMark)
+                val expectedSelectEvents = if (targetPage == config.expectedFinalPage) {
+                    listOf(targetPage)
+                } else {
+                    listOf(targetPage, config.expectedFinalPage)
+                }
+                // verify all events
+                assertThat(settlingIx, equalTo(0))
+                assertThat(pageSelectedIx(targetPage), equalTo(1))
+                assertThat(removeItemMarkIx, greaterThan(1))
+                assertThat(idleIx, equalTo(lastIx))
+                assertThat(selectEvents.map { it.position }, equalTo(expectedSelectEvents))
+                assertThat(scrollEventCount, equalTo(eventCount - 3 - expectedSelectEvents.size))
+
+                // verify scroll events _before_ and _after_ the marker
+                val scrollsBeforeMarker = scrollEventsBefore(removeItemMarkIx)
+                val scrollsAfterMarker = scrollEventsAfter(removeItemMarkIx)
+                listOf(scrollsBeforeMarker, scrollsAfterMarker).forEach {
+                    it.assertPositionSorted(SortOrder.ASC)
+                    it.assertOffsetSorted(SortOrder.ASC)
+                    it.assertValueSanity(0, targetPage, test.viewPager.pageSize)
+                }
+                // Only check assertMaxShownPages on scroll events _before_ the marker:
+                //   after the data set change, it can scroll an arbitrary number of pages
+                scrollsBeforeMarker.assertMaxShownPages()
+                // Only check assertLastCorrect on scroll events _after_ the marker:
+                //   the target is not reached before the data set change
+                scrollsAfterMarker.assertLastCorrect(config.expectedFinalPage)
+            }
+        }
+    }
+
+    private fun scrollToTargetUntilWindowStart() {
+        val latch = test.viewPager
+            .addWaitForDistanceToTarget(targetPage, targetPage - windowStart - epsilon)
+        test.runOnUiThreadSync {
+            test.viewPager.setCurrentItem(targetPage, true)
+        }
+        latch.await(2, SECONDS)
+    }
+
+    private fun verifyWindowOfOpportunity(lastScrollEvent: OnPageScrolledEvent) {
+        val lastScrollPosition = lastScrollEvent.let {
+            it.position + it.positionOffset.toDouble()
+        }
+        if (lastScrollPosition >= windowEnd) {
+            throw RetryException("Data set should be modified while scrolling through " +
+                    "($windowStart, $windowEnd), but was modified at $lastScrollPosition")
+        }
+    }
+
+    private fun makeModification() {
+        when (config.modification) {
+            REMOVE_FIRST_VISIBLE -> {
+                removeCurrentPage()
+            }
+            SHIFT_FIRST_VISIBLE -> {
+                shiftCurrentPageToStart()
+            }
+            SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST -> {
+                shiftCurrentPageToStart()
+                removeFirstPages()
+            }
+            SHIFT_FIRST_VISIBLE_THEN_REMOVE_LAST -> {
+                shiftCurrentPageToStart()
+                removeLastPages()
+            }
+            SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST_AND_LAST -> {
+                shiftCurrentPageToStart()
+                removeLastPages()
+                removeFirstPages()
+            }
+        }
+    }
+
+    private fun shiftCurrentPageToStart() {
+        // Move currently visible position and target apart from each other
+        repeat(test.viewPager.linearLayoutManager.findFirstVisibleItemPosition()) {
+            val item = dataSet.removeAt(0)
+            dataSet.add(targetPage - 1, item)
+            test.viewPager.adapter!!.notifyItemMoved(0, targetPage - 1)
+        }
+    }
+
+    private fun removeCurrentPage() {
+        val position = test.viewPager.linearLayoutManager.findFirstVisibleItemPosition()
+        dataSet.removeAt(position)
+        test.viewPager.adapter!!.notifyItemRemoved(position)
+    }
+
+    private fun removeLastPages() {
+        // Remove last items (including the target)
+        val removeCount = pageCount - targetPage
+        repeat(removeCount) {
+            dataSet.removeAt(targetPage)
+        }
+        test.viewPager.adapter!!.notifyItemRangeRemoved(targetPage, removeCount)
+    }
+
+    private fun removeFirstPages() {
+        // Remove first items (including the first visible item)
+        repeat(2) { dataSet.removeAt(0) }
+        test.viewPager.adapter!!.notifyItemRangeRemoved(0, 2)
+    }
+
+    private fun ViewPager2.addNewRecordingCallback(): RecordingCallback {
+        return RecordingCallback().also { registerOnPageChangeCallback(it) }
+    }
+
+    private sealed class Event {
+        data class OnPageScrolledEvent(
+            val position: Int,
+            val positionOffset: Float,
+            val positionOffsetPixels: Int
+        ) : Event()
+        data class OnPageSelectedEvent(val position: Int) : Event()
+        data class OnPageScrollStateChangedEvent(val state: Int) : Event()
+        data class MarkerEvent(val id: Int) : Event()
+    }
+
+    private class RecordingCallback : ViewPager2.OnPageChangeCallback() {
+        private val events = mutableListOf<Event>()
+
+        val scrollEvents get() = events.mapNotNull { it as? OnPageScrolledEvent }
+        val selectEvents get() = events.mapNotNull { it as? OnPageSelectedEvent }
+        val eventCount get() = events.size
+        val scrollEventCount get() = scrollEvents.size
+        val lastIx get() = events.size - 1
+        val settlingIx get() = events.indexOf(OnPageScrollStateChangedEvent(SCROLL_STATE_SETTLING))
+        val idleIx get() = events.indexOf(OnPageScrollStateChangedEvent(SCROLL_STATE_IDLE))
+        val pageSelectedIx: (page: Int) -> Int = { events.indexOf(OnPageSelectedEvent(it)) }
+        val markerIx: (id: Int) -> Int = { events.indexOf(MarkerEvent(it)) }
+
+        val scrollEventsBefore: (ix: Int) -> List<OnPageScrolledEvent> =
+            { scrollEventsBetween(0, it) }
+        val scrollEventsAfter: (ix: Int) -> List<OnPageScrolledEvent> =
+            { scrollEventsBetween(it + 1, events.size) }
+        val scrollEventsBetween: (fromIx: Int, toIx: Int) -> List<OnPageScrolledEvent> = { a, b ->
+            events.subList(a, b).mapNotNull { it as? OnPageScrolledEvent }
+        }
+
+        override fun onPageScrolled(
+            position: Int,
+            positionOffset: Float,
+            positionOffsetPixels: Int
+        ) {
+            events.add(OnPageScrolledEvent(position, positionOffset, positionOffsetPixels))
+        }
+
+        override fun onPageSelected(position: Int) {
+            events.add(OnPageSelectedEvent(position))
+        }
+
+        override fun onPageScrollStateChanged(state: Int) {
+            events.add(OnPageScrollStateChangedEvent(state))
+        }
+
+        fun markEvent(id: Int) {
+            events.add(MarkerEvent(id))
+        }
+    }
+
+    private fun RecordingCallback.markModification() {
+        markEvent(modificationMark)
+    }
+
+    private fun List<OnPageScrolledEvent>.assertPositionSorted(sortOrder: SortOrder) {
+        map { it.position }.assertSorted { it * sortOrder.sign }
+    }
+
+    private fun List<OnPageScrolledEvent>.assertLastCorrect(targetPage: Int) {
+        last().apply {
+            assertThat(position, equalTo(targetPage))
+            assertThat(positionOffsetPixels, equalTo(0))
+        }
+    }
+
+    private fun List<OnPageScrolledEvent>.assertValueSanity(
+        initialPage: Int,
+        otherPage: Int,
+        pageSize: Int
+    ) = forEach {
+        assertThat(it.position, isBetweenInInMinMax(initialPage, otherPage))
+        assertThat(it.positionOffset, isBetweenInEx(0f, 1f))
+        assertThat((it.positionOffset * pageSize).roundToInt(), equalTo(it.positionOffsetPixels))
+    }
+
+    private fun List<OnPageScrolledEvent>.assertOffsetSorted(sortOrder: SortOrder) {
+        map { it.position + it.positionOffset.toDouble() }.assertSorted { it * sortOrder.sign }
+    }
+
+    private fun List<OnPageScrolledEvent>.assertMaxShownPages() {
+        assertThat(map { it.position }.distinct().size, isBetweenInIn(0, 4))
+    }
+}
+
+// region Test Suite creation
+
+private fun createTestSet(): List<TestConfig> {
+    return listOf(viewAdapterProvider, viewAdapterProviderValueId).flatMap { adapterProvider ->
+        listOf(ORIENTATION_HORIZONTAL, ORIENTATION_VERTICAL).flatMap { orientation ->
+            listOf(false, true).flatMap { rtl ->
+                listOf(
+                    TestConfig(
+                        orientation, rtl, true,
+                        SHIFT_FIRST_VISIBLE,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = 2,
+                        expectedFinalPageText = "0"
+                    ),
+                    TestConfig(
+                        orientation, rtl, true,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage - 1,
+                        expectedFinalPageText = "${targetPage + 1}"
+                    ),
+                    TestConfig(
+                        orientation, rtl, true,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_LAST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = 2,
+                        expectedFinalPageText = "0"
+                    ),
+                    TestConfig(
+                        orientation, rtl, true,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST_AND_LAST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage - 3,
+                        expectedFinalPageText = "${targetPage - 3}"
+                    ),
+                    TestConfig(
+                        orientation, rtl, true,
+                        REMOVE_FIRST_VISIBLE,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage - 1,
+                        expectedFinalPageText = "$targetPage"
+                    ),
+                    TestConfig(
+                        orientation, rtl, false,
+                        SHIFT_FIRST_VISIBLE,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage,
+                        expectedFinalPageText = "$targetPage"
+                    ),
+                    TestConfig(
+                        orientation, rtl, false,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage,
+                        expectedFinalPageText = "${targetPage + 2}"
+                    ),
+                    TestConfig(
+                        orientation, rtl, false,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_LAST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage - 1,
+                        expectedFinalPageText = "${targetPage - 4}"
+                    ),
+                    TestConfig(
+                        orientation, rtl, false,
+                        SHIFT_FIRST_VISIBLE_THEN_REMOVE_FIRST_AND_LAST,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage - 3,
+                        expectedFinalPageText = "${targetPage - 4}"
+                    ),
+                    TestConfig(
+                        orientation, rtl, false,
+                        REMOVE_FIRST_VISIBLE,
+                        adapterProvider = adapterProvider,
+                        expectedFinalPage = targetPage,
+                        expectedFinalPageText = "${targetPage + 1}"
+                    )
+                )
+            }
+        }
+    }
+}
+
+// endregion
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
index 1a284f4..8185e8b 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/BaseTest.kt
@@ -45,6 +45,7 @@
 import androidx.test.rule.ActivityTestRule
 import androidx.testutils.LocaleTestUtils
 import androidx.testutils.recreate
+import androidx.testutils.waitForExecution
 import androidx.viewpager2.adapter.FragmentStateAdapter
 import androidx.viewpager2.test.R
 import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
@@ -503,6 +504,13 @@
         assertPageActions()
     }
 
+    fun Context.resetViewPagerTo(page: Int) {
+        viewPager.setCurrentItemSync(page, false, 2, TimeUnit.SECONDS)
+        // VP2 was potentially settling while the RetryException was raised,
+        // in which case we must wait until the IDLE event has been fired
+        activityTestRule.waitForExecution(1)
+    }
+
     fun Context.modifyDataSetSync(block: () -> Unit) {
         val layoutChangedLatch = viewPager.addWaitForLayoutChangeLatch()
         runOnUiThreadSync {
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.kt
new file mode 100644
index 0000000..861f676
--- /dev/null
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/ChangeDataSetWhileScrollingTest.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.viewpager2.widget
+
+import android.os.SystemClock.sleep
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.testutils.PollingCheck
+import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
+import androidx.viewpager2.widget.ViewPager2.SCROLL_STATE_IDLE
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@LargeTest
+class ChangeDataSetWhileScrollingTest : BaseTest() {
+    private val orientation = ORIENTATION_HORIZONTAL
+    private val adapterProvider = viewAdapterProviderValueId
+
+    @Test
+    fun test_regression01() {
+        setUpTest(orientation).apply {
+            val items = listOf("49", "51").toMutableList()
+            setAdapterSync(adapterProvider(items))
+            assertBasicState(0, items[0])
+
+            viewPager.post {
+                viewPager.setCurrentItem(1, true)
+            }
+
+            viewPager.post {
+                items.remove("51")
+                viewPager.adapter!!.notifyDataSetChanged()
+            }
+
+            sleep(200) // introduce some delay, follow-up with pollingCheck
+
+            PollingCheck.waitFor(2000) {
+                viewPager.scrollState == SCROLL_STATE_IDLE && viewPager.currentItem == 0
+            }
+
+            assertBasicState(0, "49")
+        }
+    }
+}
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
index 4a8f194..c3614cf 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/FakeDragTest.kt
@@ -28,7 +28,6 @@
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SdkSuppress
 import androidx.testutils.LocaleTestUtils
-import androidx.testutils.waitForExecution
 import androidx.viewpager2.widget.BaseTest.Context.SwipeMethod
 import androidx.viewpager2.widget.FakeDragTest.Event.OnPageScrollStateChangedEvent
 import androidx.viewpager2.widget.FakeDragTest.Event.OnPageScrolledEvent
@@ -400,12 +399,7 @@
     ) {
         val initialPage = test.viewPager.currentItem
 
-        tryNTimes(3, { /* RESET block */
-            test.viewPager.setCurrentItemSync(initialPage, false, 2, SECONDS)
-            // VP2 was potentially settling while the RetryException was raised, in which case we
-            // must wait until the IDLE event has been fired
-            activityTestRule.waitForExecution(1)
-        }) { /* TRY block */
+        tryNTimes(3, resetBlock = { test.resetViewPagerTo(initialPage) }) {
             val recorder = test.viewPager.addNewRecordingCallback()
 
             // start smooth scroll
@@ -508,12 +502,7 @@
             val initialPage = test.viewPager.currentItem
             val expectedFinalPage = initialPage + 1
 
-            tryNTimes(3, resetBlock = {
-                test.viewPager.setCurrentItemSync(initialPage, false, 2, SECONDS)
-                // VP2 was potentially settling while the RetryException was raised,
-                // in which case we must wait until the IDLE event has been fired
-                activityTestRule.waitForExecution(1)
-            }) {
+            tryNTimes(3, resetBlock = { test.resetViewPagerTo(initialPage) }) {
                 val recorder = test.viewPager.addNewRecordingCallback()
 
                 // start fake drag
diff --git a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
index d8afaac..da60cc2 100644
--- a/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
+++ b/viewpager2/src/androidTest/java/androidx/viewpager2/widget/PageChangeCallbackTest.kt
@@ -26,7 +26,6 @@
 import androidx.test.filters.LargeTest
 import androidx.testutils.LocaleTestUtils
 import androidx.testutils.PollingCheck
-import androidx.testutils.waitForExecution
 import androidx.viewpager.widget.ViewPager
 import androidx.viewpager2.test.ui.SparseAdapter
 import androidx.viewpager2.widget.BaseTest.Context.SwipeMethod
@@ -706,8 +705,7 @@
 
         // when
         tryNTimes(3, resetBlock = {
-            test.viewPager.setCurrentItemSync(currentPage, false, 2, SECONDS)
-            activityTestRule.waitForExecution(1)
+            test.resetViewPagerTo(currentPage)
             test.viewPager.unregisterOnPageChangeCallback(recorder)
             recorder = test.viewPager.addNewRecordingCallback()
         }) {
@@ -1032,99 +1030,6 @@
         recorder.assertAllPagesSelected(listOf(targetPage, targetPage + 1))
     }
 
-    @Test
-    fun test_removeFirstVisibleItemWhileScrolling_targetNotBound() {
-        test_removeFirstVisibleItemWhileScrolling(false)
-    }
-
-    @Test
-    fun test_removeFirstVisibleItemWhileScrolling_targetBound() {
-        test_removeFirstVisibleItemWhileScrolling(true)
-    }
-
-    /** @param targetBound If the target page should be bound by RV when modifying the dataset */
-    private fun test_removeFirstVisibleItemWhileScrolling(targetBound: Boolean) {
-        // given
-        val pageCount = 10     // number of pages
-        val initialPage = 0    // page we start at
-        val targetPage = 5     // page we smooth scroll to
-        val removeItemMark = 1 // id of the mark we make when modifying the dataset
-        val bindThreshold = 2  // how many pages from x before x gets bound?
-        val epsilon = 0.001f
-        // start and end of the window of opportunity to modify the dataset
-        val windowStart = targetPage - bindThreshold - if (targetBound) 0 else 1
-        val windowEnd = targetPage - if (targetBound) 0 else bindThreshold
-
-        val test = setUpTest(config.orientation)
-        activityTestRule.runOnUiThread { test.viewPager.offscreenPageLimit = 1 }
-        val dataSet = stringSequence(pageCount).toMutableList()
-        test.setAdapterSync(viewAdapterProvider(dataSet))
-
-        tryNTimes(3, resetBlock = {
-            test.viewPager.setCurrentItemSync(initialPage, false, 2, SECONDS)
-            // VP2 was potentially settling while the RetryException was raised,
-            // in which case we must wait until the IDLE event has been fired
-            activityTestRule.waitForExecution(1)
-        }) {
-            // when we are scrolling to the target
-            val recorder = test.viewPager.addNewRecordingCallback()
-            val distanceLatch = test.viewPager.addWaitForDistanceToTarget(targetPage,
-                targetPage - windowStart - epsilon)
-            val idleLatch = test.viewPager.addWaitForIdleLatch()
-            test.runOnUiThreadSync { test.viewPager.setCurrentItem(targetPage, true) }
-            distanceLatch.await(2, SECONDS)
-
-            // and we remove the first visible item
-            test.modifyDataSetSync {
-                val lastScrollPosition = recorder.scrollEvents.last().let {
-                    it.position + it.positionOffset.toDouble()
-                }
-                if (lastScrollPosition >= windowEnd) {
-                    throw RetryException("Data set should be modified while scrolling through " +
-                            "($windowStart, $windowEnd), but was modified at $lastScrollPosition")
-                }
-                recorder.markEvent(removeItemMark)
-                val position = test.viewPager.linearLayoutManager.findFirstVisibleItemPosition()
-                dataSet.removeAt(position)
-                test.viewPager.adapter!!.notifyItemRemoved(position)
-            }
-            idleLatch.await(2, SECONDS)
-
-            // then
-            val expectedFinalPage = targetPage - if (targetBound) 1 else 0
-            val expectedFinalPageText = expectedFinalPage + 1
-            test.assertBasicState(expectedFinalPage, "$expectedFinalPageText")
-            recorder.apply {
-                val removeItemMarkIx = markerIx(removeItemMark)
-                val expectedSelectEvents = listOf(targetPage).plus(
-                    if (targetPage != expectedFinalPage) listOf(expectedFinalPage) else emptyList()
-                )
-                // verify all events
-                assertThat(settlingIx, equalTo(0))
-                assertThat(pageSelectedIx(targetPage), equalTo(1))
-                assertThat(removeItemMarkIx, greaterThan(1))
-                assertThat(idleIx, equalTo(lastIx))
-                assertThat(selectEvents.map { it.position }, equalTo(expectedSelectEvents))
-                assertThat(scrollEventCount, equalTo(eventCount - 3 - expectedSelectEvents.size))
-
-                // verify scroll events _before_ and _after_ the marker
-                val scrollsBeforeMarker = scrollEventsBefore(removeItemMarkIx)
-                val scrollsAfterMarker = scrollEventsAfter(removeItemMarkIx)
-                listOf(scrollsBeforeMarker, scrollsAfterMarker).forEach {
-                    it.assertPositionSorted(SortOrder.ASC)
-                    it.assertOffsetSorted(SortOrder.ASC)
-                    it.assertValueSanity(0, targetPage, test.viewPager.pageSize)
-                }
-                // Only check assertMaxShownPages on scroll events _before_ the marker:
-                //   after the data set change, it can scroll an arbitrary number of pages
-                scrollsBeforeMarker.assertMaxShownPages()
-                // Only check assertLastCorrect on scroll events _after_ the marker:
-                //   the target is not reached before the data set change
-                scrollsAfterMarker.assertLastCorrect(expectedFinalPage)
-            }
-        }
-    }
-
     private fun ViewPager2.addNewRecordingCallback(): RecordingCallback {
         return RecordingCallback().also { registerOnPageChangeCallback(it) }
     }
@@ -1170,7 +1075,6 @@
         val draggingIx get() = events.indexOf(OnPageScrollStateChangedEvent(SCROLL_STATE_DRAGGING))
         val idleIx get() = events.indexOf(OnPageScrollStateChangedEvent(SCROLL_STATE_IDLE))
         val pageSelectedIx: (page: Int) -> Int = { events.indexOf(OnPageSelectedEvent(it)) }
-        val markerIx: (id: Int) -> Int = { events.indexOf(MarkerEvent(it)) }
 
         val scrollEventsBefore: (ix: Int) -> List<OnPageScrolledEvent> =
             { scrollEventsBetween(0, it) }
diff --git a/viewpager2/src/androidTest/res/layout/item_test_layout.xml b/viewpager2/src/androidTest/res/layout/item_test_layout.xml
index 74a0e03..ab051e4 100644
--- a/viewpager2/src/androidTest/res/layout/item_test_layout.xml
+++ b/viewpager2/src/androidTest/res/layout/item_test_layout.xml
@@ -20,4 +20,5 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:textColor="@color/primary_text_default_material_light"
+    android:textSize="40sp"
     android:gravity="center"/>
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java b/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
index fa9f235..456786f 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
+++ b/viewpager2/src/main/java/androidx/viewpager2/widget/ScrollEventAdapter.java
@@ -78,6 +78,7 @@
     private int mTarget;
     private boolean mDispatchSelected;
     private boolean mScrollHappened;
+    private boolean mDataSetChangeHappened;
     private boolean mFakeDragging;
 
     ScrollEventAdapter(@NonNull ViewPager2 viewPager) {
@@ -96,6 +97,7 @@
         mDispatchSelected = false;
         mScrollHappened = false;
         mFakeDragging = false;
+        mDataSetChangeHappened = false;
     }
 
     /**
@@ -125,10 +127,10 @@
         }
 
         // Drag is finished (dragging || settling -> idle)
-        if (mAdapterState != STATE_IDLE && newState == RecyclerView.SCROLL_STATE_IDLE) {
+        if (isInAnyDraggingState() && newState == RecyclerView.SCROLL_STATE_IDLE) {
             boolean dispatchIdle = false;
             updateScrollEventValues();
-            if (!mScrollHappened && isInAnyDraggingState()) {
+            if (!mScrollHappened) {
                 // Pages didn't move during drag, so either we're at the start or end of the list,
                 // or there are no pages at all.
                 // In the first case, ViewPager's contract requires at least one scroll event.
@@ -137,19 +139,11 @@
                     dispatchScrolled(mScrollValues.mPosition, 0f, 0);
                 }
                 dispatchIdle = true;
-            } else if (mScrollHappened && mScrollValues.mOffsetPx == 0) {
-                // Normally we dispatch the selected page and go to idle in onScrolled after we
-                // settled (mOffsetPx == 0), but there are a few exceptions:
-                //
-                // 1) The drag was still ongoing when onScrolled was called, so we didn't know it
-                //    was about to end. End it now.
-                // 2) If the adapter data set changes during a smooth scroll, RecyclerView may
-                //    settle at a different position, which we don't know about until we're there.
-                //    End it now.
-                //
-                // Now RecyclerView is idle and mOffsetPx == 0, so the view has stabilized. Fire
-                // onPageSelected to notify clients of the position settled upon and go to idle.
-                //
+            } else if (mScrollValues.mOffsetPx == 0) {
+                // Normally we dispatch the selected page and go to idle in onScrolled when
+                // mOffsetPx == 0, but in this case the drag was still ongoing when onScrolled was
+                // called, so that didn't happen. And since mOffsetPx == 0, there will be no further
+                // scroll events, so fire the onPageSelected event and go to idle now.
                 // Note that if we _did_ go to idle in that last onScrolled event, this code will
                 // not be executed because mAdapterState has been reset to STATE_IDLE.
                 dispatchIdle = true;
@@ -164,6 +158,19 @@
                 resetState();
             }
         }
+
+        if (mAdapterState == STATE_IN_PROGRESS_SMOOTH_SCROLL
+                && newState == RecyclerView.SCROLL_STATE_IDLE && mDataSetChangeHappened) {
+            updateScrollEventValues();
+            if (mScrollValues.mOffsetPx == 0) {
+                if (mTarget != mScrollValues.mPosition) {
+                    dispatchSelected(
+                            mScrollValues.mPosition == NO_POSITION ? 0 : mScrollValues.mPosition);
+                }
+                dispatchStateChanged(SCROLL_STATE_IDLE);
+                resetState();
+            }
+        }
     }
 
     /**
@@ -287,6 +294,10 @@
         dispatchStateChanged(SCROLL_STATE_DRAGGING);
     }
 
+    void notifyDataSetChangeHappened() {
+        mDataSetChangeHappened = true;
+    }
+
     /**
      * Let the adapter know a programmatic scroll was initiated.
      */
diff --git a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
index 7c71ca7..bd4247e 100644
--- a/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
+++ b/viewpager2/src/main/java/androidx/viewpager2/widget/ViewPager2.java
@@ -134,6 +134,7 @@
                 @Override
                 public void onChanged() {
                     mCurrentItemDirty = true;
+                    mScrollEventAdapter.notifyDataSetChangeHappened();
                 }
             };
 
@@ -142,7 +143,7 @@
     private Parcelable mPendingAdapterState;
     private RecyclerView mRecyclerView;
     private PagerSnapHelper mPagerSnapHelper;
-    private ScrollEventAdapter mScrollEventAdapter;
+    ScrollEventAdapter mScrollEventAdapter;
     private CompositeOnPageChangeCallback mPageChangeEventDispatcher;
     private FakeDrag mFakeDragger;
     private PageTransformerAdapter mPageTransformerAdapter;
diff --git a/webkit/build.gradle b/webkit/build.gradle
index 622bf29..8c0c18d 100644
--- a/webkit/build.gradle
+++ b/webkit/build.gradle
@@ -26,7 +26,7 @@
 
 dependencies {
     api("androidx.annotation:annotation:1.1.0")
-    api("androidx.core:core:1.1.0")
+    api("androidx.core:core:1.1.0-rc01")
 
     androidTestImplementation(OKHTTP_MOCKWEBSERVER)
     androidTestImplementation(ANDROIDX_TEST_EXT_JUNIT)
diff --git a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemalarm/SystemAlarmDispatcherTest.java b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemalarm/SystemAlarmDispatcherTest.java
index 620307f..95b6d4c 100644
--- a/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemalarm/SystemAlarmDispatcherTest.java
+++ b/work/workmanager/src/androidTest/java/androidx/work/impl/background/systemalarm/SystemAlarmDispatcherTest.java
@@ -567,6 +567,7 @@
 
     @Test
     public void testConstraintsChanged_withFutureWork() throws InterruptedException {
+        when(mBatteryChargingTracker.getInitialState()).thenReturn(true);
         // Use a mocked scheduler in this test.
         Scheduler scheduler = mock(Scheduler.class);
         doCallRealMethod().when(mWorkManager).rescheduleEligibleWork();
diff --git a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
index 2203618..41ac5d0 100644
--- a/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
+++ b/work/workmanager/src/main/java/androidx/work/ListenableWorker.java
@@ -180,6 +180,9 @@
      * A ListenableWorker is given a maximum of ten minutes to finish its execution and return a
      * {@link Result}.  After this time has expired, the worker will be signalled to stop and its
      * {@link ListenableFuture} will be cancelled.
+     * <p>
+     * The future will also be cancelled if this worker is stopped for any reason
+     * (see {@link #onStopped()}).
      *
      * @return A {@link ListenableFuture} with the {@link Result} of the computation.  If you
      *         cancel this Future, WorkManager will treat this unit of work as failed.
@@ -222,12 +225,13 @@
     }
 
     /**
-     * This method is invoked when this Worker has been told to stop.  This could happen due
-     * to an explicit cancellation signal by the user, or because the system has decided to preempt
-     * the task.  In these cases, the results of the work will be ignored by WorkManager.  All
-     * processing in this method should be lightweight - there are no contractual guarantees about
-     * which thread will invoke this call, so this should not be a long-running or blocking
-     * operation.
+     * This method is invoked when this Worker has been told to stop.  At this point, the
+     * {@link ListenableFuture} returned by the instance of {@link #startWork()} is
+     * also cancelled.  This could happen due to an explicit cancellation signal by the user, or
+     * because the system has decided to preempt the task.  In these cases, the results of the
+     * work will be ignored by WorkManager.  All processing in this method should be lightweight
+     * - there are no contractual guarantees about which thread will invoke this call, so this
+     * should not be a long-running or blocking operation.
      */
     public void onStopped() {
         // Do nothing by default.