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