Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a5948ba2 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Expose onTransition(Start|End) callbacks in STLState

This CL exposes new callbacks on STLState when a transition is
started/finished, as well as a new Transition.cuj coming from the
transition spec.

Bug: 387321113
Test: atest SceneTransitionLayoutStateTest
Flag: com.android.systemui.scene_container
Change-Id: Id0ab0e8a8ac65bdc36afcdae77891bec601eb6f2
parent d590a3dd
Loading
Loading
Loading
Loading
+15 −9
Original line number Original line Diff line number Diff line
@@ -232,6 +232,8 @@ fun MutableSceneTransitionLayoutState(
    canShowOverlay: (OverlayKey) -> Boolean = { true },
    canShowOverlay: (OverlayKey) -> Boolean = { true },
    canHideOverlay: (OverlayKey) -> Boolean = { true },
    canHideOverlay: (OverlayKey) -> Boolean = { true },
    canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
    canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
    onTransitionStart: (TransitionState.Transition) -> Unit = {},
    onTransitionEnd: (TransitionState.Transition) -> Unit = {},
): MutableSceneTransitionLayoutState {
): MutableSceneTransitionLayoutState {
    return MutableSceneTransitionLayoutStateImpl(
    return MutableSceneTransitionLayoutStateImpl(
        initialScene,
        initialScene,
@@ -241,6 +243,8 @@ fun MutableSceneTransitionLayoutState(
        canShowOverlay,
        canShowOverlay,
        canHideOverlay,
        canHideOverlay,
        canReplaceOverlay,
        canReplaceOverlay,
        onTransitionStart,
        onTransitionEnd,
    )
    )
}
}


@@ -252,7 +256,11 @@ internal class MutableSceneTransitionLayoutStateImpl(
    internal val canChangeScene: (SceneKey) -> Boolean = { true },
    internal val canChangeScene: (SceneKey) -> Boolean = { true },
    internal val canShowOverlay: (OverlayKey) -> Boolean = { true },
    internal val canShowOverlay: (OverlayKey) -> Boolean = { true },
    internal val canHideOverlay: (OverlayKey) -> Boolean = { true },
    internal val canHideOverlay: (OverlayKey) -> Boolean = { true },
    internal val canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ -> true },
    internal val canReplaceOverlay: (from: OverlayKey, to: OverlayKey) -> Boolean = { _, _ ->
        true
    },
    private val onTransitionStart: (TransitionState.Transition) -> Unit = {},
    private val onTransitionEnd: (TransitionState.Transition) -> Unit = {},
) : MutableSceneTransitionLayoutState {
) : MutableSceneTransitionLayoutState {
    private val creationThread: Thread = Thread.currentThread()
    private val creationThread: Thread = Thread.currentThread()


@@ -367,9 +375,11 @@ internal class MutableSceneTransitionLayoutStateImpl(
            startTransitionInternal(transition, chain)
            startTransitionInternal(transition, chain)


            // Run the transition until it is finished.
            // Run the transition until it is finished.
            onTransitionStart(transition)
            transition.runInternal()
            transition.runInternal()
        } finally {
        } finally {
            finishTransition(transition)
            finishTransition(transition)
            onTransitionEnd(transition)
        }
        }
    }
    }


@@ -384,14 +394,10 @@ internal class MutableSceneTransitionLayoutStateImpl(
        val toContent = transition.toContent
        val toContent = transition.toContent


        // Update the transition specs.
        // Update the transition specs.
        transition.transformationSpec =
        val spec = transitions.transitionSpec(fromContent, toContent, key = transition.key)
            transitions
        transition._cuj = spec.cuj
                .transitionSpec(fromContent, toContent, key = transition.key)
        transition.transformationSpec = spec.transformationSpec(transition)
                .transformationSpec(transition)
        transition.previewTransformationSpec = spec.previewTransformationSpec(transition)
        transition.previewTransformationSpec =
            transitions
                .transitionSpec(fromContent, toContent, key = transition.key)
                .previewTransformationSpec(transition)
    }
    }


    private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
    private fun startTransitionInternal(transition: TransitionState.Transition, chain: Boolean) {
+15 −1
Original line number Original line Diff line number Diff line
@@ -29,6 +29,7 @@ import com.android.compose.animation.scene.transformation.PropertyTransformation
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.SharedElementTransformation
import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationWithRange
import com.android.compose.animation.scene.transformation.TransformationWithRange
import com.android.internal.jank.Cuj.CujType


/** The transitions configuration of a [SceneTransitionLayout]. */
/** The transitions configuration of a [SceneTransitionLayout]. */
class SceneTransitions
class SceneTransitions
@@ -111,7 +112,15 @@ internal constructor(
    }
    }


    private fun defaultTransition(from: ContentKey, to: ContentKey) =
    private fun defaultTransition(from: ContentKey, to: ContentKey) =
        TransitionSpecImpl(key = null, from, to, null, null, TransformationSpec.EmptyProvider)
        TransitionSpecImpl(
            key = null,
            from,
            to,
            cuj = null,
            previewTransformationSpec = null,
            reversePreviewTransformationSpec = null,
            TransformationSpec.EmptyProvider,
        )


    companion object {
    companion object {
        internal val DefaultSwipeSpec =
        internal val DefaultSwipeSpec =
@@ -147,6 +156,9 @@ internal interface TransitionSpec {
     */
     */
    val to: ContentKey?
    val to: ContentKey?


    /** The CUJ covered by this transition. */
    @CujType val cuj: Int?

    /**
    /**
     * Return a reversed version of this [TransitionSpec] for a transition going from [to] to
     * Return a reversed version of this [TransitionSpec] for a transition going from [to] to
     * [from].
     * [from].
@@ -213,6 +225,7 @@ internal class TransitionSpecImpl(
    override val key: TransitionKey?,
    override val key: TransitionKey?,
    override val from: ContentKey?,
    override val from: ContentKey?,
    override val to: ContentKey?,
    override val to: ContentKey?,
    override val cuj: Int?,
    private val previewTransformationSpec:
    private val previewTransformationSpec:
        ((TransitionState.Transition) -> TransformationSpecImpl)? =
        ((TransitionState.Transition) -> TransformationSpecImpl)? =
        null,
        null,
@@ -226,6 +239,7 @@ internal class TransitionSpecImpl(
            key = key,
            key = key,
            from = to,
            from = to,
            to = from,
            to = from,
            cuj = cuj,
            previewTransformationSpec = reversePreviewTransformationSpec,
            previewTransformationSpec = reversePreviewTransformationSpec,
            reversePreviewTransformationSpec = previewTransformationSpec,
            reversePreviewTransformationSpec = previewTransformationSpec,
            transformationSpec = { transition ->
            transformationSpec = { transition ->
+6 −0
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.animation.scene.transformation.Transformation
import com.android.compose.animation.scene.transformation.Transformation
import com.android.internal.jank.Cuj.CujType


/** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
/** Define the [transitions][SceneTransitions] to be used with a [SceneTransitionLayout]. */
fun transitions(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
fun transitions(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
@@ -64,6 +65,7 @@ interface SceneTransitionsBuilder {
    fun to(
    fun to(
        to: ContentKey,
        to: ContentKey,
        key: TransitionKey? = null,
        key: TransitionKey? = null,
        @CujType cuj: Int? = null,
        preview: (TransitionBuilder.() -> Unit)? = null,
        preview: (TransitionBuilder.() -> Unit)? = null,
        reversePreview: (TransitionBuilder.() -> Unit)? = null,
        reversePreview: (TransitionBuilder.() -> Unit)? = null,
        builder: TransitionBuilder.() -> Unit = {},
        builder: TransitionBuilder.() -> Unit = {},
@@ -90,6 +92,7 @@ interface SceneTransitionsBuilder {
        from: ContentKey,
        from: ContentKey,
        to: ContentKey? = null,
        to: ContentKey? = null,
        key: TransitionKey? = null,
        key: TransitionKey? = null,
        @CujType cuj: Int? = null,
        preview: (TransitionBuilder.() -> Unit)? = null,
        preview: (TransitionBuilder.() -> Unit)? = null,
        reversePreview: (TransitionBuilder.() -> Unit)? = null,
        reversePreview: (TransitionBuilder.() -> Unit)? = null,
        builder: TransitionBuilder.() -> Unit = {},
        builder: TransitionBuilder.() -> Unit = {},
@@ -146,6 +149,9 @@ interface TransitionBuilder : BaseTransitionBuilder {
     */
     */
    var swipeSpec: SpringSpec<Float>?
    var swipeSpec: SpringSpec<Float>?


    /** The CUJ associated to this transitions. */
    @CujType var cuj: Int?

    /**
    /**
     * Define a timestamp-based range for the transformations inside [builder].
     * Define a timestamp-based range for the transformations inside [builder].
     *
     *
+27 −5
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.compose.animation.scene.transformation.Transformation
import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationMatcher
import com.android.compose.animation.scene.transformation.TransformationRange
import com.android.compose.animation.scene.transformation.TransformationRange
import com.android.compose.animation.scene.transformation.Translate
import com.android.compose.animation.scene.transformation.Translate
import com.android.internal.jank.Cuj.CujType


internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
internal fun transitionsImpl(builder: SceneTransitionsBuilder.() -> Unit): SceneTransitions {
    val impl = SceneTransitionsBuilderImpl().apply(builder)
    val impl = SceneTransitionsBuilderImpl().apply(builder)
@@ -52,28 +53,47 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {
    override fun to(
    override fun to(
        to: ContentKey,
        to: ContentKey,
        key: TransitionKey?,
        key: TransitionKey?,
        @CujType cuj: Int?,
        preview: (TransitionBuilder.() -> Unit)?,
        preview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        builder: TransitionBuilder.() -> Unit,
        builder: TransitionBuilder.() -> Unit,
    ) {
    ) {
        transition(from = null, to = to, key = key, preview, reversePreview, builder)
        transition(
            from = null,
            to = to,
            key = key,
            cuj = cuj,
            preview = preview,
            reversePreview = reversePreview,
            builder = builder,
        )
    }
    }


    override fun from(
    override fun from(
        from: ContentKey,
        from: ContentKey,
        to: ContentKey?,
        to: ContentKey?,
        key: TransitionKey?,
        key: TransitionKey?,
        @CujType cuj: Int?,
        preview: (TransitionBuilder.() -> Unit)?,
        preview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        builder: TransitionBuilder.() -> Unit,
        builder: TransitionBuilder.() -> Unit,
    ) {
    ) {
        transition(from = from, to = to, key = key, preview, reversePreview, builder)
        transition(
            from = from,
            to = to,
            key = key,
            cuj = cuj,
            preview = preview,
            reversePreview = reversePreview,
            builder = builder,
        )
    }
    }


    private fun transition(
    private fun transition(
        from: ContentKey?,
        from: ContentKey?,
        to: ContentKey?,
        to: ContentKey?,
        key: TransitionKey?,
        key: TransitionKey?,
        @CujType cuj: Int?,
        preview: (TransitionBuilder.() -> Unit)?,
        preview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        reversePreview: (TransitionBuilder.() -> Unit)?,
        builder: TransitionBuilder.() -> Unit,
        builder: TransitionBuilder.() -> Unit,
@@ -93,9 +113,10 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder {


        val spec =
        val spec =
            TransitionSpecImpl(
            TransitionSpecImpl(
                key,
                key = key,
                from,
                from = from,
                to,
                to = to,
                cuj = cuj,
                previewTransformationSpec = preview?.let { { t -> transformationSpec(t, it) } },
                previewTransformationSpec = preview?.let { { t -> transformationSpec(t, it) } },
                reversePreviewTransformationSpec =
                reversePreviewTransformationSpec =
                    reversePreview?.let { { t -> transformationSpec(t, it) } },
                    reversePreview?.let { { t -> transformationSpec(t, it) } },
@@ -190,6 +211,7 @@ internal class TransitionBuilderImpl(override val transition: TransitionState.Tr
    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
    override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow)
    override var swipeSpec: SpringSpec<Float>? = null
    override var swipeSpec: SpringSpec<Float>? = null
    override var distance: UserActionDistance? = null
    override var distance: UserActionDistance? = null
    override var cuj: Int? = null
    private val durationMillis: Int by lazy {
    private val durationMillis: Int by lazy {
        val spec = spec
        val spec = spec
        if (spec !is DurationBasedAnimationSpec) {
        if (spec !is DurationBasedAnimationSpec) {
+9 −1
Original line number Original line Diff line number Diff line
@@ -32,6 +32,7 @@ import com.android.compose.animation.scene.SceneTransitionLayoutImpl
import com.android.compose.animation.scene.TransformationSpec
import com.android.compose.animation.scene.TransformationSpec
import com.android.compose.animation.scene.TransformationSpecImpl
import com.android.compose.animation.scene.TransformationSpecImpl
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.TransitionKey
import com.android.internal.jank.Cuj.CujType
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
@@ -237,6 +238,11 @@ sealed interface TransitionState {
        /** Whether user input is currently driving the transition. */
        /** Whether user input is currently driving the transition. */
        abstract val isUserInputOngoing: Boolean
        abstract val isUserInputOngoing: Boolean


        /** The CUJ covered by this transition. */
        @CujType
        val cuj: Int?
            get() = _cuj

        /**
        /**
         * The progress of the preview transition. This is usually in the `[0; 1]` range, but it can
         * The progress of the preview transition. This is usually in the `[0; 1]` range, but it can
         * also be less than `0` or greater than `1` when using transitions with a spring
         * also be less than `0` or greater than `1` when using transitions with a spring
@@ -251,13 +257,15 @@ sealed interface TransitionState {
        internal open val isInPreviewStage: Boolean = false
        internal open val isInPreviewStage: Boolean = false


        /**
        /**
         * The current [TransformationSpecImpl] associated to this transition.
         * The current [TransformationSpecImpl] and other values associated to this transition from
         * the spec.
         *
         *
         * Important: These will be set exactly once, when this transition is
         * Important: These will be set exactly once, when this transition is
         * [started][MutableSceneTransitionLayoutStateImpl.startTransition].
         * [started][MutableSceneTransitionLayoutStateImpl.startTransition].
         */
         */
        internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
        internal var transformationSpec: TransformationSpecImpl = TransformationSpec.Empty
        internal var previewTransformationSpec: TransformationSpecImpl? = null
        internal var previewTransformationSpec: TransformationSpecImpl? = null
        internal var _cuj: Int? = null


        /**
        /**
         * An animatable that animates from 1f to 0f. This will be used to nicely animate the sudden
         * An animatable that animates from 1f to 0f. This will be used to nicely animate the sudden
Loading