Remove compose:runtime-dispatch

Move MonotonicFrameClock and BroadcastFrameClock to compose:runtime and
AndroidUiDispatcher/FrameClock to compose:ui.

Test: Existing tests moved to new homes
Relnote: "The compose:runtime-dispatch artifact is now deprecated.
MonotonicFrameClock can now be found in compose:runtime and
AndroidUiDispatcher can be found in compose:ui."

Change-Id: Ib5c36a427306eceac4b9b16b52a091e864e5b936
diff --git a/compose/animation/animation-core/api/current.txt b/compose/animation/animation-core/api/current.txt
index acd2ab7..56daddd 100644
--- a/compose/animation/animation-core/api/current.txt
+++ b/compose/animation/animation-core/api/current.txt
@@ -446,7 +446,7 @@
     property public final boolean hasObservers;
   }
 
-  public final class ManualFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  public final class ManualFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor @Deprecated public ManualFrameClock(long initialTime, boolean dispatchOnSubscribe);
     ctor public ManualFrameClock(long initialTime);
     method public void advanceClock(long nanos);
diff --git a/compose/animation/animation-core/api/public_plus_experimental_current.txt b/compose/animation/animation-core/api/public_plus_experimental_current.txt
index acd2ab7..56daddd 100644
--- a/compose/animation/animation-core/api/public_plus_experimental_current.txt
+++ b/compose/animation/animation-core/api/public_plus_experimental_current.txt
@@ -446,7 +446,7 @@
     property public final boolean hasObservers;
   }
 
-  public final class ManualFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  public final class ManualFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor @Deprecated public ManualFrameClock(long initialTime, boolean dispatchOnSubscribe);
     ctor public ManualFrameClock(long initialTime);
     method public void advanceClock(long nanos);
diff --git a/compose/animation/animation-core/api/restricted_current.txt b/compose/animation/animation-core/api/restricted_current.txt
index 47a95c9..699b076 100644
--- a/compose/animation/animation-core/api/restricted_current.txt
+++ b/compose/animation/animation-core/api/restricted_current.txt
@@ -446,7 +446,7 @@
     property public final boolean hasObservers;
   }
 
-  public final class ManualFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  public final class ManualFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor @Deprecated public ManualFrameClock(long initialTime, boolean dispatchOnSubscribe);
     ctor public ManualFrameClock(long initialTime);
     method public void advanceClock(long nanos);
diff --git a/compose/animation/animation-core/build.gradle b/compose/animation/animation-core/build.gradle
index 7e1f35a..c55e82a 100644
--- a/compose/animation/animation-core/build.gradle
+++ b/compose/animation/animation-core/build.gradle
@@ -42,10 +42,10 @@
         api "androidx.annotation:annotation:1.1.0"
 
         implementation project(":compose:runtime:runtime")
-        implementation project(":compose:runtime:runtime-dispatch")
         implementation project(":compose:ui:ui-unit")
         implementation project(":compose:ui:ui-util")
         implementation (KOTLIN_STDLIB)
+        api(KOTLIN_COROUTINES_CORE)
 
         testImplementation(ANDROIDX_TEST_RULES)
         testImplementation(ANDROIDX_TEST_RUNNER)
@@ -74,10 +74,10 @@
         sourceSets {
             commonMain.dependencies {
                 implementation project(":compose:runtime:runtime")
-                implementation project(":compose:runtime:runtime-dispatch")
                 implementation project(":compose:ui:ui-unit")
                 implementation project(":compose:ui:ui-util")
                 implementation(KOTLIN_STDLIB_COMMON)
+                api(KOTLIN_COROUTINES_CORE)
             }
             androidMain.dependencies {
                 api "androidx.annotation:annotation:1.1.0"
diff --git a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/InfiniteTransitionTest.kt b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/InfiniteTransitionTest.kt
index e6f7b5a..0ce2950 100644
--- a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/InfiniteTransitionTest.kt
+++ b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/InfiniteTransitionTest.kt
@@ -19,7 +19,7 @@
 import androidx.compose.animation.VectorConverter
 import androidx.compose.animation.animateColor
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.test.junit4.createComposeRule
diff --git a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/SingleValueAnimationTest.kt b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/SingleValueAnimationTest.kt
index 31b6963..fe66c47 100644
--- a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/SingleValueAnimationTest.kt
+++ b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/SingleValueAnimationTest.kt
@@ -19,7 +19,7 @@
 import androidx.compose.animation.animateColorAsState
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
diff --git a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
index e286010..47bccf1 100644
--- a/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
+++ b/compose/animation/animation-core/src/androidAndroidTest/kotlin/androidx/compose/animation/core/TransitionTest.kt
@@ -20,7 +20,7 @@
 import androidx.compose.animation.animateColor
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.State
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/InfiniteTransition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/InfiniteTransition.kt
index e52d481..dd37aaa 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/InfiniteTransition.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/InfiniteTransition.kt
@@ -22,7 +22,7 @@
 import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.State
 import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
index 73b584f..8d7204e 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/ManualFrameClock.kt
@@ -16,8 +16,8 @@
 
 package androidx.compose.animation.core
 
-import androidx.compose.runtime.dispatch.BroadcastFrameClock
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.BroadcastFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 
 /**
  * A [MonotonicFrameClock] built on a [BroadcastFrameClock] that keeps track of the current time.
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
index ffe6bb5..d866d77 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/MonotonicFrameAnimationClock.kt
@@ -16,9 +16,9 @@
 
 package androidx.compose.animation.core
 
-import androidx.compose.runtime.dispatch.DefaultMonotonicFrameClock
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
-import androidx.compose.runtime.dispatch.withFrameMillis
+import androidx.compose.runtime.DefaultMonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
+import androidx.compose.runtime.withFrameMillis
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
index d6a0072..5594bfd 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/SuspendAnimation.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.animation.core
 
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import kotlinx.coroutines.CancellationException
 
 /**
diff --git a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
index d8f3999..fb21aa8 100644
--- a/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
+++ b/compose/animation/animation-core/src/commonMain/kotlin/androidx/compose/animation/core/Transition.kt
@@ -25,7 +25,7 @@
 import androidx.compose.runtime.SideEffect
 import androidx.compose.runtime.State
 import androidx.compose.runtime.collection.mutableVectorOf
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
diff --git a/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SuspendAnimationTest.kt b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SuspendAnimationTest.kt
index 9d09692..a734bd1 100644
--- a/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SuspendAnimationTest.kt
+++ b/compose/animation/animation-core/src/test/java/androidx/compose/animation/core/SuspendAnimationTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.animation.core
 
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.ui.geometry.Offset
 import junit.framework.TestCase.assertEquals
 import junit.framework.TestCase.assertFalse
diff --git a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
index 48e8991..9fe9099 100644
--- a/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
+++ b/compose/compiler/compiler-hosted/integration-tests/src/test/java/androidx/compose/compiler/plugins/kotlin/RobolectricComposeTester.kt
@@ -24,13 +24,13 @@
 import androidx.activity.ComponentActivity
 import androidx.compose.runtime.Composer
 import androidx.compose.runtime.Composition
-import androidx.compose.runtime.EmbeddingContext
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.node.UiApplier
 import androidx.compose.ui.platform.AmbientContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.NonCancellable
 import kotlinx.coroutines.launch
@@ -122,9 +122,8 @@
     companion object {
         @OptIn(ExperimentalCoroutinesApi::class)
         private val recomposer = run {
-            val embeddingContext = EmbeddingContext()
             val mainScope = CoroutineScope(
-                NonCancellable + embeddingContext.mainThreadCompositionContext()
+                NonCancellable + Dispatchers.Main
             )
 
             Recomposer(mainScope.coroutineContext).also {
diff --git a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/animation/Scrolling.kt b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/animation/Scrolling.kt
index 5ea0c9c..5eb7e0d 100644
--- a/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/animation/Scrolling.kt
+++ b/compose/foundation/foundation/src/commonMain/kotlin/androidx/compose/foundation/animation/Scrolling.kt
@@ -20,7 +20,7 @@
 import androidx.compose.animation.core.VectorConverter
 import androidx.compose.animation.core.spring
 import androidx.compose.foundation.gestures.Scrollable
-import androidx.compose.runtime.dispatch.withFrameMillis
+import androidx.compose.runtime.withFrameMillis
 
 /**
  * Smooth scroll by [value] pixels.
diff --git a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
index 0726cf4..3d4fe80 100644
--- a/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
+++ b/compose/foundation/foundation/src/test/kotlin/androidx/compose/foundation/gestures/SuspendingGestureTestUtil.kt
@@ -25,7 +25,7 @@
 import androidx.compose.runtime.Recomposer
 import androidx.compose.runtime.ControlledComposition
 import androidx.compose.runtime.currentComposer
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.runtime.withRunningRecomposer
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
diff --git a/compose/runtime/runtime-dispatch/api/current.txt b/compose/runtime/runtime-dispatch/api/current.txt
index f8f939f..059af93 100644
--- a/compose/runtime/runtime-dispatch/api/current.txt
+++ b/compose/runtime/runtime-dispatch/api/current.txt
@@ -1,60 +1,13 @@
 // Signature format: 4.0
 package androidx.compose.runtime.dispatch {
 
-  public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.dispatch.MonotonicFrameClock getDefaultMonotonicFrameClock();
-  }
-
-  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
-    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
-    method public android.view.Choreographer getChoreographer();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
-    property public final android.view.Choreographer choreographer;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
-    field public static final androidx.compose.runtime.dispatch.AndroidUiDispatcher.Companion Companion;
-  }
-
-  public static final class AndroidUiDispatcher.Companion {
-    method public kotlin.coroutines.CoroutineContext getCurrentThread();
-    method public kotlin.coroutines.CoroutineContext getMain();
-    property public final kotlin.coroutines.CoroutineContext CurrentThread;
-    property public final kotlin.coroutines.CoroutineContext Main;
-  }
-
-  public final class AndroidUiDispatcherKt {
-  }
-
-  public final class AndroidUiFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
-    method public android.view.Choreographer getChoreographer();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final android.view.Choreographer choreographer;
-  }
-
-  public final class BroadcastFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
-    ctor public BroadcastFrameClock();
-    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
-    method public boolean getHasAwaiters();
-    method public void sendFrame(long timeNanos);
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final boolean hasAwaiters;
-  }
-
-  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
-    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
-    field public static final androidx.compose.runtime.dispatch.MonotonicFrameClock.Key Key;
-  }
-
-  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.dispatch.MonotonicFrameClock> {
+  public final class ExpectKt {
+    method @Deprecated public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class MonotonicFrameClockKt {
-    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.dispatch.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
 
 }
diff --git a/compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt b/compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt
index f8f939f..059af93 100644
--- a/compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime-dispatch/api/public_plus_experimental_current.txt
@@ -1,60 +1,13 @@
 // Signature format: 4.0
 package androidx.compose.runtime.dispatch {
 
-  public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.dispatch.MonotonicFrameClock getDefaultMonotonicFrameClock();
-  }
-
-  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
-    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
-    method public android.view.Choreographer getChoreographer();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
-    property public final android.view.Choreographer choreographer;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
-    field public static final androidx.compose.runtime.dispatch.AndroidUiDispatcher.Companion Companion;
-  }
-
-  public static final class AndroidUiDispatcher.Companion {
-    method public kotlin.coroutines.CoroutineContext getCurrentThread();
-    method public kotlin.coroutines.CoroutineContext getMain();
-    property public final kotlin.coroutines.CoroutineContext CurrentThread;
-    property public final kotlin.coroutines.CoroutineContext Main;
-  }
-
-  public final class AndroidUiDispatcherKt {
-  }
-
-  public final class AndroidUiFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
-    method public android.view.Choreographer getChoreographer();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final android.view.Choreographer choreographer;
-  }
-
-  public final class BroadcastFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
-    ctor public BroadcastFrameClock();
-    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
-    method public boolean getHasAwaiters();
-    method public void sendFrame(long timeNanos);
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final boolean hasAwaiters;
-  }
-
-  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
-    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
-    field public static final androidx.compose.runtime.dispatch.MonotonicFrameClock.Key Key;
-  }
-
-  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.dispatch.MonotonicFrameClock> {
+  public final class ExpectKt {
+    method @Deprecated public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class MonotonicFrameClockKt {
-    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.dispatch.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
 
 }
diff --git a/compose/runtime/runtime-dispatch/api/restricted_current.txt b/compose/runtime/runtime-dispatch/api/restricted_current.txt
index f8f939f..059af93 100644
--- a/compose/runtime/runtime-dispatch/api/restricted_current.txt
+++ b/compose/runtime/runtime-dispatch/api/restricted_current.txt
@@ -1,60 +1,13 @@
 // Signature format: 4.0
 package androidx.compose.runtime.dispatch {
 
-  public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.dispatch.MonotonicFrameClock getDefaultMonotonicFrameClock();
-  }
-
-  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
-    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
-    method public android.view.Choreographer getChoreographer();
-    method public androidx.compose.runtime.dispatch.MonotonicFrameClock getFrameClock();
-    property public final android.view.Choreographer choreographer;
-    property public final androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock;
-    field public static final androidx.compose.runtime.dispatch.AndroidUiDispatcher.Companion Companion;
-  }
-
-  public static final class AndroidUiDispatcher.Companion {
-    method public kotlin.coroutines.CoroutineContext getCurrentThread();
-    method public kotlin.coroutines.CoroutineContext getMain();
-    property public final kotlin.coroutines.CoroutineContext CurrentThread;
-    property public final kotlin.coroutines.CoroutineContext Main;
-  }
-
-  public final class AndroidUiDispatcherKt {
-  }
-
-  public final class AndroidUiFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
-    method public android.view.Choreographer getChoreographer();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final android.view.Choreographer choreographer;
-  }
-
-  public final class BroadcastFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
-    ctor public BroadcastFrameClock();
-    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
-    method public boolean getHasAwaiters();
-    method public void sendFrame(long timeNanos);
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public final boolean hasAwaiters;
-  }
-
-  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
-    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
-    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
-    field public static final androidx.compose.runtime.dispatch.MonotonicFrameClock.Key Key;
-  }
-
-  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.dispatch.MonotonicFrameClock> {
+  public final class ExpectKt {
+    method @Deprecated public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class MonotonicFrameClockKt {
-    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.dispatch.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
-    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method @Deprecated public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
   }
 
 }
diff --git a/compose/runtime/runtime-dispatch/build.gradle b/compose/runtime/runtime-dispatch/build.gradle
index 7694ed5..7967eab 100644
--- a/compose/runtime/runtime-dispatch/build.gradle
+++ b/compose/runtime/runtime-dispatch/build.gradle
@@ -40,6 +40,8 @@
         api(KOTLIN_COROUTINES_CORE)
         api "androidx.annotation:annotation:1.1.0"
 
+        api(project(":compose:ui:ui"))
+
         implementation(KOTLIN_STDLIB_COMMON)
         implementation(KOTLIN_STDLIB)
         implementation("androidx.core:core-ktx:1.1.0")
@@ -69,6 +71,7 @@
             commonMain.dependencies {
                 implementation(KOTLIN_STDLIB_COMMON)
                 api(KOTLIN_COROUTINES_CORE)
+                api(project(":compose:ui:ui"))
             }
             jvmMain.dependencies {
                 implementation(KOTLIN_STDLIB)
diff --git a/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt b/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt
deleted file mode 100644
index 83fa029..0000000
--- a/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/TestActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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.compose.runtime.dispatch
-
-import androidx.core.app.ComponentActivity
-
-class TestActivity : ComponentActivity()
\ No newline at end of file
diff --git a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt b/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt
deleted file mode 100644
index 1beb3a0..0000000
--- a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/ActualAndroid.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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.compose.runtime.dispatch
-
-import android.os.Looper
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.withContext
-
-/**
- * This is an inaccurate implementation that will only be used when running linked against
- * Android SDK stubs in host-side tests. A real implementation should synchronize with the
- * device's default display's vsync rate.
- */
-private object SdkStubsFallbackFrameClock : MonotonicFrameClock {
-    private const val DefaultFrameDelay = 16L // milliseconds
-
-    override suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R =
-        withContext(Dispatchers.Main) {
-            delay(DefaultFrameDelay)
-            onFrame(System.nanoTime())
-        }
-}
-
-actual val DefaultMonotonicFrameClock: MonotonicFrameClock by lazy {
-    // When linked against Android SDK stubs and running host-side tests, APIs such as
-    // Looper.getMainLooper() that will never return null on a real device will return null.
-    // This branch offers an alternative solution.
-    if (Looper.getMainLooper() != null) AndroidUiDispatcher.Main[MonotonicFrameClock]!!
-    else SdkStubsFallbackFrameClock
-}
diff --git a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
index 44010e8..d8e4796 100644
--- a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
+++ b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/Expect.kt
@@ -16,12 +16,17 @@
 
 package androidx.compose.runtime.dispatch
 
+import androidx.compose.runtime.withFrameMillis
+import androidx.compose.runtime.withFrameNanos
+
 /**
  * The [MonotonicFrameClock] used by [withFrameNanos] and [withFrameMillis] if one is not present
  * in the calling [kotlin.coroutines.CoroutineContext].
  */
-// Implementor's note:
-// This frame clock implementation should try to synchronize with the vsync rate of the device's
-// default display. Without this synchronization, any usage of this default clock will result
-// in inconsistent animation frame timing and associated visual artifacts.
-expect val DefaultMonotonicFrameClock: MonotonicFrameClock
+@Suppress("DEPRECATION")
+@Deprecated(
+    "Moved to androidx.compose.runtime",
+    ReplaceWith("androidx.compose.runtime.DefaultMonotonicFrameClock")
+)
+val DefaultMonotonicFrameClock: MonotonicFrameClock
+    get() = androidx.compose.runtime.DefaultMonotonicFrameClock
diff --git a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
index 157c309..3882c52 100644
--- a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
+++ b/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/MonotonicFrameClock.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 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.
@@ -16,91 +16,29 @@
 
 package androidx.compose.runtime.dispatch
 
-import kotlin.coroutines.CoroutineContext
-import kotlin.coroutines.coroutineContext
-
-/**
- * Provides a time source for display frames and the ability to perform an action on the next frame.
- * This may be used for matching timing with the refresh rate of a display or otherwise
- * synchronizing work with a desired frame rate.
- */
-interface MonotonicFrameClock : CoroutineContext.Element {
-    /**
-     * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
-     * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
-     * [onFrame].
-     *
-     * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
-     * as it may be normalized to the target time for the frame, not necessarily a direct,
-     * "now" value.
-     *
-     * The time base of the value provided by [withFrameNanos] is implementation defined.
-     * Time values provided are monotonically increasing; after a call to [withFrameNanos]
-     * completes it must not provide the same value again for a subsequent call.
-     */
-    suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R
-
-    override val key: CoroutineContext.Key<*> get() = Key
-
-    companion object Key : CoroutineContext.Key<MonotonicFrameClock>
-}
+@Deprecated("Moved to androidx.compose.runtime in the compose:runtime artifact")
+typealias MonotonicFrameClock = androidx.compose.runtime.MonotonicFrameClock
 
 /**
  * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
  * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
  * [onFrame].
- *
- * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
- * as it may be normalized to the target time for the frame, not necessarily a direct,
- * "now" value.
- *
- * The time base of the value provided by [MonotonicFrameClock.withFrameMillis] is
- * implementation defined. Time values provided are monotonically increasing; after a call to
- * [MonotonicFrameClock.withFrameMillis] completes it must not provide the same value again for
- * a subsequent call.
  */
-@Suppress("UnnecessaryLambdaCreation")
-suspend inline fun <R> MonotonicFrameClock.withFrameMillis(
-    crossinline onFrame: (frameTimeMillis: Long) -> R
-): R = withFrameNanos { onFrame(it / 1_000_000L) }
-
-/**
- * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
- * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
- * [onFrame].
- *
- * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
- * as it may be normalized to the target time for the frame, not necessarily a direct,
- * "now" value.
- *
- * The time base of the value provided by [withFrameNanos] is implementation defined.
- * Time values provided are monotonically increasing; after a call to [withFrameNanos]
- * completes it must not provide the same value again for a subsequent call.
- *
- * This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
- * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
- * in the [CoroutineContext].
- */
+@Deprecated(
+    "Moved to androidx.compose.runtime",
+    ReplaceWith("androidx.compose.runtime.withFrameNanos(onFrame)")
+)
 suspend fun <R> withFrameNanos(onFrame: (frameTimeMillis: Long) -> R): R =
-    (coroutineContext[MonotonicFrameClock] ?: DefaultMonotonicFrameClock).withFrameNanos(onFrame)
+    androidx.compose.runtime.withFrameNanos(onFrame)
 
 /**
  * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
  * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
  * [onFrame].
- *
- * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
- * as it may be normalized to the target time for the frame, not necessarily a direct,
- * "now" value.
- *
- * The time base of the value provided by [MonotonicFrameClock.withFrameMillis] is
- * implementation defined. Time values provided are monotonically increasing; after a call to
- * [MonotonicFrameClock.withFrameMillis] completes it must not provide the same value again for
- * a subsequent call.
- *
- * This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
- * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
- * in the [CoroutineContext].
  */
+@Deprecated(
+    "Moved to androidx.compose.runtime",
+    ReplaceWith("androidx.compose.runtime.withFrameMillis(onFrame)")
+)
 suspend fun <R> withFrameMillis(onFrame: (frameTimeMillis: Long) -> R): R =
-    (coroutineContext[MonotonicFrameClock] ?: DefaultMonotonicFrameClock).withFrameMillis(onFrame)
+    androidx.compose.runtime.withFrameMillis(onFrame)
diff --git a/compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt b/compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt
deleted file mode 100644
index 711bd90..0000000
--- a/compose/runtime/runtime-dispatch/src/desktopMain/kotlin/androidx/compose/runtime/dispatch/ActualDesktop.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.compose.runtime.dispatch
-
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.yield
-import java.awt.DisplayMode
-import java.awt.GraphicsEnvironment
-
-// TODO implement local Recomposer in each Window, so each Window can have own MonotonicFrameClock.
-//  It is needed for smooth animations and for the case when user have multiple windows on multiple
-//  monitors with different refresh rates.
-//  see https://github.com/JetBrains/compose-jb/issues/137
-actual val DefaultMonotonicFrameClock: MonotonicFrameClock by lazy {
-    object : MonotonicFrameClock {
-        override suspend fun <R> withFrameNanos(
-            onFrame: (Long) -> R
-        ): R {
-            if (GraphicsEnvironment.isHeadless()) {
-                yield()
-            } else {
-                delay(1000L / getFramesPerSecond())
-            }
-            return onFrame(System.nanoTime())
-        }
-
-        private fun getFramesPerSecond(): Int {
-            val refreshRate = GraphicsEnvironment
-                .getLocalGraphicsEnvironment()
-                .screenDevices.maxOfOrNull { it.displayMode.refreshRate }
-                ?: DisplayMode.REFRESH_RATE_UNKNOWN
-            return if (refreshRate != DisplayMode.REFRESH_RATE_UNKNOWN) refreshRate else 60
-        }
-    }
-}
\ No newline at end of file
diff --git a/compose/runtime/runtime/api/current.txt b/compose/runtime/runtime/api/current.txt
index dfe7b99..833d1e5 100644
--- a/compose/runtime/runtime/api/current.txt
+++ b/compose/runtime/runtime/api/current.txt
@@ -17,7 +17,7 @@
   }
 
   public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.EmbeddingContext EmbeddingContext();
+    method public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class ActualJvmKt {
@@ -51,6 +51,16 @@
   public final class BitwiseOperatorsKt {
   }
 
+  public final class BroadcastFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
+    ctor public BroadcastFrameClock();
+    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
+    method public boolean getHasAwaiters();
+    method public void sendFrame(long timeNanos);
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final boolean hasAwaiters;
+  }
+
   @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface Composable {
   }
 
@@ -219,11 +229,6 @@
     method public inline androidx.compose.runtime.DisposableEffectResult onDispose(kotlin.jvm.functions.Function0<kotlin.Unit> onDisposeEffect);
   }
 
-  public interface EmbeddingContext {
-    method public boolean isMainThread();
-    method public kotlin.coroutines.CoroutineContext mainThreadCompositionContext();
-  }
-
   public final class ExpectKt {
   }
 
@@ -269,6 +274,22 @@
     method @androidx.compose.runtime.InternalComposeApi public static void resetSourceInfo();
   }
 
+  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
+    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
+    field public static final androidx.compose.runtime.MonotonicFrameClock.Key Key;
+  }
+
+  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.MonotonicFrameClock> {
+  }
+
+  public final class MonotonicFrameClockKt {
+    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+  }
+
   @androidx.compose.runtime.Stable public interface MutableState<T> extends androidx.compose.runtime.State<T> {
     method public operator T! component1();
     method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
@@ -294,8 +315,8 @@
   @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface NoLiveLiterals {
   }
 
-  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock);
+  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.MonotonicFrameClock frameClock);
     method public boolean isPaused();
     method public void pause();
     method public void resume();
diff --git a/compose/runtime/runtime/api/public_plus_experimental_current.txt b/compose/runtime/runtime/api/public_plus_experimental_current.txt
index dfe7b99..833d1e5 100644
--- a/compose/runtime/runtime/api/public_plus_experimental_current.txt
+++ b/compose/runtime/runtime/api/public_plus_experimental_current.txt
@@ -17,7 +17,7 @@
   }
 
   public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.EmbeddingContext EmbeddingContext();
+    method public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class ActualJvmKt {
@@ -51,6 +51,16 @@
   public final class BitwiseOperatorsKt {
   }
 
+  public final class BroadcastFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
+    ctor public BroadcastFrameClock();
+    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
+    method public boolean getHasAwaiters();
+    method public void sendFrame(long timeNanos);
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final boolean hasAwaiters;
+  }
+
   @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface Composable {
   }
 
@@ -219,11 +229,6 @@
     method public inline androidx.compose.runtime.DisposableEffectResult onDispose(kotlin.jvm.functions.Function0<kotlin.Unit> onDisposeEffect);
   }
 
-  public interface EmbeddingContext {
-    method public boolean isMainThread();
-    method public kotlin.coroutines.CoroutineContext mainThreadCompositionContext();
-  }
-
   public final class ExpectKt {
   }
 
@@ -269,6 +274,22 @@
     method @androidx.compose.runtime.InternalComposeApi public static void resetSourceInfo();
   }
 
+  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
+    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
+    field public static final androidx.compose.runtime.MonotonicFrameClock.Key Key;
+  }
+
+  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.MonotonicFrameClock> {
+  }
+
+  public final class MonotonicFrameClockKt {
+    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+  }
+
   @androidx.compose.runtime.Stable public interface MutableState<T> extends androidx.compose.runtime.State<T> {
     method public operator T! component1();
     method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
@@ -294,8 +315,8 @@
   @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface NoLiveLiterals {
   }
 
-  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock);
+  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.MonotonicFrameClock frameClock);
     method public boolean isPaused();
     method public void pause();
     method public void resume();
diff --git a/compose/runtime/runtime/api/restricted_current.txt b/compose/runtime/runtime/api/restricted_current.txt
index 48d7439..07e1499 100644
--- a/compose/runtime/runtime/api/restricted_current.txt
+++ b/compose/runtime/runtime/api/restricted_current.txt
@@ -17,7 +17,7 @@
   }
 
   public final class ActualAndroidKt {
-    method public static androidx.compose.runtime.EmbeddingContext EmbeddingContext();
+    method public static androidx.compose.runtime.MonotonicFrameClock getDefaultMonotonicFrameClock();
   }
 
   public final class ActualJvmKt {
@@ -52,6 +52,16 @@
   public final class BitwiseOperatorsKt {
   }
 
+  public final class BroadcastFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public BroadcastFrameClock(kotlin.jvm.functions.Function0<kotlin.Unit>? onNewAwaiters);
+    ctor public BroadcastFrameClock();
+    method public void cancel(optional java.util.concurrent.CancellationException cancellationException);
+    method public boolean getHasAwaiters();
+    method public void sendFrame(long timeNanos);
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final boolean hasAwaiters;
+  }
+
   @kotlin.annotation.MustBeDocumented @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface Composable {
   }
 
@@ -242,11 +252,6 @@
     method public inline androidx.compose.runtime.DisposableEffectResult onDispose(kotlin.jvm.functions.Function0<kotlin.Unit> onDisposeEffect);
   }
 
-  public interface EmbeddingContext {
-    method public boolean isMainThread();
-    method public kotlin.coroutines.CoroutineContext mainThreadCompositionContext();
-  }
-
   public final class ExpectKt {
     method @kotlin.PublishedApi internal static inline <R> R! synchronized(Object lock, kotlin.jvm.functions.Function0<? extends R> block);
   }
@@ -293,6 +298,22 @@
     method @androidx.compose.runtime.InternalComposeApi public static void resetSourceInfo();
   }
 
+  public interface MonotonicFrameClock extends kotlin.coroutines.CoroutineContext.Element {
+    method public default kotlin.coroutines.CoroutineContext.Key<?> getKey();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public default kotlin.coroutines.CoroutineContext.Key<?> key;
+    field public static final androidx.compose.runtime.MonotonicFrameClock.Key Key;
+  }
+
+  public static final class MonotonicFrameClock.Key implements kotlin.coroutines.CoroutineContext.Key<androidx.compose.runtime.MonotonicFrameClock> {
+  }
+
+  public final class MonotonicFrameClockKt {
+    method public static suspend inline <R> Object? withFrameMillis(androidx.compose.runtime.MonotonicFrameClock, kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameMillis(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    method public static suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+  }
+
   @androidx.compose.runtime.Stable public interface MutableState<T> extends androidx.compose.runtime.State<T> {
     method public operator T! component1();
     method public operator kotlin.jvm.functions.Function1<T,kotlin.Unit> component2();
@@ -318,8 +339,8 @@
   @kotlin.annotation.Retention(kotlin.annotation.AnnotationRetention) @kotlin.annotation.Target(allowedTargets={kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget, kotlin.annotation.AnnotationTarget}) public @interface NoLiveLiterals {
   }
 
-  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
-    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.dispatch.MonotonicFrameClock frameClock);
+  public final class PausableMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public PausableMonotonicFrameClock(androidx.compose.runtime.MonotonicFrameClock frameClock);
     method public boolean isPaused();
     method public void pause();
     method public void resume();
diff --git a/compose/runtime/runtime/build.gradle b/compose/runtime/runtime/build.gradle
index 3bec43a..b0d5f77 100644
--- a/compose/runtime/runtime/build.gradle
+++ b/compose/runtime/runtime/build.gradle
@@ -38,7 +38,6 @@
          * corresponding block below
          */
 
-        api project(':compose:runtime:runtime-dispatch')
         api(KOTLIN_COROUTINES_ANDROID)
 
         implementation "androidx.annotation:annotation:1.1.0"
@@ -76,7 +75,6 @@
             commonMain.dependencies {
                 implementation(KOTLIN_STDLIB_COMMON)
                 implementation(KOTLIN_COROUTINES_CORE)
-                api project(':compose:runtime:runtime-dispatch')
                 implementation "org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3"
             }
             jvmMain.dependencies {
diff --git a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SideEffectTests.kt b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SideEffectTests.kt
index 386994c..e5a5fd3 100644
--- a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SideEffectTests.kt
+++ b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SideEffectTests.kt
@@ -17,8 +17,6 @@
 package androidx.compose.runtime
 
 import android.view.Choreographer
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
-import androidx.compose.runtime.dispatch.withFrameNanos
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import kotlinx.coroutines.channels.Channel
diff --git a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
index 443d8f3..75c706f 100644
--- a/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
+++ b/compose/runtime/runtime/integration-tests/src/androidAndroidTest/kotlin/androidx/compose/runtime/SuspendingEffectsTests.kt
@@ -17,8 +17,6 @@
 package androidx.compose.runtime
 
 import android.view.Choreographer
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
-import androidx.compose.runtime.dispatch.withFrameNanos
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.MediumTest
 import kotlinx.coroutines.CoroutineScope
diff --git a/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
index 86e3745..1aab3c2 100644
--- a/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
+++ b/compose/runtime/runtime/src/androidMain/kotlin/androidx/compose/runtime/ActualAndroid.kt
@@ -17,29 +17,12 @@
 package androidx.compose.runtime
 
 import android.os.Looper
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
+import android.view.Choreographer
 import kotlinx.coroutines.Dispatchers
-import kotlin.coroutines.CoroutineContext
-
-private object AndroidEmbeddingContext : EmbeddingContext {
-
-    override fun isMainThread(): Boolean {
-        return Looper.myLooper() == Looper.getMainLooper()
-    }
-
-    override fun mainThreadCompositionContext(): CoroutineContext {
-        return MainAndroidUiContext
-    }
-}
-
-actual fun EmbeddingContext(): EmbeddingContext = AndroidEmbeddingContext
-
-// TODO: Our host-side tests still grab the Android actuals based on SDK stubs that return null.
-// Satisfy their dependencies.
-private val MainAndroidUiContext: CoroutineContext by lazy {
-    if (Looper.getMainLooper() != null) AndroidUiDispatcher.Main
-    else Dispatchers.Main
-}
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.suspendCancellableCoroutine
+import kotlinx.coroutines.withContext
 
 internal actual object Trace {
     actual fun beginSection(name: String): Any? {
@@ -55,3 +38,47 @@
 internal actual typealias MainThread = androidx.annotation.MainThread
 
 internal actual typealias CheckResult = androidx.annotation.CheckResult
+
+/**
+ * This is an inaccurate implementation that will only be used when running linked against
+ * Android SDK stubs in host-side tests. A real implementation should synchronize with the
+ * device's default display's vsync rate.
+ */
+private object SdkStubsFallbackFrameClock : MonotonicFrameClock {
+    private const val DefaultFrameDelay = 16L // milliseconds
+
+    override suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R =
+        withContext(Dispatchers.Main) {
+            delay(DefaultFrameDelay)
+            onFrame(System.nanoTime())
+        }
+}
+
+private object DefaultChoreographerFrameClock : MonotonicFrameClock {
+    private val choreographer = runBlocking(Dispatchers.Main.immediate) {
+        Choreographer.getInstance()
+    }
+
+    override suspend fun <R> withFrameNanos(
+        onFrame: (frameTimeNanos: Long) -> R
+    ): R = suspendCancellableCoroutine<R> { co ->
+        val callback = Choreographer.FrameCallback { frameTimeNanos ->
+            co.resumeWith(runCatching { onFrame(frameTimeNanos) })
+        }
+        choreographer.postFrameCallback(callback)
+        co.invokeOnCancellation { choreographer.removeFrameCallback(callback) }
+    }
+}
+
+// For local testing
+private const val DisallowDefaultMonotonicFrameClock = false
+
+actual val DefaultMonotonicFrameClock: MonotonicFrameClock by lazy {
+    if (DisallowDefaultMonotonicFrameClock) error("Disallowed use of DefaultMonotonicFrameClock")
+
+    // When linked against Android SDK stubs and running host-side tests, APIs such as
+    // Looper.getMainLooper() that will never return null on a real device will return null.
+    // This branch offers an alternative solution.
+    if (Looper.getMainLooper() != null) DefaultChoreographerFrameClock
+    else SdkStubsFallbackFrameClock
+}
diff --git a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
similarity index 97%
rename from compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt
rename to compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
index 79db2ef..e5112e9 100644
--- a/compose/runtime/runtime-dispatch/src/commonMain/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClock.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/BroadcastFrameClock.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.runtime.dispatch
+package androidx.compose.runtime
 
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.suspendCancellableCoroutine
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt
deleted file mode 100644
index d2958264..0000000
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/EmbeddingContext.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * 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.compose.runtime
-
-import kotlin.coroutines.CoroutineContext
-
-interface EmbeddingContext {
-    fun isMainThread(): Boolean
-    fun mainThreadCompositionContext(): CoroutineContext
-}
-
-expect fun EmbeddingContext(): EmbeddingContext
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
index 9edecf5..2fa9cba 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/Expect.kt
@@ -68,3 +68,13 @@
 expect annotation class CheckResult(
     val suggest: String
 )
+
+/**
+ * The [MonotonicFrameClock] used by [withFrameNanos] and [withFrameMillis] if one is not present
+ * in the calling [kotlin.coroutines.CoroutineContext].
+ */
+// Implementor's note:
+// This frame clock implementation should try to synchronize with the vsync rate of the device's
+// default display. Without this synchronization, any usage of this default clock will result
+// in inconsistent animation frame timing and associated visual artifacts.
+expect val DefaultMonotonicFrameClock: MonotonicFrameClock
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt
new file mode 100644
index 0000000..17d6bff
--- /dev/null
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/MonotonicFrameClock.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.compose.runtime
+
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
+
+/**
+ * Provides a time source for display frames and the ability to perform an action on the next frame.
+ * This may be used for matching timing with the refresh rate of a display or otherwise
+ * synchronizing work with a desired frame rate.
+ */
+interface MonotonicFrameClock : CoroutineContext.Element {
+    /**
+     * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
+     * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
+     * [onFrame].
+     *
+     * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
+     * as it may be normalized to the target time for the frame, not necessarily a direct,
+     * "now" value.
+     *
+     * The time base of the value provided by [withFrameNanos] is implementation defined.
+     * Time values provided are monotonically increasing; after a call to [withFrameNanos]
+     * completes it must not provide the same value again for a subsequent call.
+     */
+    suspend fun <R> withFrameNanos(onFrame: (frameTimeNanos: Long) -> R): R
+
+    override val key: CoroutineContext.Key<*> get() = Key
+
+    companion object Key : CoroutineContext.Key<MonotonicFrameClock>
+}
+
+/**
+ * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
+ * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
+ * [onFrame].
+ *
+ * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
+ * as it may be normalized to the target time for the frame, not necessarily a direct,
+ * "now" value.
+ *
+ * The time base of the value provided by [MonotonicFrameClock.withFrameMillis] is
+ * implementation defined. Time values provided are monotonically increasing; after a call to
+ * [MonotonicFrameClock.withFrameMillis] completes it must not provide the same value again for
+ * a subsequent call.
+ */
+@Suppress("UnnecessaryLambdaCreation")
+suspend inline fun <R> MonotonicFrameClock.withFrameMillis(
+    crossinline onFrame: (frameTimeMillis: Long) -> R
+): R = withFrameNanos { onFrame(it / 1_000_000L) }
+
+/**
+ * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
+ * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
+ * [onFrame].
+ *
+ * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
+ * as it may be normalized to the target time for the frame, not necessarily a direct,
+ * "now" value.
+ *
+ * The time base of the value provided by [withFrameNanos] is implementation defined.
+ * Time values provided are monotonically increasing; after a call to [withFrameNanos]
+ * completes it must not provide the same value again for a subsequent call.
+ *
+ * This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
+ * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
+ * in the [CoroutineContext].
+ */
+suspend fun <R> withFrameNanos(onFrame: (frameTimeMillis: Long) -> R): R =
+    (coroutineContext[MonotonicFrameClock] ?: DefaultMonotonicFrameClock).withFrameNanos(onFrame)
+
+/**
+ * Suspends until a new frame is requested, immediately invokes [onFrame] with the frame time
+ * in nanoseconds in the calling context of frame dispatch, then resumes with the result from
+ * [onFrame].
+ *
+ * `frameTimeNanos` should be used when calculating animation time deltas from frame to frame
+ * as it may be normalized to the target time for the frame, not necessarily a direct,
+ * "now" value.
+ *
+ * The time base of the value provided by [MonotonicFrameClock.withFrameMillis] is
+ * implementation defined. Time values provided are monotonically increasing; after a call to
+ * [MonotonicFrameClock.withFrameMillis] completes it must not provide the same value again for
+ * a subsequent call.
+ *
+ * This function will invoke [MonotonicFrameClock.withFrameNanos] using the calling
+ * [CoroutineContext]'s [MonotonicFrameClock] or a default frame clock if one is not present
+ * in the [CoroutineContext].
+ */
+suspend fun <R> withFrameMillis(onFrame: (frameTimeMillis: Long) -> R): R =
+    (coroutineContext[MonotonicFrameClock] ?: DefaultMonotonicFrameClock).withFrameMillis(onFrame)
diff --git a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/PausableMonotonicFrameClock.kt b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/PausableMonotonicFrameClock.kt
index 2312443..b8a9246c 100644
--- a/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/PausableMonotonicFrameClock.kt
+++ b/compose/runtime/runtime/src/commonMain/kotlin/androidx/compose/runtime/PausableMonotonicFrameClock.kt
@@ -16,8 +16,6 @@
 
 package androidx.compose.runtime
 
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
-
 /**
  * A [MonotonicFrameClock] wrapper that can be [pause]d and [resume]d.
  *
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 3dbe264..8cc6928 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
@@ -16,9 +16,6 @@
 
 package androidx.compose.runtime
 
-import androidx.compose.runtime.dispatch.BroadcastFrameClock
-import androidx.compose.runtime.dispatch.DefaultMonotonicFrameClock
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
 import androidx.compose.runtime.snapshots.MutableSnapshot
 import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.runtime.snapshots.SnapshotApplyResult
diff --git a/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
index 84b217f..6da8ac9b 100644
--- a/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
+++ b/compose/runtime/runtime/src/desktopMain/kotlin/androidx/compose/runtime/ActualDesktop.kt
@@ -16,23 +16,10 @@
 
 package androidx.compose.runtime
 
-import androidx.compose.runtime.dispatch.DefaultMonotonicFrameClock
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.swing.Swing
-import javax.swing.SwingUtilities
-import kotlin.coroutines.CoroutineContext
-
-class SwingEmbeddingContext : EmbeddingContext {
-    override fun isMainThread(): Boolean {
-        return SwingUtilities.isEventDispatchThread()
-    }
-
-    override fun mainThreadCompositionContext(): CoroutineContext {
-        return Dispatchers.Swing + DefaultMonotonicFrameClock
-    }
-}
-
-actual fun EmbeddingContext(): EmbeddingContext = SwingEmbeddingContext()
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.yield
+import java.awt.DisplayMode
+import java.awt.GraphicsEnvironment
 
 internal actual object Trace {
     actual fun beginSection(name: String): Any? {
@@ -104,4 +91,31 @@
 
 // TODO(igotti): do we need actual processing for those?
 actual annotation class MainThread()
-actual annotation class CheckResult(actual val suggest: String)
\ No newline at end of file
+actual annotation class CheckResult(actual val suggest: String)
+
+// TODO implement local Recomposer in each Window, so each Window can have own MonotonicFrameClock.
+//  It is needed for smooth animations and for the case when user have multiple windows on multiple
+//  monitors with different refresh rates.
+//  see https://github.com/JetBrains/compose-jb/issues/137
+actual val DefaultMonotonicFrameClock: MonotonicFrameClock by lazy {
+    object : MonotonicFrameClock {
+        override suspend fun <R> withFrameNanos(
+            onFrame: (Long) -> R
+        ): R {
+            if (GraphicsEnvironment.isHeadless()) {
+                yield()
+            } else {
+                delay(1000L / getFramesPerSecond())
+            }
+            return onFrame(System.nanoTime())
+        }
+
+        private fun getFramesPerSecond(): Int {
+            val refreshRate = GraphicsEnvironment
+                .getLocalGraphicsEnvironment()
+                .screenDevices.maxOfOrNull { it.displayMode.refreshRate }
+                ?: DisplayMode.REFRESH_RATE_UNKNOWN
+            return if (refreshRate != DisplayMode.REFRESH_RATE_UNKNOWN) refreshRate else 60
+        }
+    }
+}
diff --git a/compose/runtime/runtime-dispatch/src/test/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClockTest.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/BroadcastFrameClockTest.kt
similarity index 91%
rename from compose/runtime/runtime-dispatch/src/test/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClockTest.kt
rename to compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/BroadcastFrameClockTest.kt
index 7204639..b348e9b 100644
--- a/compose/runtime/runtime-dispatch/src/test/kotlin/androidx/compose/runtime/dispatch/BroadcastFrameClockTest.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/BroadcastFrameClockTest.kt
@@ -29,7 +29,7 @@
 class BroadcastFrameClockTest {
     @Test
     fun sendAndReceiveFrames() = runBlockingTest {
-        val clock = BroadcastFrameClock()
+        val clock = androidx.compose.runtime.BroadcastFrameClock()
 
         val frameAwaiter = async { clock.withFrameNanos { it } }
 
@@ -49,7 +49,7 @@
 
     @Test
     fun cancelClock() = runBlockingTest {
-        val clock = BroadcastFrameClock()
+        val clock = androidx.compose.runtime.BroadcastFrameClock()
         val frameAwaiter = async { clock.withFrameNanos { it } }
 
         clock.cancel()
@@ -64,7 +64,7 @@
 
     @Test
     fun failClockWhenNewAwaitersNotified() = runBlockingTest {
-        val clock = BroadcastFrameClock {
+        val clock = androidx.compose.runtime.BroadcastFrameClock {
             throw CancellationException("failed frame clock")
         }
 
diff --git a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/TestMonotonicFrameClock.kt b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/TestMonotonicFrameClock.kt
index d7d6eb2..87ba6a4 100644
--- a/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/TestMonotonicFrameClock.kt
+++ b/compose/runtime/runtime/src/test/kotlin/androidx/compose/runtime/mock/TestMonotonicFrameClock.kt
@@ -20,7 +20,7 @@
  */
 package androidx.compose.runtime.mock
 
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.kt b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.kt
index 61e30d5..78b7b8f 100644
--- a/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.kt
+++ b/compose/test-utils/src/androidMain/kotlin/androidx/compose/testutils/AndroidComposeTestCaseRunner.kt
@@ -31,7 +31,7 @@
 import androidx.activity.ComponentActivity
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.ui.platform.ViewRootForTest
 import androidx.compose.ui.platform.setContent
diff --git a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeIdlingResourceTest.kt b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeIdlingResourceTest.kt
index b54bb4e..3895bc6 100644
--- a/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeIdlingResourceTest.kt
+++ b/compose/ui/ui-test-junit4/src/androidAndroidTest/kotlin/androidx/compose/ui/test/junit4/ComposeIdlingResourceTest.kt
@@ -30,11 +30,11 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.State
-import androidx.compose.runtime.dispatch.withFrameNanos
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.rememberCoroutineScope
 import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.runtime.withFrameNanos
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.geometry.Size
diff --git a/compose/ui/ui-test/api/current.txt b/compose/ui/ui-test/api/current.txt
index 343c76f..61c92645 100644
--- a/compose/ui/ui-test/api/current.txt
+++ b/compose/ui/ui-test/api/current.txt
@@ -279,7 +279,7 @@
   public final class TestContext {
   }
 
-  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor public TestMonotonicFrameClock(kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.test.DelayController delayController, long frameDelayNanos);
     method public long getFrameDelayNanos();
     method public boolean getHasAwaiters();
diff --git a/compose/ui/ui-test/api/public_plus_experimental_current.txt b/compose/ui/ui-test/api/public_plus_experimental_current.txt
index 343c76f..61c92645 100644
--- a/compose/ui/ui-test/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui-test/api/public_plus_experimental_current.txt
@@ -279,7 +279,7 @@
   public final class TestContext {
   }
 
-  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor public TestMonotonicFrameClock(kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.test.DelayController delayController, long frameDelayNanos);
     method public long getFrameDelayNanos();
     method public boolean getHasAwaiters();
diff --git a/compose/ui/ui-test/api/restricted_current.txt b/compose/ui/ui-test/api/restricted_current.txt
index 343c76f..61c92645 100644
--- a/compose/ui/ui-test/api/restricted_current.txt
+++ b/compose/ui/ui-test/api/restricted_current.txt
@@ -279,7 +279,7 @@
   public final class TestContext {
   }
 
-  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.dispatch.MonotonicFrameClock {
+  @kotlinx.coroutines.ExperimentalCoroutinesApi public final class TestMonotonicFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
     ctor public TestMonotonicFrameClock(kotlinx.coroutines.CoroutineScope coroutineScope, kotlinx.coroutines.test.DelayController delayController, long frameDelayNanos);
     method public long getFrameDelayNanos();
     method public boolean getHasAwaiters();
diff --git a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TestMonotonicFrameClockTest.kt b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TestMonotonicFrameClockTest.kt
index adbf9ab..75bfc07 100644
--- a/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TestMonotonicFrameClockTest.kt
+++ b/compose/ui/ui-test/src/androidAndroidTest/kotlin/androidx/compose/ui/test/TestMonotonicFrameClockTest.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.ui.test
 
-import androidx.compose.runtime.dispatch.withFrameNanos
+import androidx.compose.runtime.withFrameNanos
 import androidx.test.filters.SmallTest
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.launch
diff --git a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.kt b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.kt
index b43fcc5..adadb76 100644
--- a/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.kt
+++ b/compose/ui/ui-test/src/androidMain/kotlin/androidx/compose/ui/test/AndroidInputDispatcher.kt
@@ -25,7 +25,7 @@
 import android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT
 import android.view.MotionEvent.ACTION_POINTER_UP
 import android.view.MotionEvent.ACTION_UP
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
+import androidx.compose.ui.platform.AndroidUiDispatcher
 import androidx.compose.ui.geometry.Offset
 import androidx.compose.ui.node.RootForTest
 import androidx.compose.ui.platform.ViewRootForTest
diff --git a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.kt b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.kt
index 289a08d..f68fbfe 100644
--- a/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.kt
+++ b/compose/ui/ui-test/src/jvmMain/kotlin/androidx/compose/ui/test/TestMonotonicFrameClock.kt
@@ -16,7 +16,7 @@
 
 package androidx.compose.ui.test
 
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import kotlinx.coroutines.CancellableContinuation
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
diff --git a/compose/ui/ui/api/current.txt b/compose/ui/ui/api/current.txt
index aea0509..b39e99c 100644
--- a/compose/ui/ui/api/current.txt
+++ b/compose/ui/ui/api/current.txt
@@ -2185,6 +2185,32 @@
   public final class AndroidComposeViewKt {
   }
 
+  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
+    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
+    method public android.view.Choreographer getChoreographer();
+    method public androidx.compose.runtime.MonotonicFrameClock getFrameClock();
+    property public final android.view.Choreographer choreographer;
+    property public final androidx.compose.runtime.MonotonicFrameClock frameClock;
+    field public static final androidx.compose.ui.platform.AndroidUiDispatcher.Companion Companion;
+  }
+
+  public static final class AndroidUiDispatcher.Companion {
+    method public kotlin.coroutines.CoroutineContext getCurrentThread();
+    method public kotlin.coroutines.CoroutineContext getMain();
+    property public final kotlin.coroutines.CoroutineContext CurrentThread;
+    property public final kotlin.coroutines.CoroutineContext Main;
+  }
+
+  public final class AndroidUiDispatcherKt {
+  }
+
+  public final class AndroidUiFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
+    method public android.view.Choreographer getChoreographer();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final android.view.Choreographer choreographer;
+  }
+
   public final class AndroidUriHandler implements androidx.compose.ui.platform.UriHandler {
     ctor public AndroidUriHandler(android.content.Context context);
     method public void openUri(String uri);
diff --git a/compose/ui/ui/api/public_plus_experimental_current.txt b/compose/ui/ui/api/public_plus_experimental_current.txt
index aea0509..b39e99c 100644
--- a/compose/ui/ui/api/public_plus_experimental_current.txt
+++ b/compose/ui/ui/api/public_plus_experimental_current.txt
@@ -2185,6 +2185,32 @@
   public final class AndroidComposeViewKt {
   }
 
+  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
+    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
+    method public android.view.Choreographer getChoreographer();
+    method public androidx.compose.runtime.MonotonicFrameClock getFrameClock();
+    property public final android.view.Choreographer choreographer;
+    property public final androidx.compose.runtime.MonotonicFrameClock frameClock;
+    field public static final androidx.compose.ui.platform.AndroidUiDispatcher.Companion Companion;
+  }
+
+  public static final class AndroidUiDispatcher.Companion {
+    method public kotlin.coroutines.CoroutineContext getCurrentThread();
+    method public kotlin.coroutines.CoroutineContext getMain();
+    property public final kotlin.coroutines.CoroutineContext CurrentThread;
+    property public final kotlin.coroutines.CoroutineContext Main;
+  }
+
+  public final class AndroidUiDispatcherKt {
+  }
+
+  public final class AndroidUiFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
+    method public android.view.Choreographer getChoreographer();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final android.view.Choreographer choreographer;
+  }
+
   public final class AndroidUriHandler implements androidx.compose.ui.platform.UriHandler {
     ctor public AndroidUriHandler(android.content.Context context);
     method public void openUri(String uri);
diff --git a/compose/ui/ui/api/restricted_current.txt b/compose/ui/ui/api/restricted_current.txt
index bdcf71e..3ff9be4b 100644
--- a/compose/ui/ui/api/restricted_current.txt
+++ b/compose/ui/ui/api/restricted_current.txt
@@ -2247,6 +2247,32 @@
   public final class AndroidComposeViewKt {
   }
 
+  public final class AndroidUiDispatcher extends kotlinx.coroutines.CoroutineDispatcher {
+    method public void dispatch(kotlin.coroutines.CoroutineContext context, Runnable block);
+    method public android.view.Choreographer getChoreographer();
+    method public androidx.compose.runtime.MonotonicFrameClock getFrameClock();
+    property public final android.view.Choreographer choreographer;
+    property public final androidx.compose.runtime.MonotonicFrameClock frameClock;
+    field public static final androidx.compose.ui.platform.AndroidUiDispatcher.Companion Companion;
+  }
+
+  public static final class AndroidUiDispatcher.Companion {
+    method public kotlin.coroutines.CoroutineContext getCurrentThread();
+    method public kotlin.coroutines.CoroutineContext getMain();
+    property public final kotlin.coroutines.CoroutineContext CurrentThread;
+    property public final kotlin.coroutines.CoroutineContext Main;
+  }
+
+  public final class AndroidUiDispatcherKt {
+  }
+
+  public final class AndroidUiFrameClock implements androidx.compose.runtime.MonotonicFrameClock {
+    ctor public AndroidUiFrameClock(android.view.Choreographer choreographer);
+    method public android.view.Choreographer getChoreographer();
+    method public suspend <R> Object? withFrameNanos(kotlin.jvm.functions.Function1<? super java.lang.Long,? extends R> onFrame, kotlin.coroutines.Continuation<? super R> p);
+    property public final android.view.Choreographer choreographer;
+  }
+
   public final class AndroidUriHandler implements androidx.compose.ui.platform.UriHandler {
     ctor public AndroidUriHandler(android.content.Context context);
     method public void openUri(String uri);
diff --git a/compose/ui/ui/build.gradle b/compose/ui/ui/build.gradle
index 108a403..57fc27e 100644
--- a/compose/ui/ui/build.gradle
+++ b/compose/ui/ui/build.gradle
@@ -72,6 +72,7 @@
 
         testImplementation(ANDROIDX_TEST_RULES)
         testImplementation(ANDROIDX_TEST_RUNNER)
+        testImplementation(KOTLIN_COROUTINES_TEST)
         testImplementation(JUNIT)
         testImplementation(TRUTH)
         testImplementation(MOCKITO_CORE)
@@ -87,6 +88,8 @@
         androidTestImplementation(ANDROIDX_TEST_UIAUTOMATOR)
         androidTestImplementation(ANDROIDX_TEST_RULES)
         androidTestImplementation(ANDROIDX_TEST_RUNNER)
+        androidTestImplementation(ANDROIDX_TEST_EXT_KTX)
+        androidTestImplementation(KOTLIN_COROUTINES_TEST)
         androidTestImplementation(ESPRESSO_CORE)
         androidTestImplementation(JUNIT)
         androidTestImplementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
@@ -104,6 +107,7 @@
         androidTestImplementation project(":compose:ui:ui-test-junit4")
         androidTestImplementation project(":test-screenshot")
         androidTestImplementation "androidx.recyclerview:recyclerview:1.1.0"
+        androidTestImplementation("androidx.core:core-ktx:1.1.0")
 
         lintChecks project(":compose:ui:ui-lint")
         lintPublish project(":compose:ui:ui-lint")
@@ -166,6 +170,7 @@
             test.dependencies {
                 implementation(ANDROIDX_TEST_RULES)
                 implementation(ANDROIDX_TEST_RUNNER)
+                implementation(KOTLIN_COROUTINES_TEST)
                 implementation(JUNIT)
                 implementation(TRUTH)
                 implementation(MOCKITO_CORE)
@@ -183,6 +188,8 @@
                 implementation(ANDROIDX_TEST_UIAUTOMATOR)
                 implementation(ANDROIDX_TEST_RULES)
                 implementation(ANDROIDX_TEST_RUNNER)
+                implementation(ANDROIDX_TEST_EXT_KTX)
+                implementation(KOTLIN_COROUTINES_TEST)
                 implementation(ESPRESSO_CORE)
                 implementation(JUNIT)
                 implementation(DEXMAKER_MOCKITO, libs.exclude_bytebuddy)
@@ -200,6 +207,7 @@
                 implementation project(":compose:ui:ui-test-junit4")
                 implementation project(":test-screenshot")
                 implementation "androidx.recyclerview:recyclerview:1.1.0"
+                implementation("androidx.core:core-ktx:1.1.0")
             }
 
             desktopTest.dependencies {
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/MemoryLeakTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/MemoryLeakTest.kt
index c4198df..91f3634 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/MemoryLeakTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/MemoryLeakTest.kt
@@ -24,7 +24,7 @@
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
+import androidx.compose.ui.platform.AndroidUiDispatcher
 import androidx.compose.testutils.ComposeTestCase
 import androidx.compose.testutils.createAndroidComposeBenchmarkRunner
 import androidx.compose.ui.platform.setContent
diff --git a/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidUiDispatcherTest.kt
similarity index 80%
rename from compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt
rename to compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidUiDispatcherTest.kt
index a46885d..50a283b 100644
--- a/compose/runtime/runtime-dispatch/src/androidAndroidTest/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcherTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/AndroidUiDispatcherTest.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 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.
@@ -14,13 +14,16 @@
  * limitations under the License.
  */
 
-package androidx.compose.runtime.dispatch
+package androidx.compose.ui.platform
 
 import android.graphics.Rect
 import android.view.Choreographer
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup.LayoutParams
+import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.runtime.MonotonicFrameClock
+import androidx.compose.runtime.withFrameNanos
 import androidx.core.view.doOnLayout
 import androidx.test.ext.junit.rules.activityScenarioRule
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -31,9 +34,10 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withTimeout
+import kotlinx.coroutines.withTimeoutOrNull
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertNotEquals
+import org.junit.Assert.assertNotNull
 import org.junit.Assert.assertSame
 import org.junit.Assert.assertTrue
 import org.junit.Rule
@@ -44,7 +48,7 @@
 @RunWith(AndroidJUnit4::class)
 class AndroidUiDispatcherTest {
     @get:Rule
-    val rule = activityScenarioRule<TestActivity>()
+    val rule = activityScenarioRule<AppCompatActivity>()
 
     @Test
     fun currentThreadIsMainOnMainThread() = runBlocking(Dispatchers.Main) {
@@ -133,28 +137,32 @@
             // in the same frame if the resume was triggered by the input event.
             val rect = layoutRect.await()
             swipe(rect.left + 1, rect.top + 1, rect.right - 1, rect.bottom - 1, 30)
+            waitForIdle()
         }
 
-        withTimeout(3_000) {
-            val viewTouched = viewTouchedOnFrame.await()
-            val inputJob = ranInputJobOnFrame.await()
-            assertNotEquals(0, viewTouched)
-            assertNotEquals(0, inputJob)
-            assertEquals(
-                "touch and launched job resume happened on same frame",
-                viewTouched,
-                inputJob
-            )
-            assertEquals(
-                "withFrame ran on the same frame where it was called",
-                inputJob,
-                withFrameOnFrame.await()
-            )
-            assertEquals(
-                "second withFrame call was invoked on the very next frame",
-                inputJob + 1,
-                withFrameSecondCall.await()
-            )
-        }
+        assertNotNull(
+            "Timeout exceeded waiting for response to input events",
+            withTimeoutOrNull(5_000) {
+                val viewTouched = viewTouchedOnFrame.await()
+                val inputJob = ranInputJobOnFrame.await()
+                assertNotEquals(0, viewTouched)
+                assertNotEquals(0, inputJob)
+                assertEquals(
+                    "touch and launched job resume happened on same frame",
+                    viewTouched,
+                    inputJob
+                )
+                assertEquals(
+                    "withFrame ran on the same frame where it was called",
+                    inputJob,
+                    withFrameOnFrame.await()
+                )
+                assertEquals(
+                    "second withFrame call was invoked on the very next frame",
+                    inputJob + 1,
+                    withFrameSecondCall.await()
+                )
+            }
+        )
     }
 }
diff --git a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WindowRecomposerTest.kt b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WindowRecomposerTest.kt
index fd51969..26d6a75 100644
--- a/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WindowRecomposerTest.kt
+++ b/compose/ui/ui/src/androidAndroidTest/kotlin/androidx/compose/ui/platform/WindowRecomposerTest.kt
@@ -21,7 +21,6 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.background
diff --git a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiDispatcher.kt
similarity index 95%
rename from compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt
rename to compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiDispatcher.kt
index 2141b1d..e72b4a2 100644
--- a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiDispatcher.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiDispatcher.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 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.
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package androidx.compose.runtime.dispatch
+package androidx.compose.ui.platform
 
 import android.os.Looper
 import android.view.Choreographer
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher.Companion.CurrentThread
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher.Companion.Main
+import androidx.compose.runtime.MonotonicFrameClock
+import androidx.compose.ui.platform.AndroidUiDispatcher.Companion.CurrentThread
+import androidx.compose.ui.platform.AndroidUiDispatcher.Companion.Main
 import androidx.core.os.HandlerCompat
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.Dispatchers
diff --git a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiFrameClock.kt
similarity index 93%
rename from compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt
rename to compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiFrameClock.kt
index 71318f4..fbc7b21 100644
--- a/compose/runtime/runtime-dispatch/src/androidMain/kotlin/androidx/compose/runtime/dispatch/AndroidUiFrameClock.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/AndroidUiFrameClock.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The Android Open Source Project
+ * Copyright 2021 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.
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package androidx.compose.runtime.dispatch
+package androidx.compose.ui.platform
 
 import android.view.Choreographer
 import kotlinx.coroutines.suspendCancellableCoroutine
@@ -23,7 +23,7 @@
 
 class AndroidUiFrameClock(
     val choreographer: Choreographer
-) : MonotonicFrameClock {
+) : androidx.compose.runtime.MonotonicFrameClock {
     override suspend fun <R> withFrameNanos(
         onFrame: (Long) -> R
     ): R {
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.kt
index e869b2a..d702ebf 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/GlobalSnapshotManager.kt
@@ -17,7 +17,6 @@
 package androidx.compose.ui.platform
 
 import androidx.compose.runtime.ExperimentalComposeApi
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
 import androidx.compose.runtime.snapshots.Snapshot
 import androidx.compose.runtime.snapshots.SnapshotWriteObserver
 import androidx.compose.ui.platform.GlobalSnapshotManager.ensureStarted
diff --git a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.kt b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.kt
index b865bd9..c90661e 100644
--- a/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.kt
+++ b/compose/ui/ui/src/androidMain/kotlin/androidx/compose/ui/platform/WindowRecomposer.kt
@@ -21,8 +21,7 @@
 import androidx.compose.runtime.CompositionReference
 import androidx.compose.runtime.PausableMonotonicFrameClock
 import androidx.compose.runtime.Recomposer
-import androidx.compose.runtime.dispatch.AndroidUiDispatcher
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.ui.InternalComposeUiApi
 import androidx.compose.ui.R
 import androidx.lifecycle.Lifecycle
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 3cdf0e5..772faee 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
@@ -18,23 +18,37 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.Composition
 import androidx.compose.runtime.CompositionReference
-import androidx.compose.runtime.EmbeddingContext
+import androidx.compose.runtime.DefaultMonotonicFrameClock
 import androidx.compose.runtime.ExperimentalComposeApi
 import androidx.compose.runtime.Providers
 import androidx.compose.runtime.Recomposer
 import androidx.compose.ui.ExperimentalComposeUiApi
 import androidx.compose.ui.node.LayoutNode
+import kotlin.coroutines.CoroutineContext
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.NonCancellable
 import kotlinx.coroutines.launch
+import kotlinx.coroutines.swing.Swing
+import javax.swing.SwingUtilities
+
+object SwingEmbeddingContext {
+    fun isMainThread(): Boolean {
+        return SwingUtilities.isEventDispatchThread()
+    }
+
+    fun mainThreadCompositionContext(): CoroutineContext {
+        return Dispatchers.Swing + DefaultMonotonicFrameClock
+    }
+}
 
 // TODO: Replace usages with an appropriately scoped implementation
 // Below is a local copy of the old Recomposer.current() implementation.
 @OptIn(ExperimentalCoroutinesApi::class)
 private val GlobalDefaultRecomposer = run {
-    val embeddingContext = EmbeddingContext()
+    val embeddingContext = SwingEmbeddingContext
     val mainScope = CoroutineScope(
         NonCancellable + embeddingContext.mainThreadCompositionContext()
     )
diff --git a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
index 679e9e9..417f745 100644
--- a/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
+++ b/compose/ui/ui/src/test/kotlin/androidx/compose/ui/ComposedModifierTest.kt
@@ -25,7 +25,7 @@
 import androidx.compose.runtime.RecomposeScope
 import androidx.compose.runtime.currentComposer
 import androidx.compose.runtime.currentRecomposeScope
-import androidx.compose.runtime.dispatch.MonotonicFrameClock
+import androidx.compose.runtime.MonotonicFrameClock
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.withRunningRecomposer
 import kotlinx.coroutines.channels.Channel