Merge "Change all annotation-sampled dependencies to compileOnly." into androidx-master-dev
diff --git a/benchmark/benchmark-macro-runtime/build.gradle b/benchmark/benchmark-macro-runtime/build.gradle
index 8c8ca06..7886270 100644
--- a/benchmark/benchmark-macro-runtime/build.gradle
+++ b/benchmark/benchmark-macro-runtime/build.gradle
@@ -36,6 +36,7 @@
     api(KOTLIN_STDLIB)
     api(KOTLIN_COROUTINES_ANDROID)
     api("androidx.annotation:annotation:1.1.0")
+    implementation(project(":benchmark:benchmark-perfetto"))
     implementation(GUAVA_ANDROID)
     implementation(ANDROIDX_TEST_EXT_JUNIT)
     implementation(ANDROIDX_TEST_UIAUTOMATOR)
diff --git a/benchmark/benchmark-macro-runtime/src/androidTest/java/androidx/benchmark/macro/MacroBenchmarkTest.kt b/benchmark/benchmark-macro-runtime/src/androidTest/java/androidx/benchmark/macro/MacroBenchmarkTest.kt
index 155f131..0c028b6 100644
--- a/benchmark/benchmark-macro-runtime/src/androidTest/java/androidx/benchmark/macro/MacroBenchmarkTest.kt
+++ b/benchmark/benchmark-macro-runtime/src/androidTest/java/androidx/benchmark/macro/MacroBenchmarkTest.kt
@@ -42,7 +42,11 @@
     @LargeTest
     @Ignore("Not running the test in CI")
     fun basicTest() {
-        val collectors = listOf<Collector<*>>(CpuUsageCollector(), AppStartupCollector())
+        val collectors = listOf<Collector<*>>(
+            CpuUsageCollector(),
+            AppStartupCollector(),
+            PerfettoCollector("basicTest")
+        )
         val loopManager = LoopManager(packageName, instrumentation, collectors)
 
         loopManager.measureRepeated(2) { _ ->
diff --git a/benchmark/benchmark-macro-runtime/src/main/java/androidx/benchmark/macro/PerfettoCollector.kt b/benchmark/benchmark-macro-runtime/src/main/java/androidx/benchmark/macro/PerfettoCollector.kt
new file mode 100644
index 0000000..2b0cbef
--- /dev/null
+++ b/benchmark/benchmark-macro-runtime/src/main/java/androidx/benchmark/macro/PerfettoCollector.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 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.benchmark.macro
+
+import android.os.Build
+import android.util.Log
+import androidx.benchmark.perfetto.PerfettoCapture
+import androidx.benchmark.perfetto.destinationPath
+import androidx.benchmark.perfetto.reportAdditionalFileToCopy
+
+/**
+ * Helps capture Perfetto traces.
+ */
+class PerfettoCollector(private val traceName: String) : Collector<Unit> {
+    private var capture: PerfettoCapture? = null
+
+    init {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            capture = PerfettoCapture()
+        }
+    }
+
+    override fun start(): Boolean {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            Log.d(TAG, "Recording perfetto trace $traceName")
+            capture?.start()
+        }
+        return true
+    }
+
+    override fun stop(): Boolean {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            val destination = destinationPath(traceName).absolutePath
+            capture?.stop(destination)
+            reportAdditionalFileToCopy("perfetto_trace", destination)
+        }
+        return true
+    }
+
+    override fun metrics(): Map<String, Unit> {
+        return emptyMap()
+    }
+
+    companion object {
+        private const val TAG = "PerfettoCollector"
+    }
+}
diff --git a/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt b/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
index 82b0c02..77e056a 100644
--- a/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
+++ b/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoCapture.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
 import androidx.test.platform.app.InstrumentationRegistry
 import java.io.File
 
@@ -30,8 +31,9 @@
  * - App tags are not available, due to lack of `<profileable shell=true>`. Can potentially hack
  * around this for individual tags within test infra as needed.
  */
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
 @RequiresApi(29)
-internal class PerfettoCapture {
+class PerfettoCapture {
     private val helper = PerfettoHelper()
 
     /**
diff --git a/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoRule.kt b/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoRule.kt
index fa0d614..7de75b3 100644
--- a/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoRule.kt
+++ b/benchmark/perfetto/src/main/java/androidx/benchmark/perfetto/PerfettoRule.kt
@@ -21,6 +21,7 @@
 import android.os.Environment
 import android.util.Log
 import androidx.annotation.RequiresApi
+import androidx.annotation.RestrictTo
 import androidx.test.platform.app.InstrumentationRegistry
 import org.junit.rules.TestRule
 import org.junit.runner.Description
@@ -71,19 +72,11 @@
 
 @RequiresApi(Build.VERSION_CODES.Q)
 internal fun PerfettoCapture.recordAndReportFile(traceName: String, block: () -> Unit) {
-    // NOTE: this method of getting additionalTestOutputDir duplicates behavior in
-    // `androidx.benchmark.Arguments`, and should be unified at some point.
-    val additionalTestOutputDir = InstrumentationRegistry.getArguments()
-        .getString("additionalTestOutputDir")
-    @Suppress("DEPRECATION") // Legacy code path for versions of agp older than 3.6
-    val testOutputDir = additionalTestOutputDir?.let { File(it) }
-        ?: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
-
     try {
         Log.d(PerfettoRule.TAG, "Recording perfetto trace $traceName")
         start()
         block()
-        val dst = File(testOutputDir, traceName)
+        val dst = destinationPath(traceName)
         stop(dst.absolutePath)
         reportAdditionalFileToCopy("perfetto_trace", dst.absolutePath)
     } finally {
@@ -91,13 +84,29 @@
     }
 }
 
+/*
+   NOTE: this method of getting additionalTestOutputDir duplicates behavior in
+   androidx.benchmark.Arguments`, and should be unified at some point.
+*/
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun destinationPath(traceName: String): File {
+    val additionalTestOutputDir = InstrumentationRegistry.getArguments()
+        .getString("additionalTestOutputDir")
+
+    @Suppress("DEPRECATION") // Legacy code path for versions of agp older than 3.6
+    val testOutputDir = additionalTestOutputDir?.let { File(it) }
+        ?: Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
+    return File(testOutputDir, traceName)
+}
+
 /**
  * Report additional file to be copied.
  *
  * Note that this is a temporary reimplementation of
  * `InstrumentationResults.reportAdditionalFileToCopy`, and should be unified at some point.
  */
-private fun reportAdditionalFileToCopy(
+@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
+fun reportAdditionalFileToCopy(
     @Suppress("SameParameterValue") key: String,
     absoluteFilePath: String
 ) {
@@ -107,4 +116,4 @@
     InstrumentationRegistry
         .getInstrumentation()
         .sendStatus(2, bundle)
-}
\ No newline at end of file
+}
diff --git a/biometric/biometric/src/androidTest/java/androidx/biometric/DeviceUtilsTest.java b/biometric/biometric/src/androidTest/java/androidx/biometric/DeviceUtilsTest.java
index 508f1b3..791d38f 100644
--- a/biometric/biometric/src/androidTest/java/androidx/biometric/DeviceUtilsTest.java
+++ b/biometric/biometric/src/androidTest/java/androidx/biometric/DeviceUtilsTest.java
@@ -112,19 +112,23 @@
 
     @Test
     public void testCanAssumeStrongBiometrics() {
-        final String[] modelPrefixes = {"foo", "bar"};
+        final String[] modelNames = {"S", "flame", "My phone"};
         when(mContext.getResources()).thenReturn(mResources);
-        when(mResources.getStringArray(R.array.assume_strong_biometrics_prefixes))
-                .thenReturn(modelPrefixes);
+        when(mResources.getStringArray(R.array.assume_strong_biometrics_models))
+                .thenReturn(modelNames);
 
         final boolean isPreApi30 = Build.VERSION.SDK_INT < Build.VERSION_CODES.R;
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "foo")).isEqualTo(isPreApi30);
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "bar")).isEqualTo(isPreApi30);
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "foobar")).isEqualTo(isPreApi30);
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "bar123")).isEqualTo(isPreApi30);
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "baz")).isFalse();
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "abcxyz")).isFalse();
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "bazfoo")).isFalse();
-        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "FooBar")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "S")).isEqualTo(isPreApi30);
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "flame")).isEqualTo(isPreApi30);
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "My phone"))
+                .isEqualTo(isPreApi30);
+
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "s")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "Y")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "Flame")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "coral")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "My Phone")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "Myphone")).isFalse();
+        assertThat(DeviceUtils.canAssumeStrongBiometrics(mContext, "My phone2")).isFalse();
     }
 }
diff --git a/biometric/biometric/src/main/java/androidx/biometric/DeviceUtils.java b/biometric/biometric/src/main/java/androidx/biometric/DeviceUtils.java
index caf16d5..077c509 100644
--- a/biometric/biometric/src/main/java/androidx/biometric/DeviceUtils.java
+++ b/biometric/biometric/src/main/java/androidx/biometric/DeviceUtils.java
@@ -96,7 +96,7 @@
             // Android 11 (API 30) and above may downgrade a sensor's security class at runtime.
             return false;
         }
-        return isModelInPrefixList(context, model, R.array.assume_strong_biometrics_prefixes);
+        return isModelInList(context, model, R.array.assume_strong_biometrics_models);
     }
 
     /**
@@ -106,7 +106,7 @@
      * @param context The application or activity context.
      * @param vendor Case-insensitive name of the device vendor.
      * @param resId Resource ID for the string array of vendor names to check against.
-     * @return Whether the vendor name matches one in the given string array.
+     * @return Whether the vendor name matches one in the string array.
      */
     private static boolean isVendorInList(@NonNull Context context, String vendor, int resId) {
         if (vendor == null) {
@@ -128,7 +128,7 @@
      * @param context The application or activity context.
      * @param model Model name of the current device.
      * @param resId Resource ID for the string array of device model prefixes to check against.
-     * @return Whether the model matches one in the given string array.
+     * @return Whether the model matches a prefix in the string array.
      */
     private static boolean isModelInPrefixList(@NonNull Context context, String model, int resId) {
         if (model == null) {
@@ -150,7 +150,7 @@
      * @param context The application or activity context.
      * @param model Model name of the current device.
      * @param resId Resource ID for the string array of device model prefixes to check against.
-     * @return Whether the model matches one in the given string array.
+     * @return Whether the model matches one in the string array.
      */
     private static boolean isModelInList(@NonNull Context context, String model, int resId) {
         if (model == null) {
diff --git a/biometric/biometric/src/main/res/values/devices.xml b/biometric/biometric/src/main/res/values/devices.xml
index 4a7c2ac..2089d3f 100644
--- a/biometric/biometric/src/main/res/values/devices.xml
+++ b/biometric/biometric/src/main/res/values/devices.xml
@@ -78,6 +78,8 @@
     List of known device models for which all biometric sensors checked by
     BiometricManager#canAuthenticate() meet or exceed the Class 3 (Strong) security threshold.
     -->
-    <string-array name="assume_strong_biometrics_prefixes">
+    <string-array name="assume_strong_biometrics_models">
+        <item>Pixel 4</item>
+        <item>Pixel 4 XL</item>
     </string-array>
 </resources>
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index d5fa477..9a24321 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -104,7 +104,7 @@
   }
 
   public final class Composer<N> {
-    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, @androidx.compose.runtime.ExperimentalComposeApi androidx.compose.runtime.Recomposer recomposer);
+    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, internal androidx.compose.runtime.CompositionReference parentReference);
     method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
     method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
     method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -129,7 +129,6 @@
     method public int getCurrentCompoundKeyHash();
     method public boolean getDefaultsInvalid();
     method public boolean getInserting();
-    method public androidx.compose.runtime.Recomposer getRecomposer();
     method public boolean getSkipping();
     method public androidx.compose.runtime.SlotTable getSlotTable();
     method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
@@ -153,7 +152,6 @@
     property public final int currentCompoundKeyHash;
     property public final boolean defaultsInvalid;
     property public final boolean inserting;
-    property public final androidx.compose.runtime.Recomposer recomposer;
     property public final boolean skipping;
     property public final androidx.compose.runtime.SlotTable slotTable;
   }
@@ -168,10 +166,6 @@
     method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @Deprecated public interface CompositionCoroutineScope extends kotlinx.coroutines.CoroutineScope {
-    method @Deprecated public default suspend Object? awaitFrame(kotlin.coroutines.Continuation<? super java.lang.Long> p);
-  }
-
   @Deprecated public interface CompositionFrameClock extends androidx.compose.runtime.dispatch.MonotonicFrameClock {
     method @Deprecated public default suspend <R> Object? awaitFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
@@ -184,7 +178,7 @@
   }
 
   public final class CompositionKt {
-    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
+    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
   }
 
   public interface CompositionLifecycleObserver {
@@ -195,6 +189,9 @@
   public abstract class CompositionReference {
   }
 
+  public final class CompositionReferenceKt {
+  }
+
   public final class DerivedStateKt {
     method public static <T> androidx.compose.runtime.State<T> derivedStateOf(kotlin.jvm.functions.Function0<? extends T> calculation);
   }
@@ -352,18 +349,24 @@
     property public final T! value;
   }
 
-  public final class Recomposer {
+  public final class Recomposer extends androidx.compose.runtime.CompositionReference {
     ctor public Recomposer(androidx.compose.runtime.EmbeddingContext embeddingContext);
     ctor public Recomposer();
     method public suspend Object? awaitIdle(kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void composeInitial$metalava_module(androidx.compose.runtime.Composer<?> composer, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public kotlin.coroutines.CoroutineContext? getApplyingCoroutineContext$metalava_module();
+    method public boolean getCollectingKeySources$metalava_module();
+    method public int getCompoundHashKey$metalava_module();
     method public androidx.compose.runtime.EmbeddingContext getEmbeddingContext();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
     method public boolean hasInvalidations();
+    method public void invalidate$metalava_module(androidx.compose.runtime.Composer<?> composer);
     method public suspend Object? recomposeAndApplyChanges(long frameCount, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void recordInspectionTable$metalava_module(java.util.Set<androidx.compose.runtime.SlotTable> table);
     method public suspend Object? runRecomposeAndApplyChanges(kotlin.coroutines.Continuation<?> p);
-    method public void setEmbeddingContext(androidx.compose.runtime.EmbeddingContext p);
+    property public kotlin.coroutines.CoroutineContext? applyingCoroutineContext;
+    property public boolean collectingKeySources;
+    property public int compoundHashKey;
     property public final androidx.compose.runtime.EmbeddingContext embeddingContext;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
     field public static final androidx.compose.runtime.Recomposer.Companion Companion;
   }
 
@@ -565,12 +568,6 @@
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object![]? keys, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated public static suspend Object? awaitDispose(androidx.compose.runtime.CompositionCoroutineScope, optional kotlin.jvm.functions.Function0<kotlin.Unit> onDispose, optional kotlin.coroutines.Continuation<?> p);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object![]? keys, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static inline kotlinx.coroutines.CoroutineScope rememberCoroutineScope(optional kotlin.jvm.functions.Function0<? extends kotlin.coroutines.CoroutineContext> getContext);
   }
 
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index d5fa477..9a24321 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -104,7 +104,7 @@
   }
 
   public final class Composer<N> {
-    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, @androidx.compose.runtime.ExperimentalComposeApi androidx.compose.runtime.Recomposer recomposer);
+    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, internal androidx.compose.runtime.CompositionReference parentReference);
     method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
     method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
     method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -129,7 +129,6 @@
     method public int getCurrentCompoundKeyHash();
     method public boolean getDefaultsInvalid();
     method public boolean getInserting();
-    method public androidx.compose.runtime.Recomposer getRecomposer();
     method public boolean getSkipping();
     method public androidx.compose.runtime.SlotTable getSlotTable();
     method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
@@ -153,7 +152,6 @@
     property public final int currentCompoundKeyHash;
     property public final boolean defaultsInvalid;
     property public final boolean inserting;
-    property public final androidx.compose.runtime.Recomposer recomposer;
     property public final boolean skipping;
     property public final androidx.compose.runtime.SlotTable slotTable;
   }
@@ -168,10 +166,6 @@
     method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @Deprecated public interface CompositionCoroutineScope extends kotlinx.coroutines.CoroutineScope {
-    method @Deprecated public default suspend Object? awaitFrame(kotlin.coroutines.Continuation<? super java.lang.Long> p);
-  }
-
   @Deprecated public interface CompositionFrameClock extends androidx.compose.runtime.dispatch.MonotonicFrameClock {
     method @Deprecated public default suspend <R> Object? awaitFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
@@ -184,7 +178,7 @@
   }
 
   public final class CompositionKt {
-    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
+    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
   }
 
   public interface CompositionLifecycleObserver {
@@ -195,6 +189,9 @@
   public abstract class CompositionReference {
   }
 
+  public final class CompositionReferenceKt {
+  }
+
   public final class DerivedStateKt {
     method public static <T> androidx.compose.runtime.State<T> derivedStateOf(kotlin.jvm.functions.Function0<? extends T> calculation);
   }
@@ -352,18 +349,24 @@
     property public final T! value;
   }
 
-  public final class Recomposer {
+  public final class Recomposer extends androidx.compose.runtime.CompositionReference {
     ctor public Recomposer(androidx.compose.runtime.EmbeddingContext embeddingContext);
     ctor public Recomposer();
     method public suspend Object? awaitIdle(kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void composeInitial$metalava_module(androidx.compose.runtime.Composer<?> composer, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public kotlin.coroutines.CoroutineContext? getApplyingCoroutineContext$metalava_module();
+    method public boolean getCollectingKeySources$metalava_module();
+    method public int getCompoundHashKey$metalava_module();
     method public androidx.compose.runtime.EmbeddingContext getEmbeddingContext();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
     method public boolean hasInvalidations();
+    method public void invalidate$metalava_module(androidx.compose.runtime.Composer<?> composer);
     method public suspend Object? recomposeAndApplyChanges(long frameCount, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void recordInspectionTable$metalava_module(java.util.Set<androidx.compose.runtime.SlotTable> table);
     method public suspend Object? runRecomposeAndApplyChanges(kotlin.coroutines.Continuation<?> p);
-    method public void setEmbeddingContext(androidx.compose.runtime.EmbeddingContext p);
+    property public kotlin.coroutines.CoroutineContext? applyingCoroutineContext;
+    property public boolean collectingKeySources;
+    property public int compoundHashKey;
     property public final androidx.compose.runtime.EmbeddingContext embeddingContext;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
     field public static final androidx.compose.runtime.Recomposer.Companion Companion;
   }
 
@@ -565,12 +568,6 @@
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object![]? keys, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated public static suspend Object? awaitDispose(androidx.compose.runtime.CompositionCoroutineScope, optional kotlin.jvm.functions.Function0<kotlin.Unit> onDispose, optional kotlin.coroutines.Continuation<?> p);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object![]? keys, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static inline kotlinx.coroutines.CoroutineScope rememberCoroutineScope(optional kotlin.jvm.functions.Function0<? extends kotlin.coroutines.CoroutineContext> getContext);
   }
 
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index e0c38a8..dfa4f02 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -104,7 +104,7 @@
   }
 
   public final class Composer<N> {
-    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, @androidx.compose.runtime.ExperimentalComposeApi androidx.compose.runtime.Recomposer recomposer);
+    ctor public Composer(androidx.compose.runtime.SlotTable slotTable, @androidx.compose.runtime.ComposeCompilerApi androidx.compose.runtime.Applier<N> applier, internal androidx.compose.runtime.CompositionReference parentReference);
     method @androidx.compose.runtime.InternalComposeApi public void applyChanges();
     method @androidx.compose.runtime.ComposeCompilerApi public inline <T> T! cache(boolean invalid, kotlin.jvm.functions.Function0<? extends T> block);
     method @androidx.compose.runtime.ComposeCompilerApi public boolean changed(Object? value);
@@ -130,7 +130,6 @@
     method public int getCurrentCompoundKeyHash();
     method public boolean getDefaultsInvalid();
     method public boolean getInserting();
-    method public androidx.compose.runtime.Recomposer getRecomposer();
     method public boolean getSkipping();
     method public androidx.compose.runtime.SlotTable getSlotTable();
     method @androidx.compose.runtime.ComposeCompilerApi public Object joinKey(Object? left, Object? right);
@@ -155,7 +154,6 @@
     property public final int currentCompoundKeyHash;
     property public final boolean defaultsInvalid;
     property public final boolean inserting;
-    property public final androidx.compose.runtime.Recomposer recomposer;
     property public final boolean skipping;
     property public final androidx.compose.runtime.SlotTable slotTable;
   }
@@ -182,10 +180,6 @@
     method public void setContent(kotlin.jvm.functions.Function0<kotlin.Unit> content);
   }
 
-  @Deprecated public interface CompositionCoroutineScope extends kotlinx.coroutines.CoroutineScope {
-    method @Deprecated public default suspend Object? awaitFrame(kotlin.coroutines.Continuation<? super java.lang.Long> p);
-  }
-
   @Deprecated public interface CompositionFrameClock extends androidx.compose.runtime.dispatch.MonotonicFrameClock {
     method @Deprecated public default suspend <R> Object? awaitFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
@@ -198,7 +192,7 @@
   }
 
   public final class CompositionKt {
-    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
+    method @androidx.compose.runtime.ExperimentalComposeApi public static androidx.compose.runtime.Composition compositionFor(Object key, androidx.compose.runtime.Applier<?> applier, androidx.compose.runtime.CompositionReference parent, optional kotlin.jvm.functions.Function0<kotlin.Unit> onCreated);
   }
 
   public interface CompositionLifecycleObserver {
@@ -209,6 +203,9 @@
   public abstract class CompositionReference {
   }
 
+  public final class CompositionReferenceKt {
+  }
+
   @kotlin.PublishedApi internal final class CompositionScopedCoroutineScopeCanceller implements androidx.compose.runtime.CompositionLifecycleObserver {
     ctor public CompositionScopedCoroutineScopeCanceller(kotlinx.coroutines.CoroutineScope coroutineScope);
     method public kotlinx.coroutines.CoroutineScope getCoroutineScope();
@@ -378,18 +375,24 @@
     property public final T! value;
   }
 
-  public final class Recomposer {
+  public final class Recomposer extends androidx.compose.runtime.CompositionReference {
     ctor public Recomposer(androidx.compose.runtime.EmbeddingContext embeddingContext);
     ctor public Recomposer();
     method public suspend Object? awaitIdle(kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void composeInitial$metalava_module(androidx.compose.runtime.Composer<?> composer, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public kotlin.coroutines.CoroutineContext? getApplyingCoroutineContext$metalava_module();
+    method public boolean getCollectingKeySources$metalava_module();
+    method public int getCompoundHashKey$metalava_module();
     method public androidx.compose.runtime.EmbeddingContext getEmbeddingContext();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
     method public boolean hasInvalidations();
+    method public void invalidate$metalava_module(androidx.compose.runtime.Composer<?> composer);
     method public suspend Object? recomposeAndApplyChanges(long frameCount, kotlin.coroutines.Continuation<? super kotlin.Unit> p);
+    method public void recordInspectionTable$metalava_module(java.util.Set<androidx.compose.runtime.SlotTable> table);
     method public suspend Object? runRecomposeAndApplyChanges(kotlin.coroutines.Continuation<?> p);
-    method public void setEmbeddingContext(androidx.compose.runtime.EmbeddingContext p);
+    property public kotlin.coroutines.CoroutineContext? applyingCoroutineContext;
+    property public boolean collectingKeySources;
+    property public int compoundHashKey;
     property public final androidx.compose.runtime.EmbeddingContext embeddingContext;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
     field public static final androidx.compose.runtime.Recomposer.Companion Companion;
   }
 
@@ -592,13 +595,7 @@
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static void LaunchedTask(Object![]? keys, kotlin.jvm.functions.Function2<? super kotlinx.coroutines.CoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated public static suspend Object? awaitDispose(androidx.compose.runtime.CompositionCoroutineScope, optional kotlin.jvm.functions.Function0<kotlin.Unit> onDispose, optional kotlin.coroutines.Continuation<?> p);
     method @kotlin.PublishedApi internal static kotlinx.coroutines.CoroutineScope createCompositionCoroutineScope(kotlin.coroutines.CoroutineContext coroutineContext, androidx.compose.runtime.Composer<?> composer);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object? key1, Object? key2, Object? key3, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
-    method @Deprecated @androidx.compose.runtime.Composable public static void launchInComposition(Object![]? keys, kotlin.jvm.functions.Function2<? super androidx.compose.runtime.CompositionCoroutineScope,? super kotlin.coroutines.Continuation<? super kotlin.Unit>,?> block);
     method @androidx.compose.runtime.Composable public static inline kotlinx.coroutines.CoroutineScope rememberCoroutineScope(optional kotlin.jvm.functions.Function0<? extends kotlin.coroutines.CoroutineContext> getContext);
   }
 
diff --git a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
index 9998e17..9adeb79 100644
--- a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/AmbientTests.kt
@@ -506,7 +506,6 @@
             // TODO(b/150390669): Review use of @ComposableContract(tracked = false)
             subcomposeInto(
                 container,
-                Recomposer.current(),
                 ref.value
             ) @ComposableContract(tracked = false) {
                 block()
diff --git a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
index 49c2735..a9b066f 100644
--- a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/BaseComposeTest.kt
@@ -124,7 +124,6 @@
         @OptIn(ExperimentalComposeApi::class)
         subcomposeInto(
             container,
-            Recomposer.current(),
             reference
         ) @ComposableContract(tracked = false) {
             block()
diff --git a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
index 48f208f..0d2eafc 100644
--- a/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
+++ b/compose/runtime/runtime/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
@@ -170,7 +170,8 @@
         var rememberCoroutineScopeFrameClock: MonotonicFrameClock? = null
 
         compose {
-            recomposerClock = currentComposer.recomposer.frameClock
+            recomposerClock = currentComposer.parentReference
+                .applyingCoroutineContext?.get(MonotonicFrameClock)
             LaunchedTask {
                 launchedTaskClock = coroutineContext[MonotonicFrameClock]
             }
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
index 01402b1..78cf0fe 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composer.kt
@@ -23,6 +23,7 @@
 
 import androidx.compose.runtime.SlotTable.Companion.EMPTY
 import androidx.compose.runtime.tooling.InspectionTables
+import kotlin.coroutines.CoroutineContext
 
 internal typealias Change<N> = (
     applier: Applier<N>,
@@ -316,10 +317,9 @@
     val applier: Applier<N>,
 
     /**
-     * Manager for scheduling recompositions.
+     * Parent of this composition; a [Recomposer] for root-level compositions.
      */
-    @ExperimentalComposeApi
-    val recomposer: Recomposer
+    internal val parentReference: CompositionReference
 ) {
     init {
         FrameManager.ensureStarted()
@@ -352,7 +352,6 @@
 
     private val invalidateStack = Stack<RecomposeScope>()
 
-    internal var parentReference: CompositionReference? = null
     internal var isComposing = false
         private set
     internal var isDisposed = false
@@ -499,18 +498,18 @@
     private fun startRoot() {
         reader = slotTable.openReader()
         startGroup(rootKey)
-        parentReference?.let { parentRef ->
-            parentRef.startComposing()
-            parentProvider = parentRef.getAmbientScope()
-            providersInvalidStack.push(providersInvalid.asInt())
-            providersInvalid = changed(parentProvider)
-            collectKeySources = parentRef.collectingKeySources
-            resolveAmbient(InspectionTables, parentProvider)?.let {
-                it.add(slotTable)
-                parentRef.recordInspectionTable(it)
-            }
-            startGroup(parentRef.compoundHashKey)
+
+        // parent reference management
+        parentReference.startComposing()
+        parentProvider = parentReference.getAmbientScope()
+        providersInvalidStack.push(providersInvalid.asInt())
+        providersInvalid = changed(parentProvider)
+        collectKeySources = parentReference.collectingKeySources
+        resolveAmbient(InspectionTables, parentProvider)?.let {
+            it.add(slotTable)
+            parentReference.recordInspectionTable(it)
         }
+        startGroup(parentReference.compoundHashKey)
     }
 
     /**
@@ -518,10 +517,9 @@
      * the composition.
      */
     private fun endRoot() {
-        parentReference?.let { parentRef ->
-            endGroup()
-            parentRef.doneComposing()
-        }
+        endGroup()
+        parentReference.doneComposing()
+
         endGroup()
         recordEndRoot()
         finalizeCompose()
@@ -757,7 +755,7 @@
 
     internal fun dispose() {
         trace("Compose:Composer.dispose") {
-            parentReference?.unregisterComposer(this)
+            parentReference.unregisterComposer(this)
             invalidateStack.clear()
             invalidations.clear()
             changes.clear()
@@ -1219,17 +1217,8 @@
         return ref.ref
     }
 
-    private fun <T> resolveAmbient(key: Ambient<T>, scope: AmbientMap): T {
-        if (scope.contains(key)) return scope.getValueOf(key)
-
-        val ref = parentReference
-
-        if (ref != null) {
-            return ref.getAmbient(key)
-        }
-
-        return key.defaultValueHolder.value
-    }
+    private fun <T> resolveAmbient(key: Ambient<T>, scope: AmbientMap): T =
+        if (scope.contains(key)) scope.getValueOf(key) else parentReference.getAmbient(key)
 
     internal fun <T> parentAmbient(key: Ambient<T>): T = resolveAmbient(key, currentAmbientScope())
 
@@ -1772,11 +1761,7 @@
             // composition.
             return InvalidationResult.IMMINENT
         }
-        if (parentReference != null) {
-            parentReference?.invalidate()
-        } else {
-            recomposer.scheduleRecompose(this)
-        }
+        parentReference.invalidate(this)
         return if (isComposing) InvalidationResult.DEFERRED else InvalidationResult.SCHEDULED
     }
 
@@ -2313,7 +2298,7 @@
             }
         }
 
-        override fun <N> registerComposer(composer: Composer<N>) {
+        override fun registerComposer(composer: Composer<*>) {
             composers.add(composer)
         }
 
@@ -2322,10 +2307,14 @@
             composers.remove(composer)
         }
 
-        override fun invalidate() {
-            // continue invalidating up the spine of AmbientReferences
-            parentReference?.invalidate()
+        override val applyingCoroutineContext: CoroutineContext?
+            get() = parentReference.applyingCoroutineContext
 
+        override fun composeInitial(composer: Composer<*>, composable: @Composable () -> Unit) {
+            parentReference.composeInitial(composer, composable)
+        }
+
+        override fun invalidate(composer: Composer<*>) {
             invalidate(scope)
         }
 
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
index 894cb3a..f77223e 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Composition.kt
@@ -57,7 +57,6 @@
  * for a given [key]. If the same [key] is passed in subsequent calls, the same [Composition]
  * instance will be returned.
  * @param applier The [Applier] instance to be used in the composition.
- * @param recomposer The [Recomposer] instance to be used for composition.
  * @param parent The parent composition reference, if applicable. Default is null.
  * @param onCreated A function which will be executed only when the Composition is created.
  *
@@ -69,12 +68,10 @@
 fun compositionFor(
     key: Any,
     applier: Applier<*>,
-    recomposer: Recomposer,
-    parent: CompositionReference? = null,
+    parent: CompositionReference,
     onCreated: () -> Unit = {}
 ): Composition = Compositions.findOrCreate(key) {
     CompositionImpl(
-        recomposer,
         parent,
         composerFactory = { slots, rcmpsr -> Composer(slots, applier, rcmpsr) },
         onDispose = { Compositions.onDisposed(key) }
@@ -89,21 +86,19 @@
  * @param onDispose A callback to be triggered when [dispose] is called.
  */
 private class CompositionImpl(
-    private val recomposer: Recomposer,
-    parent: CompositionReference?,
-    composerFactory: (SlotTable, Recomposer) -> Composer<*>,
+    private val parent: CompositionReference,
+    composerFactory: (SlotTable, CompositionReference) -> Composer<*>,
     private val onDispose: () -> Unit
 ) : Composition {
     private val slotTable: SlotTable = SlotTable()
-    private val composer: Composer<*> = composerFactory(slotTable, recomposer).also {
-        it.parentReference = parent
-        parent?.registerComposer(it)
+    private val composer: Composer<*> = composerFactory(slotTable, parent).also {
+        parent.registerComposer(it)
     }
 
     /**
      * Return true if this is a root (non-sub-) composition.
      */
-    val isRoot: Boolean = parent == null
+    val isRoot: Boolean = parent is Recomposer
 
     private var disposed = false
 
@@ -112,7 +107,7 @@
     override fun setContent(content: @Composable () -> Unit) {
         check(!disposed) { "The composition is disposed" }
         this.composable = content
-        recomposer.composeInitial(composable, composer)
+        parent.composeInitial(composer, composable)
     }
 
     override fun dispose() {
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
index 6ac0fd5..53a9fab 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/CompositionReference.kt
@@ -16,6 +16,10 @@
 
 package androidx.compose.runtime
 
+import kotlin.coroutines.CoroutineContext
+
+private val EmptyAmbientMap: AmbientMap = buildableMapOf()
+
 /**
  * A [CompositionReference] is an opaque type that is used to logically "link" two compositions
  * together. The [CompositionReference] instance represents a reference to the "parent" composition
@@ -23,17 +27,22 @@
  * "child" composition. This reference ensures that invalidations and ambients flow logically
  * through the two compositions as if they were not separate.
  *
+ * The "parent" of a root composition is a [Recomposer].
+ *
  * @see compositionReference
  */
 abstract class CompositionReference internal constructor() {
     internal abstract val compoundHashKey: Int
     internal abstract val collectingKeySources: Boolean
+    internal abstract val applyingCoroutineContext: CoroutineContext?
     internal abstract fun recordInspectionTable(table: MutableSet<SlotTable>)
-    internal abstract fun <T> getAmbient(key: Ambient<T>): T
-    internal abstract fun invalidate()
-    internal abstract fun <N> registerComposer(composer: Composer<N>)
-    internal abstract fun unregisterComposer(composer: Composer<*>)
-    internal abstract fun getAmbientScope(): AmbientMap
-    internal abstract fun startComposing()
-    internal abstract fun doneComposing()
+    internal abstract fun composeInitial(composer: Composer<*>, composable: @Composable () -> Unit)
+    internal abstract fun invalidate(composer: Composer<*>)
+
+    internal open fun <T> getAmbient(key: Ambient<T>): T = key.defaultValueHolder.value
+    internal open fun getAmbientScope(): AmbientMap = EmptyAmbientMap
+    internal open fun registerComposer(composer: Composer<*>) {}
+    internal open fun unregisterComposer(composer: Composer<*>) {}
+    internal open fun startComposing() {}
+    internal open fun doneComposing() {}
 }
\ No newline at end of file
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
index 9bf8ef9..daa5de5 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Recomposer.kt
@@ -33,11 +33,9 @@
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
 import kotlinx.coroutines.NonCancellable
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.launch
-import kotlinx.coroutines.plus
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import kotlin.coroutines.Continuation
@@ -45,6 +43,9 @@
 import kotlin.coroutines.coroutineContext
 import kotlin.coroutines.resume
 
+// TODO: Can we use rootKey for this since all compositions will have an eventual Recomposer parent?
+private const val RecomposerCompoundHashKey = 1000
+
 /**
  * Runs [block] with a new, active [Recomposer] applying changes in the calling [CoroutineContext].
  */
@@ -59,9 +60,10 @@
 
 /**
  * The scheduler for performing recomposition and applying updates to one or more [Composition]s.
- * [frameClock] is used to align changes with display frames.
  */
-class Recomposer(var embeddingContext: EmbeddingContext = EmbeddingContext()) {
+class Recomposer(
+    val embeddingContext: EmbeddingContext = EmbeddingContext()
+) : CompositionReference() {
 
     /**
      * This collection is its own lock, shared with [invalidComposersAwaiter]
@@ -82,7 +84,8 @@
 
     /**
      * Enforces that only one caller of [runRecomposeAndApplyChanges] is active at a time
-     * while carrying its calling scope. Used to [launchEffect] on the apply dispatcher.
+     * while carrying its calling scope. Used to offer [applyingCoroutineContext] to
+     * [CompositionReference] consumers.
      */
     // TODO(adamp) convert to atomicfu once ready
     private val applyingScope = AtomicReference<CoroutineScope?>(null)
@@ -96,7 +99,6 @@
             }
         }
     }
-    val frameClock: MonotonicFrameClock get() = broadcastFrameClock
 
     /**
      * Await the invalidation of any associated [Composer]s, recompose them, and apply their
@@ -211,26 +213,12 @@
         }
     }
 
-    @Suppress("DEPRECATION")
-    private class CompositionCoroutineScopeImpl(
-        override val coroutineContext: CoroutineContext
-    ) : CompositionCoroutineScope
-
-    @Suppress("DEPRECATION")
-    @OptIn(ExperimentalCoroutinesApi::class)
-    internal fun launchEffect(
-        block: suspend CompositionCoroutineScope.() -> Unit
-    ): Job = applyingScope.get()?.launch {
-        CompositionCoroutineScopeImpl(coroutineContext).block()
-    } ?: error("apply scope missing; runRecomposeAndApplyChanges must be running")
-
-    // TODO this is temporary until more of this logic moves to Composition
-    internal val applyingCoroutineContext: CoroutineContext?
+    override val applyingCoroutineContext: CoroutineContext?
         get() = applyingScope.get()?.coroutineContext
 
-    internal fun composeInitial(
-        composable: @Composable () -> Unit,
-        composer: Composer<*>
+    override fun composeInitial(
+        composer: Composer<*>,
+        composable: @Composable () -> Unit
     ) {
         if (composer.disposeHook == null) {
             // This will eventually move to the recomposer once it tracks active compositions.
@@ -313,17 +301,6 @@
     fun hasInvalidations(): Boolean =
         !idlingLatch.isOpen || synchronized(invalidComposers) { invalidComposers.isNotEmpty() }
 
-    internal fun scheduleRecompose(composer: Composer<*>) {
-        synchronized(invalidComposers) {
-            invalidComposers.add(composer)
-            invalidComposersAwaiter?.let {
-                invalidComposersAwaiter = null
-                idlingLatch.closeLatch()
-                it.resume(Unit)
-            }
-        }
-    }
-
     /**
      * Suspends until the currently pending recomposition frame is complete.
      * Any recomposition for this recomposer triggered by actions before this call begins
@@ -334,6 +311,30 @@
      */
     suspend fun awaitIdle(): Unit = idlingLatch.await()
 
+    // Recomposer always starts with a constant compound hash
+    override val compoundHashKey: Int
+        get() = RecomposerCompoundHashKey
+
+    // Collecting key sources happens at the level of a composer; starts as false
+    override val collectingKeySources: Boolean
+        get() = false
+
+    override fun recordInspectionTable(table: MutableSet<SlotTable>) {
+        // TODO: The root recomposer might be a better place to set up inspection
+        // than the current configuration with an ambient
+    }
+
+    override fun invalidate(composer: Composer<*>) {
+        synchronized(invalidComposers) {
+            invalidComposers.add(composer)
+            invalidComposersAwaiter?.let {
+                invalidComposersAwaiter = null
+                idlingLatch.closeLatch()
+                it.resume(Unit)
+            }
+        }
+    }
+
     companion object {
         private val embeddingContext by lazy { EmbeddingContext() }
         /**
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
index cd99e06..7023821 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/SuspendingEffects.kt
@@ -18,210 +18,13 @@
 @file:OptIn(InternalComposeApi::class)
 package androidx.compose.runtime
 
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Job
 import kotlinx.coroutines.cancel
 import kotlinx.coroutines.launch
-import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlin.coroutines.CoroutineContext
 import kotlin.coroutines.EmptyCoroutineContext
 
-@Suppress("DEPRECATION")
-@Deprecated("No replacement; removing CompositionCoroutineScope in migration to LaunchedTask")
-private class SuspendingEffect(
-    private val recomposer: Recomposer,
-    private val block: suspend CompositionCoroutineScope.() -> Unit
-) : CompositionLifecycleObserver {
-
-    private var job: Job? = null
-
-    override fun onEnter() {
-        job?.cancel("Old job was still running!")
-        job = recomposer.launchEffect(block)
-    }
-
-    override fun onLeave() {
-        job?.cancel()
-        job = null
-    }
-}
-
-/**
- * A [CoroutineScope] used for launching [side effects][launchInComposition] of a composition
- * that also permits [awaiting][MonotonicFrameClock.withFrameNanos] the next presentation
- * frame of the composition. This can be useful for performing the next action of an animation
- * while the effect is still present in the composition.
- */
-@Deprecated("No replacement; LaunchedTask uses CoroutineScope as a receiver directly")
-interface CompositionCoroutineScope : CoroutineScope {
-    // This method deliberately shadows the awaitFrame method from kotlinx-coroutines-android
-    // to redirect usage to the CompositionFrameClock API in effect blocks.
-    @Suppress("RedundantSuspendModifier", "DeprecatedCallableAddReplaceWith")
-    @Deprecated(
-        "use withFrameNanos to perform work on a composition frame",
-        level = DeprecationLevel.ERROR
-    )
-    suspend fun awaitFrame(): Long = error("awaitFrame should not be used; use withFrameNanos")
-}
-
-/**
- * Suspends the current coroutine until the effect is **disposed** and the
- * [CompositionCoroutineScope] is cancelled, and invokes [onDispose] before resuming.
- * [awaitDispose] never resumes normally and will always throw either
- * [kotlinx.coroutines.CancellationException] or the exception that failed the current
- * [kotlinx.coroutines.Job].
- */
-@Suppress("unused", "DeprecatedCallableAddReplaceWith", "DEPRECATION")
-@Deprecated("No replacement; LaunchedTask uses CoroutineScope as a receiver directly")
-suspend fun CompositionCoroutineScope.awaitDispose(onDispose: () -> Unit = {}): Nothing = try {
-    suspendCancellableCoroutine<Nothing> { /* Suspend until cancellation */ }
-} finally {
-    onDispose()
-}
-
-/**
- * Launch a suspending side effect when this composition is committed and cancel it
- * when [launchInComposition] leaves the composition. [block] will run in the **apply** scope of the
- * composition's [Recomposer], which is usually your UI's main thread.
- *
- * [block] will be launched **once** when this call enters the composition; recomposition will not
- * cause [block] to launch again. To re-launch a suspend function when inputs change, see the
- * other overloads of [launchInComposition] that accept input value parameters.
- */
-@Suppress("DEPRECATION")
-@Deprecated(
-    "Renamed to LaunchedTask; custom scope removed",
-    replaceWith = ReplaceWith("LaunchedTask(block)", "androidx.compose.runtime.LaunchedTask")
-)
-@Composable
-fun launchInComposition(
-    block: suspend CompositionCoroutineScope.() -> Unit
-) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember { SuspendingEffect(recomposer, block) }
-}
-
-/**
- * Launch a suspending side effect when this composition is committed and cancel it
- * when [launchInComposition] leaves the composition. If [key] has changed since the last
- * recomposition, cancel the currently running [block] and launch again. [block] will run in the
- * **apply** scope of the composition's [Recomposer], which is usually your UI's main thread.
- *
- * This function should **not** be used to (re-)launch ongoing tasks in response to callback
- * events by way of storing callback data in [MutableState] passed to [key]. Instead, see
- * [rememberCoroutineScope] to obtain a [CoroutineScope] that may be used to launch ongoing jobs
- * scoped to the composition in response to event callbacks.
- */
-@Suppress("DEPRECATION")
-@Deprecated(
-    "Renamed to LaunchedTask; custom scope removed",
-    replaceWith = ReplaceWith("LaunchedTask(key, block)", "androidx.compose.runtime.LaunchedTask")
-)
-@Composable
-fun launchInComposition(
-    key: Any?,
-    block: suspend CompositionCoroutineScope.() -> Unit
-) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key) { SuspendingEffect(recomposer, block) }
-}
-
-/**
- * Launch a suspending side effect when this composition is committed and cancel it
- * when [launchInComposition] leaves the composition. If [key1] or [key2] has changed since the last
- * recomposition, cancel the currently running [block] and launch again. By default [block] will
- * run in the **apply** scope of the composition's [Recomposer], which is usually your UI's main
- * thread.
- *
- * This function should **not** be used to (re-)launch ongoing tasks in response to callback
- * events by way of storing callback data in [MutableState] passed to [key1] or [key2]. Instead, see
- * [rememberCoroutineScope] to obtain a [CoroutineScope] that may be used to launch ongoing jobs
- * scoped to the composition in response to event callbacks.
- */
-@Suppress("DEPRECATION")
-@Deprecated(
-    "Renamed to LaunchedTask; custom scope removed",
-    replaceWith = ReplaceWith(
-        "LaunchedTask(key1, key2, block)",
-        "androidx.compose.runtime.LaunchedTask"
-    )
-)
-@Composable
-fun launchInComposition(
-    key1: Any?,
-    key2: Any?,
-    block: suspend CompositionCoroutineScope.() -> Unit
-) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key1, key2) { SuspendingEffect(recomposer, block) }
-}
-
-/**
- * Launch a suspending side effect when this composition is committed and cancel it
- * when [launchInComposition] leaves the composition. If [key1], [key2] or [key3] has changed since
- * the last recomposition, cancel the currently running [block] and launch again. By default [block]
- * will run in the **apply** scope of the composition's [Recomposer], which is usually your UI's
- * main thread.
- *
- * This function should **not** be used to (re-)launch ongoing tasks in response to callback
- * events by way of storing callback data in [MutableState] passed to [key1], [key2] or [key3].
- * Instead, see [rememberCoroutineScope] to obtain a [CoroutineScope] that may be used to launch
- * ongoing jobs scoped to the composition in response to event callbacks.
- */
-@Suppress("DEPRECATION")
-@Deprecated(
-    "Renamed to LaunchedTask; custom scope removed",
-    replaceWith = ReplaceWith(
-        "LaunchedTask(key1, key2, key3, block)",
-        "androidx.compose.runtime.LaunchedTask"
-    )
-)
-@Composable
-fun launchInComposition(
-    key1: Any?,
-    key2: Any?,
-    key3: Any?,
-    block: suspend CompositionCoroutineScope.() -> Unit
-) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key1, key2, key3) { SuspendingEffect(recomposer, block) }
-}
-
-/**
- * Launch a suspending side effect when this composition is committed and cancel it
- * when [launchInComposition] leaves the composition. If [keys] have changed since the last
- * recomposition, cancel the currently running [block] and launch again. By default [block] will
- * run in the **apply** scope of the composition's [Recomposer], which is usually your UI's main
- * thread.
- *
- * This function should **not** be used to (re-)launch ongoing tasks in response to callback
- * events by way of storing callback data in [MutableState] passed to [keys]. Instead, see
- * [rememberCoroutineScope] to obtain a [CoroutineScope] that may be used to launch ongoing jobs
- * scoped to the composition in response to event callbacks.
- */
-@Suppress("DEPRECATION")
-@Deprecated(
-    "Renamed to LaunchedTask; custom scope removed",
-    replaceWith = ReplaceWith(
-        "LaunchedTask(*keys, block)",
-        "androidx.compose.runtime.LaunchedTask"
-    )
-)
-@Composable
-fun launchInComposition(
-    vararg keys: Any?,
-    block: suspend CompositionCoroutineScope.() -> Unit
-) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(*keys) { SuspendingEffect(recomposer, block) }
-}
-
 @PublishedApi
 internal class CompositionScopedCoroutineScopeCanceller(
     val coroutineScope: CoroutineScope
@@ -248,7 +51,7 @@
         }
     )
 } else {
-    val applyContext = composer.recomposer.applyingCoroutineContext
+    val applyContext = composer.parentReference.applyingCoroutineContext
     if (applyContext == null) {
         CoroutineScope(
             Job().apply {
@@ -279,7 +82,7 @@
  * interaction where the response to that event needs to unfold over time and be cancelled if the
  * composable managing that process leaves the composition. Jobs should never be launched into
  * **any** coroutine scope as a side effect of composition itself. For scoped ongoing jobs
- * initiated by composition, see [launchInComposition].
+ * initiated by composition, see [LaunchedTask].
  *
  * This function will not throw if preconditions are not met, as composable functions do not yet
  * fully support exceptions. Instead the returned scope's [CoroutineScope.coroutineContext] will
@@ -300,7 +103,7 @@
 }
 
 private class LaunchedTaskImpl(
-    private val recomposer: Recomposer,
+    private val parentRef: CompositionReference,
     private val task: suspend CoroutineScope.() -> Unit
 ) : CompositionLifecycleObserver {
 
@@ -309,7 +112,7 @@
     override fun onEnter() {
         job?.cancel("Old job was still running!")
         val scope = CoroutineScope(
-            recomposer.applyingCoroutineContext
+            parentRef.applyingCoroutineContext
                 ?: error("cannot launch LaunchedTask - Recomposer is not running")
         )
         job = scope.launch(block = task)
@@ -333,9 +136,8 @@
 fun LaunchedTask(
     block: suspend CoroutineScope.() -> Unit
 ) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember { LaunchedTaskImpl(recomposer, block) }
+    val parentRef = currentComposer.parentReference
+    remember { LaunchedTaskImpl(parentRef, block) }
 }
 
 /**
@@ -354,9 +156,8 @@
     key: Any?,
     block: suspend CoroutineScope.() -> Unit
 ) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key) { LaunchedTaskImpl(recomposer, block) }
+    val parentRef = currentComposer.parentReference
+    remember(key) { LaunchedTaskImpl(parentRef, block) }
 }
 
 /**
@@ -376,9 +177,8 @@
     key2: Any?,
     block: suspend CoroutineScope.() -> Unit
 ) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key1, key2) { LaunchedTaskImpl(recomposer, block) }
+    val parentRef = currentComposer.parentReference
+    remember(key1, key2) { LaunchedTaskImpl(parentRef, block) }
 }
 
 /**
@@ -399,9 +199,8 @@
     key3: Any?,
     block: suspend CoroutineScope.() -> Unit
 ) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(key1, key2, key3) { LaunchedTaskImpl(recomposer, block) }
+    val parentRef = currentComposer.parentReference
+    remember(key1, key2, key3) { LaunchedTaskImpl(parentRef, block) }
 }
 
 /**
@@ -420,7 +219,6 @@
     vararg keys: Any?,
     block: suspend CoroutineScope.() -> Unit
 ) {
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    remember(*keys) { LaunchedTaskImpl(recomposer, block) }
+    val parentRef = currentComposer.parentReference
+    remember(*keys) { LaunchedTaskImpl(parentRef, block) }
 }
diff --git a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPaint.kt b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPaint.kt
index 695f8f8..a22418d 100644
--- a/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPaint.kt
+++ b/compose/ui/ui-graphics/src/desktopMain/kotlin/androidx/compose/ui/graphics/DesktopPaint.kt
@@ -29,6 +29,10 @@
 class DesktopPaint : Paint {
     internal val skija = org.jetbrains.skija.Paint()
 
+    constructor() {
+        filterQuality = FilterQuality.Medium
+    }
+
     override fun asFrameworkPaint(): NativePaint = skija
 
     override var alpha: Float
diff --git a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
index 6d71958e..026300e 100644
--- a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
+++ b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/DesktopPaintTest.kt
@@ -39,7 +39,7 @@
         assertEquals(0f, paint.strokeMiterLimit)
         assertEquals(StrokeJoin.Round, paint.strokeJoin)
         assertEquals(true, paint.isAntiAlias)
-        assertEquals(FilterQuality.None, paint.filterQuality)
+        assertEquals(FilterQuality.Medium, paint.filterQuality)
         assertEquals(BlendMode.SrcOver, paint.blendMode)
         assertEquals(null, paint.colorFilter)
         assertEquals(null, paint.shader)
@@ -98,7 +98,9 @@
             srcSize = IntSize(2, 4),
             dstOffset = IntOffset(0, 4),
             dstSize = IntSize(4, 12),
-            paint = redPaint
+            paint = redPaint.apply {
+                filterQuality = FilterQuality.None
+            }
         )
         canvas.drawImageRect(
             image = imageFromResource("androidx/compose/desktop/test.png"),
diff --git a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
index 62f78f1..c25ee47 100644
--- a/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
+++ b/compose/ui/ui-graphics/src/desktopTest/kotlin/androidx/compose/ui/graphics/canvas/DesktopCanvasTest.kt
@@ -23,6 +23,7 @@
 import androidx.compose.ui.graphics.ClipOp
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.DesktopGraphicsTest
+import androidx.compose.ui.graphics.FilterQuality
 import androidx.compose.ui.graphics.Matrix
 import androidx.compose.ui.graphics.Paint
 import androidx.compose.ui.graphics.StrokeCap
@@ -115,7 +116,9 @@
             srcSize = IntSize(2, 4),
             dstOffset = IntOffset(0, 4),
             dstSize = IntSize(4, 12),
-            paint = redPaint
+            paint = redPaint.apply {
+                filterQuality = FilterQuality.None
+            }
         )
 
         screenshotRule.snap(surface)
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index 697d8f9..0df1e30 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2145,7 +2145,7 @@
   }
 
   public final class SubcompositionKt {
-    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
   public final class TestTagKt {
@@ -2189,12 +2189,10 @@
   }
 
   public final class WrapperKt {
-    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.Recomposer recomposer, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parentComposition, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
     method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
-    method @Deprecated @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
 }
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index 697d8f9..0df1e30 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2145,7 +2145,7 @@
   }
 
   public final class SubcompositionKt {
-    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
   public final class TestTagKt {
@@ -2189,12 +2189,10 @@
   }
 
   public final class WrapperKt {
-    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.Recomposer recomposer, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parentComposition, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
     method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
-    method @Deprecated @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
 }
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index b473283..6f742ec 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2222,7 +2222,7 @@
   }
 
   public final class SubcompositionKt {
-    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
   public final class TestTagKt {
@@ -2266,12 +2266,10 @@
   }
 
   public final class WrapperKt {
-    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.Recomposer recomposer, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, androidx.compose.runtime.Recomposer recomposer, optional androidx.compose.runtime.CompositionReference? parentComposition, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, kotlin.jvm.functions.Function0<kotlin.Unit> content);
-    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
+    method public static androidx.compose.runtime.Composition setContent(androidx.activity.ComponentActivity, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method public static androidx.compose.runtime.Composition setContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> content);
+    method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.view.ViewGroup, optional androidx.compose.runtime.CompositionReference parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
     method @Deprecated public static androidx.compose.runtime.Composition setViewContent(android.app.Activity, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
-    method @Deprecated @MainThread public static androidx.compose.runtime.Composition subcomposeInto(androidx.compose.ui.node.LayoutNode container, optional androidx.compose.runtime.CompositionReference? parent, kotlin.jvm.functions.Function0<kotlin.Unit> composable);
   }
 
 }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
index afcc9d8..a232f05 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/layout/SubcomposeLayoutTest.kt
@@ -528,7 +528,7 @@
             }
         }
 
-        assertTrue(stateUsedLatch.await(1, TimeUnit.SECONDS))
+        assertTrue("state was used in setup", stateUsedLatch.await(1, TimeUnit.SECONDS))
 
         stateUsedLatch = CountDownLatch(1)
         scenario.onActivity {
@@ -544,7 +544,10 @@
             container1.addView(container2)
         }
 
-        assertTrue(stateUsedLatch.await(1, TimeUnit.SECONDS))
+        assertTrue(
+            "state was used after reattaching view",
+            stateUsedLatch.await(1, TimeUnit.SECONDS)
+        )
     }
 }
 
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WrapperTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WrapperTest.kt
index 4291492..25dff54 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WrapperTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WrapperTest.kt
@@ -150,12 +150,11 @@
             it.setContent {
                 val ambient = ambientOf<Float>()
                 Providers(ambient provides 1f) {
-                    val recomposer = Recomposer.current()
                     val composition = compositionReference()
 
                     AndroidView({ frameLayout })
                     onCommit {
-                        frameLayout.setContent(recomposer, composition) {
+                        frameLayout.setContent(composition) {
                             value = ambient.current
                             composedLatch.countDown()
                         }
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
index 7ea6205..3b8c762 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
@@ -56,18 +56,16 @@
 @Deprecated(
     "setViewContent was deprecated - use setContent instead",
     ReplaceWith(
-        "setContent(Recomposer.current(), parent, composable)",
-        "androidx.compose.ui.platform.setContent",
-        "androidx.compose.runtime.Recomposer"
+        "setContent(parent, composable)",
+        "androidx.compose.ui.platform.setContent"
     )
 )
 fun ViewGroup.setViewContent(
-    parent: CompositionReference? = null,
+    parent: CompositionReference = Recomposer.current(),
     composable: @Composable () -> Unit
 ): Composition = compositionFor(
     this,
     UiApplier(this),
-    Recomposer.current(),
     parent,
     onCreated = {
         removeAllViews()
@@ -92,8 +90,7 @@
     "setViewContent was deprecated - use setContent instead",
     ReplaceWith(
         "setContent(composable)",
-        "androidx.compose.ui.platform.setContent",
-        "androidx.compose.runtime.Recomposer"
+        "androidx.compose.ui.platform.setContent"
     )
 )
 fun Activity.setViewContent(composable: @Composable () -> Unit): Composition {
@@ -107,7 +104,7 @@
         .getChildAt(0) as? ViewGroup
         ?: FrameLayout(this).also { setContentView(it) }
     @Suppress("DEPRECATION")
-    return root.setViewContent(null, composable)
+    return root.setViewContent(composable = composable)
 }
 
 // TODO(chuckj): This is a temporary work-around until subframes exist so that
@@ -117,46 +114,29 @@
 @OptIn(ExperimentalComposeApi::class, ExperimentalLayoutNodeApi::class)
 internal actual fun actualSubcomposeInto(
     container: LayoutNode,
-    recomposer: Recomposer,
-    parent: CompositionReference?,
+    parent: CompositionReference,
     composable: @Composable () -> Unit
 ): Composition = compositionFor(
     container,
     UiApplier(container),
-    recomposer,
     parent
 ).apply {
     setContent(composable)
 }
 
-@Deprecated(
-    "Specify Recomposer explicitly",
-    ReplaceWith(
-        "subcomposeInto(context, container, Recomposer.current(), parent, composable)",
-        "androidx.compose.runtime.Recomposer"
-    )
-)
-@MainThread
-@OptIn(ExperimentalLayoutNodeApi::class)
-fun subcomposeInto(
-    container: LayoutNode,
-    parent: CompositionReference? = null,
-    composable: @Composable () -> Unit
-): Composition = subcomposeInto(container, Recomposer.current(), parent, composable)
-
 /**
  * Composes the given composable into the given activity. The [content] will become the root view
  * of the given activity.
  *
  * [Composition.dispose] is called automatically when the Activity is destroyed.
  *
- * @param recomposer The [Recomposer] to coordinate scheduling of composition updates
+ * @param parent The parent composition reference to coordinate scheduling of composition updates
  * @param content A `@Composable` function declaring the UI contents
  */
 fun ComponentActivity.setContent(
     // Note: Recomposer.current() is the default here since all Activity view trees are hosted
     // on the main thread.
-    recomposer: Recomposer = Recomposer.current(),
+    parent: CompositionReference = Recomposer.current(),
     content: @Composable () -> Unit
 ): Composition {
     FrameManager.ensureStarted()
@@ -166,26 +146,24 @@
         ?: AndroidComposeView(this).also {
             setContentView(it.view, DefaultLayoutParams)
         }
-    return doSetContent(composeView, recomposer, null, content)
+    return doSetContent(composeView, parent, content)
 }
 
 /**
  * Composes the given composable into the given view.
  *
- * The new composition can be logically "linked" to an existing one, by providing a non-null
- * [parentComposition]. This will ensure that invalidations and ambients will flow through
+ * The new composition can be logically "linked" to an existing one, by providing a
+ * [parent]. This will ensure that invalidations and ambients will flow through
  * the two compositions as if they were not separate.
  *
  * Note that this [ViewGroup] should have an unique id for the saved instance state mechanism to
  * be able to save and restore the values used within the composition. See [View.setId].
  *
- * @param recomposer The [Recomposer] to coordinate scheduling of composition updates.
- * @param parentComposition The parent composition reference, if applicable.
+ * @param parent The [Recomposer] or parent composition reference.
  * @param content Composable that will be the content of the view.
  */
 fun ViewGroup.setContent(
-    recomposer: Recomposer,
-    parentComposition: CompositionReference? = null,
+    parent: CompositionReference = Recomposer.current(),
     content: @Composable () -> Unit
 ): Composition {
     FrameManager.ensureStarted()
@@ -195,32 +173,12 @@
         } else {
             removeAllViews(); null
         } ?: AndroidComposeView(context).also { addView(it.view, DefaultLayoutParams) }
-    return doSetContent(composeView, recomposer, parentComposition, content)
+    return doSetContent(composeView, parent, content)
 }
 
-/**
- * Composes the given composable into the given view.
- *
- * Note that this [ViewGroup] should have an unique id for the saved instance state mechanism to
- * be able to save and restore the values used within the composition. See [View.setId].
- *
- * @param content Composable that will be the content of the view.
- */
-@Deprecated(
-    "Specify Recomposer explicitly",
-    ReplaceWith(
-        "setContent(Recomposer.current(), content)",
-        "androidx.compose.runtime.Recomposer"
-    )
-)
-fun ViewGroup.setContent(
-    content: @Composable () -> Unit
-): Composition = setContent(recomposer = Recomposer.current(), content = content)
-
 private fun doSetContent(
     owner: AndroidOwner,
-    recomposer: Recomposer,
-    parentComposition: CompositionReference?,
+    parent: CompositionReference,
     content: @Composable () -> Unit
 ): Composition {
     if (inspectionWanted(owner)) {
@@ -231,7 +189,7 @@
         enableDebugInspectorInfo()
     }
     @OptIn(ExperimentalComposeApi::class)
-    val original = compositionFor(owner.root, UiApplier(owner.root), recomposer, parentComposition)
+    val original = compositionFor(owner.root, UiApplier(owner.root), parent)
     val wrapped = owner.view.getTag(R.id.wrapped_composition_tag)
         as? WrappedComposition
         ?: WrappedComposition(owner, original).also {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.kt
index 1920f11..c2fde88 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidDialog.kt
@@ -26,11 +26,8 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Composition
 import androidx.compose.runtime.CompositionReference
-import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Immutable
-import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.compositionReference
-import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.onActive
 import androidx.compose.runtime.onCommit
 import androidx.compose.runtime.remember
@@ -81,15 +78,7 @@
 ) {
     val view = ViewAmbient.current
 
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
-    // The recomposer can't change.
-    val dialog = remember(view) {
-        DialogWrapper(
-            view,
-            recomposer
-        )
-    }
+    val dialog = remember(view) { DialogWrapper(view) }
     dialog.onCloseRequest = onDismissRequest
     remember(properties) { dialog.setProperties(properties) }
 
@@ -130,8 +119,7 @@
 ) : FrameLayout(context), DialogWindowProvider
 
 private class DialogWrapper(
-    private val composeView: View,
-    private val recomposer: Recomposer
+    private val composeView: View
 ) : Dialog(composeView.context) {
     lateinit var onCloseRequest: () -> Unit
 
@@ -139,9 +127,10 @@
     private var composition: Composition? = null
 
     init {
-        window!!.requestFeature(Window.FEATURE_NO_TITLE)
-        window!!.setBackgroundDrawableResource(android.R.color.transparent)
-        dialogLayout = DialogLayout(context, window!!)
+        val window = window ?: error("Dialog has no window")
+        window.requestFeature(Window.FEATURE_NO_TITLE)
+        window.setBackgroundDrawableResource(android.R.color.transparent)
+        dialogLayout = DialogLayout(context, window)
         setContentView(dialogLayout)
         ViewTreeLifecycleOwner.set(dialogLayout, ViewTreeLifecycleOwner.get(composeView))
         ViewTreeViewModelStoreOwner.set(dialogLayout, ViewTreeViewModelStoreOwner.get(composeView))
@@ -154,8 +143,7 @@
     // TODO(b/159900354): Make the Android Dialog full screen and the scrim fully transparent
 
     fun setContent(parentComposition: CompositionReference, children: @Composable () -> Unit) {
-        // TODO: This should probably create a child composition of the original
-        composition = dialogLayout.setContent(recomposer, parentComposition, children)
+        composition = dialogLayout.setContent(parentComposition, children)
     }
 
     private fun setSecureFlagEnabled(secureFlagEnabled: Boolean) {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.kt
index 4e5941e..49799a9 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/window/AndroidPopup.kt
@@ -29,10 +29,8 @@
 import android.widget.FrameLayout
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Composition
-import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Immutable
 import androidx.compose.runtime.compositionReference
-import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.emptyContent
 import androidx.compose.runtime.onCommit
 import androidx.compose.runtime.onDispose
@@ -123,12 +121,9 @@
         layout(0, 0) {}
     }
 
-    // TODO(lmr): refactor these APIs so that recomposer isn't necessary
-    @OptIn(ExperimentalComposeApi::class)
-    val recomposer = currentComposer.recomposer
     val parentComposition = compositionReference()
     onCommit {
-        composition = popupLayout.setContent(recomposer, parentComposition) {
+        composition = popupLayout.setContent(parentComposition) {
             SimpleStack(
                 Modifier.semantics { this.popup() }.onGloballyPositioned {
                     // Get the size of the content
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorCompose.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorCompose.kt
index 2c7420f..ba5e8ae 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorCompose.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorCompose.kt
@@ -21,7 +21,6 @@
 import androidx.compose.runtime.Composition
 import androidx.compose.runtime.CompositionReference
 import androidx.compose.runtime.ExperimentalComposeApi
-import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.compositionFor
 import androidx.compose.runtime.emit
 import androidx.compose.ui.graphics.Brush
@@ -101,13 +100,11 @@
 @Suppress("NAME_SHADOWING")
 internal fun composeVector(
     container: VectorComponent,
-    recomposer: Recomposer,
-    parent: CompositionReference? = null,
+    parent: CompositionReference,
     composable: @Composable (viewportWidth: Float, viewportHeight: Float) -> Unit
 ): Composition = compositionFor(
     container,
     VectorApplier(container.root),
-    recomposer,
     parent
 ).apply {
     setContent {
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
index 6d69b86..b066954 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/graphics/vector/VectorPainter.kt
@@ -17,9 +17,7 @@
 package androidx.compose.ui.graphics.vector
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.compositionReference
-import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.onDispose
@@ -191,8 +189,6 @@
         }
         val composition = composeVector(
             vector,
-            @OptIn(ExperimentalComposeApi::class)
-            currentComposer.recomposer,
             compositionReference(),
             children
         )
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
index 10a7e44..14601bc 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/layout/SubcomposeLayout.kt
@@ -23,7 +23,6 @@
 import androidx.compose.runtime.CompositionLifecycleObserver
 import androidx.compose.runtime.CompositionReference
 import androidx.compose.runtime.ExperimentalComposeApi
-import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.compositionReference
 import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.emit
@@ -79,8 +78,6 @@
     measureBlock: SubcomposeMeasureScope<T>.(Constraints) -> MeasureScope.MeasureResult
 ) {
     val state = remember { SubcomposeLayoutState<T>() }
-    // TODO(lelandr): refactor these APIs so that recomposer isn't necessary
-    state.recomposer = currentComposer.recomposer
     state.compositionRef = compositionReference()
 
     val materialized = currentComposer.materialize(modifier)
@@ -122,8 +119,6 @@
 private class SubcomposeLayoutState<T> :
     SubcomposeMeasureScope<T>,
     CompositionLifecycleObserver {
-    // Values set during the composition
-    var recomposer: Recomposer? = null
     var compositionRef: CompositionReference? = null
 
     // MeasureScope delegation
@@ -190,9 +185,14 @@
     private fun subcompose(node: LayoutNode, nodeState: NodeState<T>) {
         node.ignoreModelReads {
             val content = nodeState.content
-            nodeState.composition = subcomposeInto(node, recomposer!!, compositionRef!!) {
-                content()
-            }
+            nodeState.composition = subcomposeInto(
+                container = node,
+                parent = compositionRef ?: error("parent composition reference not set"),
+                // Do not optimize this by passing nodeState.content directly; the additional
+                // composable function call from the lambda expression affects the scope of
+                // recomposition and recomposition of siblings.
+                composable = { content() }
+            )
         }
     }
 
diff --git a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/Subcomposition.kt b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/Subcomposition.kt
index 4c5b375..d821c90 100644
--- a/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/Subcomposition.kt
+++ b/compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/Subcomposition.kt
@@ -19,7 +19,6 @@
 import androidx.compose.runtime.Composition
 import androidx.compose.runtime.CompositionReference
 import androidx.compose.runtime.ExperimentalComposeApi
-import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.node.ExperimentalLayoutNodeApi
 import androidx.compose.ui.node.LayoutNode
 import androidx.compose.ui.util.annotation.MainThread
@@ -27,8 +26,7 @@
 @OptIn(ExperimentalLayoutNodeApi::class)
 internal expect fun actualSubcomposeInto(
     container: LayoutNode,
-    recomposer: Recomposer,
-    parent: CompositionReference?,
+    parent: CompositionReference,
     composable: @Composable () -> Unit
 ): Composition
 
@@ -36,7 +34,6 @@
 @MainThread
 fun subcomposeInto(
     container: LayoutNode,
-    recomposer: Recomposer,
-    parent: CompositionReference? = null,
+    parent: CompositionReference,
     composable: @Composable () -> Unit
-): Composition = actualSubcomposeInto(container, recomposer, parent, composable)
\ No newline at end of file
+): Composition = actualSubcomposeInto(container, parent, composable)
\ No newline at end of file
diff --git a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Wrapper.kt b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
index 671389d..5554e8b 100644
--- a/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
+++ b/compose/ui/ui/src/desktopMain/kotlin/androidx/compose/ui/platform/Wrapper.kt
@@ -68,13 +68,11 @@
 @OptIn(ExperimentalComposeApi::class, ExperimentalLayoutNodeApi::class)
 internal actual fun actualSubcomposeInto(
     container: LayoutNode,
-    recomposer: Recomposer,
-    parent: CompositionReference?,
+    parent: CompositionReference,
     composable: @Composable () -> Unit
 ): Composition = compositionFor(
     container,
     DesktopUiApplier(container),
-    recomposer,
     parent
 ).apply {
     setContent(composable)
diff --git a/navigation/navigation-compose/api/current.txt b/navigation/navigation-compose/api/current.txt
index bb73fec..01cad51 100644
--- a/navigation/navigation-compose/api/current.txt
+++ b/navigation/navigation-compose/api/current.txt
@@ -12,8 +12,15 @@
     ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, internal kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  public final class NamedNavArgument {
+  }
+
+  public final class NamedNavArgumentKt {
+    method @androidx.navigation.NavDestinationDsl public static androidx.navigation.compose.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
   public final class NavGraphBuilderKt {
-    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, optional java.util.List<androidx.navigation.compose.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
   public final class NavHostControllerKt {
diff --git a/navigation/navigation-compose/api/public_plus_experimental_current.txt b/navigation/navigation-compose/api/public_plus_experimental_current.txt
index bb73fec..01cad51 100644
--- a/navigation/navigation-compose/api/public_plus_experimental_current.txt
+++ b/navigation/navigation-compose/api/public_plus_experimental_current.txt
@@ -12,8 +12,15 @@
     ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, internal kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  public final class NamedNavArgument {
+  }
+
+  public final class NamedNavArgumentKt {
+    method @androidx.navigation.NavDestinationDsl public static androidx.navigation.compose.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
   public final class NavGraphBuilderKt {
-    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, optional java.util.List<androidx.navigation.compose.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
   public final class NavHostControllerKt {
diff --git a/navigation/navigation-compose/api/restricted_current.txt b/navigation/navigation-compose/api/restricted_current.txt
index bb73fec..01cad51 100644
--- a/navigation/navigation-compose/api/restricted_current.txt
+++ b/navigation/navigation-compose/api/restricted_current.txt
@@ -12,8 +12,15 @@
     ctor public ComposeNavigator.Destination(androidx.navigation.compose.ComposeNavigator navigator, internal kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
+  public final class NamedNavArgument {
+  }
+
+  public final class NamedNavArgumentKt {
+    method @androidx.navigation.NavDestinationDsl public static androidx.navigation.compose.NamedNavArgument navArgument(String name, kotlin.jvm.functions.Function1<? super androidx.navigation.NavArgumentBuilder,kotlin.Unit> builder);
+  }
+
   public final class NavGraphBuilderKt {
-    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
+    method public static void composable(androidx.navigation.NavGraphBuilder, Object id, optional java.util.List<androidx.navigation.compose.NamedNavArgument> arguments, optional java.util.List<androidx.navigation.NavDeepLink> deepLinks, kotlin.jvm.functions.Function1<? super androidx.navigation.NavBackStackEntry,kotlin.Unit> content);
   }
 
   public final class NavHostControllerKt {
diff --git a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
index e7cbbc9..da6dd7a 100644
--- a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
+++ b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/BottomBarNavDemo.kt
@@ -23,6 +23,12 @@
 import androidx.compose.material.Scaffold
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.Favorite
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.res.stringResource
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
 import androidx.navigation.compose.navigate
@@ -30,18 +36,17 @@
 import androidx.navigation.compose.samples.Dashboard
 import androidx.navigation.compose.samples.Profile
 import androidx.navigation.compose.samples.Scrollable
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
 
 @Composable
 fun BottomBarNavDemo() {
     val navController = rememberNavController()
 
     var selectedItem by remember { mutableStateOf(0) }
-    val items = listOf("Profile", "Dashboard", "Scrollable")
+    val items = listOf(
+        stringResource(R.string.profile),
+        stringResource(R.string.dashboard),
+        stringResource(R.string.scrollable)
+    )
 
     Scaffold(
         bottomBar = {
diff --git a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavByDeepLinkDemo.kt b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavByDeepLinkDemo.kt
new file mode 100644
index 0000000..cf07e24
--- /dev/null
+++ b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavByDeepLinkDemo.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.navigation.compose.demos
+
+import android.net.Uri
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.Button
+import androidx.compose.material.ButtonConstants
+import androidx.compose.material.Divider
+import androidx.compose.material.TextField
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.savedinstancestate.savedInstanceState
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.input.TextFieldValue
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavController
+import androidx.navigation.compose.NavHost
+import androidx.navigation.compose.composable
+import androidx.navigation.compose.navArgument
+import androidx.navigation.compose.rememberNavController
+import androidx.navigation.compose.samples.Dashboard
+import androidx.navigation.compose.samples.Screen
+import androidx.navigation.navDeepLink
+
+@Composable
+fun NavByDeepLinkDemo() {
+    val navController = rememberNavController()
+    val uri = "https://example.com/dashboard?args="
+    NavHost(navController, startDestination = "Profile") {
+        composable("Profile") { ProfileWithDeepLink(navController, uri) }
+        composable(
+            "Dashboard",
+            arguments = listOf(navArgument("args") { defaultValue = "no value given" }),
+            deepLinks = listOf(navDeepLink { uriPattern = "$uri{args}" })
+        ) { backStackEntry ->
+            Dashboard(navController, backStackEntry.arguments?.get("args") as? String)
+        }
+    }
+}
+
+@Composable
+fun ProfileWithDeepLink(navController: NavController, uri: String) {
+    Column(Modifier.fillMaxSize().then(Modifier.padding(8.dp))) {
+        Text(text = Screen.Profile.title)
+        Divider(color = Color.Black)
+        val state = savedInstanceState(saver = TextFieldValue.Saver) { TextFieldValue() }
+        Box {
+            TextField(
+                value = state.value,
+                onValueChange = { state.value = it },
+                placeholder = { Text("Enter args here") }
+            )
+        }
+        Divider(color = Color.Black)
+        Button(
+            onClick = { navController.navigate(Uri.parse(uri + state.value.text)) },
+            colors = ButtonConstants.defaultButtonColors(backgroundColor = Color.LightGray),
+            modifier = Modifier.fillMaxWidth()
+        ) {
+            Text(text = "Navigate By DeepLink")
+        }
+    }
+}
diff --git a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavigationDemos.kt b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavigationDemos.kt
index dc30a43..8c8b507 100644
--- a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavigationDemos.kt
+++ b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/java/androidx/navigation/compose/demos/NavigationDemos.kt
@@ -24,6 +24,7 @@
     listOf(
         ComposableDemo("Basic Nav Demo") { BasicNavDemo() },
         ComposableDemo("Bottom Bar Nav Demo") { BottomBarNavDemo() },
-        ComposableDemo("Navigation with Args") { NavWithArgsDemo() }
+        ComposableDemo("Navigation with Args") { NavWithArgsDemo() },
+        ComposableDemo("Navigation by DeepLink") { NavByDeepLinkDemo() }
     )
 )
diff --git a/navigation/navigation-compose/integration-tests/navigation-demos/src/main/res/values/strings.xml b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/res/values/strings.xml
new file mode 100644
index 0000000..11c3506
--- /dev/null
+++ b/navigation/navigation-compose/integration-tests/navigation-demos/src/main/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright 2020 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+
+<resources>
+    <string name="profile">Profile</string>
+    <string name="dashboard">Dashboard</string>
+    <string name="scrollable">Scrollable</string>
+</resources>
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavGraphBuilderTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavGraphBuilderTest.kt
index 8285c60..cdbe1f0 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavGraphBuilderTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavGraphBuilderTest.kt
@@ -16,16 +16,16 @@
 
 package androidx.navigation.compose
 
-import androidx.compose.runtime.Composable
+import android.net.Uri
 import androidx.compose.ui.platform.ContextAmbient
 import androidx.core.os.bundleOf
-import androidx.navigation.NavController
-import androidx.navigation.createGraph
+import androidx.navigation.NavDeepLinkRequest
+import androidx.navigation.navDeepLink
 import androidx.navigation.testing.TestNavHostController
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.ui.test.createComposeRule
-import com.google.common.truth.Truth.assertWithMessage
+import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import org.junit.Rule
 import org.junit.Test
@@ -40,30 +40,76 @@
 
     @Test
     fun testCurrentBackStackEntryNavigate() {
-        lateinit var navController: NavController
+        lateinit var navController: TestNavHostController
+        val key = "key"
+        val arg = "myarg"
         composeTestRule.setContent {
             navController = TestNavHostController(ContextAmbient.current)
             navController.navigatorProvider.addNavigator(ComposeNavigator())
 
-            navController.graph =
-                navController.createGraph(startDestination = generateId(FIRST_DESTINATION)) {
-                    composable(FIRST_DESTINATION) { navBackStackEntry ->
-                        TestWithArgs(navBackStackEntry.arguments?.get("test") as String)
-                    }
-                }
+            NavHost(navController, startDestination = FIRST_DESTINATION) {
+                composable(FIRST_DESTINATION) { }
+                composable(SECOND_DESTINATION) { }
+            }
         }
 
         composeTestRule.runOnUiThread {
-            navController.navigate(generateId(FIRST_DESTINATION), bundleOf("test" to "arg"))
+            navController.navigate(generateId(SECOND_DESTINATION), bundleOf(key to arg))
+            assertThat(navController.currentBackStackEntry!!.arguments!!.getString(key))
+                .isEqualTo(arg)
+        }
+    }
+
+    @Test
+    fun testDefaultArguments() {
+        lateinit var navController: TestNavHostController
+        val key = "key"
+        val defaultArg = "default"
+        composeTestRule.setContent {
+            navController = TestNavHostController(ContextAmbient.current)
+            navController.navigatorProvider.addNavigator(ComposeNavigator())
+
+            NavHost(navController, startDestination = FIRST_DESTINATION) {
+                composable(FIRST_DESTINATION) { }
+                composable(
+                    SECOND_DESTINATION,
+                    arguments = listOf(navArgument(key) { defaultValue = defaultArg })
+                ) { }
+            }
+        }
+
+        composeTestRule.runOnUiThread {
+            navController.navigate(generateId(SECOND_DESTINATION))
+            assertThat(navController.currentBackStackEntry!!.arguments!!.getString(key))
+                .isEqualTo(defaultArg)
+        }
+    }
+
+    @Test
+    fun testDeepLink() {
+        lateinit var navController: TestNavHostController
+        val uriString = "https://www.example.com"
+        val deeplink = NavDeepLinkRequest.Builder.fromUri(Uri.parse(uriString)).build()
+        composeTestRule.setContent {
+            navController = TestNavHostController(ContextAmbient.current)
+            navController.navigatorProvider.addNavigator(ComposeNavigator())
+
+            NavHost(navController, startDestination = FIRST_DESTINATION) {
+                composable(FIRST_DESTINATION) { }
+                composable(
+                    SECOND_DESTINATION,
+                    deepLinks = listOf(navDeepLink { uriPattern = uriString })
+                ) { }
+            }
+        }
+
+        composeTestRule.runOnUiThread {
+            navController.navigate(Uri.parse(uriString))
+            assertThat(navController.currentBackStackEntry!!.destination.hasDeepLink(deeplink))
+                .isTrue()
         }
     }
 }
 
-@Composable
-fun TestWithArgs(arg: String) {
-    assertWithMessage("args should be passed to TestWithArgs Composable")
-        .that(arg)
-        .isEqualTo("arg")
-}
-
-private const val FIRST_DESTINATION = 1
\ No newline at end of file
+private const val FIRST_DESTINATION = 1
+private const val SECOND_DESTINATION = 2
\ No newline at end of file
diff --git a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
index 6e2cec0..9d1227e 100644
--- a/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
+++ b/navigation/navigation-compose/src/androidTest/java/androidx/navigation/compose/NavHostTest.kt
@@ -20,6 +20,7 @@
 import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.savedinstancestate.rememberSavedInstanceState
 import androidx.compose.ui.platform.ContextAmbient
 import androidx.navigation.NavDestination
 import androidx.navigation.NavDestinationBuilder
@@ -130,6 +131,81 @@
                 .isEqualTo(generateId("Second"))
         }
     }
+
+    @Test
+    fun testStateOfInactiveScreenIsRestoredWhenWeGoBackToIt() {
+        var increment = 0
+        var numberOnScreen1 = -1
+        lateinit var navController: NavHostController
+        composeTestRule.setContent {
+            navController = rememberNavController()
+
+            NavHost(navController, startDestination = "First") {
+                composable("First") {
+                    numberOnScreen1 = rememberSavedInstanceState { increment++ }
+                }
+                composable("Second") {}
+            }
+        }
+
+        composeTestRule.runOnIdle {
+            assertWithMessage("Initial number should be 0")
+                .that(numberOnScreen1)
+                .isEqualTo(0)
+            numberOnScreen1 = -1
+            navController.navigate("Second")
+        }
+
+        composeTestRule.runOnIdle {
+            navController.popBackStack()
+        }
+
+        composeTestRule.runOnIdle {
+            assertWithMessage("The number should be restored")
+                .that(numberOnScreen1)
+                .isEqualTo(0)
+        }
+    }
+
+    @Test
+    fun stateForScreenRemovedFromBackStackIsNotRestored() {
+        var increment = 0
+        var numberOnScreen2 = -1
+        lateinit var navController: NavHostController
+        composeTestRule.setContent {
+            navController = rememberNavController()
+
+            NavHost(navController, startDestination = "First") {
+                composable("First") {
+                }
+                composable("Second") {
+                    numberOnScreen2 = rememberSavedInstanceState { increment++ }
+                }
+            }
+        }
+
+        composeTestRule.runOnIdle {
+            navController.navigate("Second")
+        }
+
+        composeTestRule.runOnIdle {
+            assertWithMessage("Initial number should be 0")
+                .that(numberOnScreen2)
+                .isEqualTo(0)
+            numberOnScreen2 = -1
+            navController.popBackStack()
+        }
+
+        composeTestRule.runOnIdle {
+            navController.navigate("Second")
+        }
+
+        composeTestRule.runOnIdle {
+            assertWithMessage("The number shouldn't be restored")
+                .that(numberOnScreen2)
+                .isEqualTo(1)
+        }
+    }
 }
 
 private inline fun NavGraphBuilder.test(
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NamedNavArgument.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NamedNavArgument.kt
new file mode 100644
index 0000000..3589239
--- /dev/null
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NamedNavArgument.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.navigation.compose
+
+import androidx.navigation.NavArgument
+import androidx.navigation.NavArgumentBuilder
+import androidx.navigation.NavDestinationDsl
+
+/**
+ * Construct a new [NavArgument]
+ */
+@NavDestinationDsl
+public fun navArgument(
+    name: String,
+    builder: NavArgumentBuilder.() -> Unit
+): NamedNavArgument = NamedNavArgument(name, NavArgumentBuilder().apply(builder).build())
+
+/**
+ * Construct a named [NavArgument] by using the [navArgument] method.
+ */
+public class NamedNavArgument internal constructor(
+    private val name: String,
+    private val argument: NavArgument
+) {
+    internal operator fun component1(): String = name
+    internal operator fun component2(): NavArgument = argument
+}
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
index 4c78e54..60b02ee 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavGraphBuilder.kt
@@ -18,6 +18,7 @@
 
 import androidx.compose.runtime.Composable
 import androidx.navigation.NavBackStackEntry
+import androidx.navigation.NavDeepLink
 import androidx.navigation.NavGraphBuilder
 import androidx.navigation.get
 
@@ -25,12 +26,25 @@
  * Add the [Composable] to the [NavGraphBuilder]
  *
  * @param id id for the destination
+ * @param arguments list of arguments to associate with destination
+ * @param deepLinks list of deep links to associate with the destinations
  * @param content composable for the destination
  */
-public fun NavGraphBuilder.composable(id: Any, content: @Composable (NavBackStackEntry) -> Unit) {
+public fun NavGraphBuilder.composable(
+    id: Any,
+    arguments: List<NamedNavArgument> = listOf(),
+    deepLinks: List<NavDeepLink> = listOf(),
+    content: @Composable (NavBackStackEntry) -> Unit
+) {
     addDestination(
         ComposeNavigator.Destination(provider[ComposeNavigator::class], content).apply {
             setId(generateId(id))
+            arguments.forEach { (argumentName, argument) ->
+                addArgument(argumentName, argument)
+            }
+            deepLinks.forEach { deepLink ->
+                addDeepLink(deepLink)
+            }
         }
     )
 }
diff --git a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
index c2a6d55..eca2ee0 100644
--- a/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
+++ b/navigation/navigation-compose/src/main/java/androidx/navigation/compose/NavHost.kt
@@ -20,15 +20,21 @@
 import androidx.activity.OnBackPressedDispatcherOwner
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Providers
-import androidx.compose.runtime.getValue
 import androidx.compose.runtime.onCommit
 import androidx.compose.runtime.remember
+import androidx.compose.runtime.savedinstancestate.ExperimentalRestorableStateHolder
+import androidx.compose.runtime.savedinstancestate.RestorableStateHolder
+import androidx.compose.runtime.savedinstancestate.rememberRestorableStateHolder
 import androidx.compose.ui.platform.ContextAmbient
 import androidx.compose.ui.platform.LifecycleOwnerAmbient
 import androidx.compose.ui.platform.ViewModelStoreOwnerAmbient
+import androidx.compose.ui.viewinterop.viewModel
+import androidx.lifecycle.SavedStateHandle
+import androidx.lifecycle.ViewModel
 import androidx.navigation.NavGraph
 import androidx.navigation.NavGraphBuilder
 import androidx.navigation.NavHostController
+import java.util.UUID
 
 /**
  * Provides in place in the Compose hierarchy for self contained navigation to occur.
@@ -66,6 +72,7 @@
  * @param navController the navController for this host
  * @param graph the graph for this host
  */
+@OptIn(ExperimentalRestorableStateHolder::class)
 @Composable
 internal fun NavHost(navController: NavHostController, graph: NavGraph) {
     var context = ContextAmbient.current
@@ -94,24 +101,56 @@
         navController.graph = graph
     }
 
+    val restorableStateHolder = rememberRestorableStateHolder<UUID>()
+
     // state from the navController back stack
-    val currentNavBackStackEntry by navController.currentBackStackEntryAsState()
+    val currentNavBackStackEntry = navController.currentBackStackEntryAsState().value
 
     // If the currentNavBackStackEntry is null, we have popped all of the destinations
     // off of the navController back stack and have nothing to show.
     if (currentNavBackStackEntry != null) {
-        val destination = currentNavBackStackEntry!!.destination
+        val destination = currentNavBackStackEntry.destination
         // If the destination is not a compose destination, (e.i. activity, dialog, view, etc)
         // then we do nothing and rely on Navigation to show the proper destination
         if (destination is ComposeNavigator.Destination) {
             // while in the scope of the composable, we provide the navBackStackEntry as the
             // ViewModelStoreOwner and LifecycleOwner
             Providers(
-                ViewModelStoreOwnerAmbient provides currentNavBackStackEntry!!,
-                LifecycleOwnerAmbient provides currentNavBackStackEntry!!
+                ViewModelStoreOwnerAmbient provides currentNavBackStackEntry,
+                LifecycleOwnerAmbient provides currentNavBackStackEntry
             ) {
-                destination.content(currentNavBackStackEntry!!)
+                restorableStateHolder.withRestorableState {
+                    destination.content(currentNavBackStackEntry)
+                }
             }
         }
     }
 }
+
+@OptIn(ExperimentalRestorableStateHolder::class)
+@Composable
+private fun RestorableStateHolder<UUID>.withRestorableState(content: @Composable () -> Unit) {
+    val viewModel = viewModel<BackStackEntryIdViewModel>()
+    viewModel.restorableStateHolder = this
+    withRestorableState(viewModel.id, content)
+}
+
+@OptIn(ExperimentalRestorableStateHolder::class)
+internal class BackStackEntryIdViewModel(handle: SavedStateHandle) : ViewModel() {
+
+    private val IdKey = "RestorableStateHolder_BackStackEntryKey"
+
+    // we create our own id for each back stack entry to support multiple entries of the same
+    // destination. this id will be restored by SavedStateHandle
+    val id: UUID = handle.get<UUID>(IdKey) ?: UUID.randomUUID().also { handle.set(IdKey, it) }
+
+    var restorableStateHolder: RestorableStateHolder<UUID>? = null
+
+    // onCleared will be called on the entries removed from the back stack. here we notify
+    // RestorableStateHolder that we shouldn't save the state for this id, so when we open this
+    // destination again the state will not be restored.
+    override fun onCleared() {
+        super.onCleared()
+        restorableStateHolder?.removeState(id)
+    }
+}
diff --git a/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/ActivityWithActionBar.kt b/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/ActivityWithActionBar.kt
index d130e17..eb1db10 100644
--- a/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/ActivityWithActionBar.kt
+++ b/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/ActivityWithActionBar.kt
@@ -43,6 +43,6 @@
     }
 
     fun setContent(composable: @Composable () -> Unit) {
-        composeHolder.setContent(Recomposer.current(), null, composable)
+        composeHolder.setContent(Recomposer.current(), composable)
     }
 }
diff --git a/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/TestAnimationClockTest.kt b/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/TestAnimationClockTest.kt
index 8f57202..b11c95b 100644
--- a/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/TestAnimationClockTest.kt
+++ b/ui/ui-test/src/androidAndroidTest/kotlin/androidx/ui/test/TestAnimationClockTest.kt
@@ -22,15 +22,14 @@
 import androidx.compose.animation.core.transitionDefinition
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.transition
-import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.Canvas
 import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.State
-import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.ui.Modifier
@@ -123,10 +122,8 @@
     @Test
     fun testAnimation_manuallyAdvanceClock_resumed() = runBlocking {
         val animationState = mutableStateOf(AnimationStates.From)
-        lateinit var recomposer: Recomposer
+        val recomposer = Recomposer.current()
         rule.setContent {
-            @OptIn(ExperimentalComposeApi::class)
-            recomposer = currentComposer.recomposer
             Ui(animationState)
         }
 
diff --git a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/ComposeViewAdapter.kt b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/ComposeViewAdapter.kt
index 3b65bd0..6bdc2f7 100644
--- a/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/ComposeViewAdapter.kt
+++ b/ui/ui-tooling/src/main/java/androidx/ui/tooling/preview/ComposeViewAdapter.kt
@@ -432,7 +432,7 @@
                 }
             }
         }
-        composition = setContent(Recomposer.current(), null, previewComposition)
+        composition = setContent(Recomposer.current(), previewComposition)
     }
 
     /**