summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt15
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt4
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt2
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt27
8 files changed, 52 insertions, 6 deletions
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 1d2c053b3c76..b264a7ef0da3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -17,6 +17,7 @@
package com.android.compose.animation.scene
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
@@ -47,6 +48,7 @@ import com.android.compose.ui.util.lerp
import kotlinx.coroutines.launch
/** An element on screen, that can be composed in one or more scenes. */
+@Stable
internal class Element(val key: ElementKey) {
/**
* The last values of this element, coming from any scene. Note that this value will be unstable
@@ -91,6 +93,7 @@ internal class Element(val key: ElementKey) {
}
/** The target values of this element in a given scene. */
+ @Stable
class TargetValues(val scene: SceneKey) {
val lastValues = Values()
@@ -108,6 +111,7 @@ internal class Element(val key: ElementKey) {
}
/** A shared value of this element. */
+ @Stable
class SharedValue<T>(val key: ValueKey, initialValue: T) {
var value by mutableStateOf(initialValue)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
index 5b752eb4e900..84d3b8647d6c 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt
@@ -17,11 +17,13 @@
package com.android.compose.animation.scene
import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.Stable
/**
* A base class to create unique keys, associated to an [identity] that is used to check the
* equality of two key instances.
*/
+@Stable
sealed class Key(val debugName: String, val identity: Any) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
index f5b271019748..f5561cb404b6 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Scene.kt
@@ -19,11 +19,13 @@ package com.android.compose.animation.scene
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.compose.runtime.snapshots.Snapshot
import androidx.compose.runtime.snapshots.SnapshotStateMap
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
@@ -34,6 +36,7 @@ import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.zIndex
/** A scene in a [SceneTransitionLayout]. */
+@Stable
internal class Scene(
val key: SceneKey,
layoutImpl: SceneTransitionLayoutImpl,
@@ -105,11 +108,13 @@ private class SceneScopeImpl(
): State<T> {
val element =
element?.let { key ->
- layoutImpl.elements[key]
- ?: error(
- "Element $key is not composed. Make sure to call animateSharedXAsState " +
- "*after* Modifier.element(key)."
- )
+ Snapshot.withoutReadObservation {
+ layoutImpl.elements[key]
+ ?: error(
+ "Element $key is not composed. Make sure to call " +
+ "animateSharedXAsState *after* Modifier.element(key)."
+ )
+ }
}
return animateSharedValueAsState(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 1f698ff00141..07add77eccd4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -19,6 +19,7 @@ package com.android.compose.animation.scene
import androidx.annotation.FloatRange
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -95,6 +96,7 @@ interface SceneTransitionLayoutScope {
@DslMarker annotation class ElementDsl
@ElementDsl
+@Stable
interface SceneScope {
/** The state of the [SceneTransitionLayout] in which this scene is contained. */
val layoutState: SceneTransitionLayoutState
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index 60f385aede02..02ddccbc051b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -23,6 +23,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.key
import androidx.compose.runtime.mutableStateOf
@@ -41,6 +42,7 @@ import com.android.compose.ui.util.lerp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
+@Stable
internal class SceneTransitionLayoutImpl(
onChangeScene: (SceneKey) -> Unit,
builder: SceneTransitionLayoutScope.() -> Unit,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index 6a87662135de..f48e9147eef4 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -16,11 +16,13 @@
package com.android.compose.animation.scene
+import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
/** The state of a [SceneTransitionLayout]. */
+@Stable
class SceneTransitionLayoutState(initialScene: SceneKey) {
/**
* The current [TransitionState]. All values read here are backed by the Snapshot system.
@@ -29,7 +31,6 @@ class SceneTransitionLayoutState(initialScene: SceneKey) {
* [SceneTransitionLayoutState.observableTransitionState] instead.
*/
var transitionState: TransitionState by mutableStateOf(TransitionState.Idle(initialScene))
- internal set
/**
* Whether we are transitioning, optionally restricting the check to the transition between
@@ -54,6 +55,7 @@ class SceneTransitionLayoutState(initialScene: SceneKey) {
}
}
+@Stable
sealed interface TransitionState {
/**
* The current effective scene. If a new transition was triggered, it would start from this
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index 828dff27637b..f91895bb0e05 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -18,6 +18,7 @@ package com.android.compose.animation.scene
import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.snap
+import androidx.compose.runtime.Stable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEach
@@ -92,6 +93,7 @@ class SceneTransitions(
}
/** The definition of a transition between [from] and [to]. */
+@Stable
data class TransitionSpec(
val from: SceneKey?,
val to: SceneKey?,
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index cc7a0b8e33b2..ce3e1db2c3d0 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -23,6 +23,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -427,4 +428,30 @@ class ElementTest {
assertThat(barElement.sceneValues.keys).containsExactly(TestScenes.SceneA)
assertThat(fooElement.sceneValues).isEmpty()
}
+
+ @Test
+ fun existingElementsDontRecomposeWhenTransitionStateChanges() {
+ var fooCompositions = 0
+
+ rule.testTransition(
+ fromSceneContent = {
+ SideEffect { fooCompositions++ }
+ Box(Modifier.element(TestElements.Foo))
+ },
+ toSceneContent = {},
+ transition = {
+ spec = tween(4 * 16)
+
+ scaleSize(TestElements.Foo, width = 2f, height = 0.5f)
+ translate(TestElements.Foo, x = 10.dp, y = 10.dp)
+ fade(TestElements.Foo)
+ }
+ ) {
+ before { assertThat(fooCompositions).isEqualTo(1) }
+ at(16) { assertThat(fooCompositions).isEqualTo(1) }
+ at(32) { assertThat(fooCompositions).isEqualTo(1) }
+ at(48) { assertThat(fooCompositions).isEqualTo(1) }
+ after { assertThat(fooCompositions).isEqualTo(1) }
+ }
+ }
}