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

Commit 83bc9c36 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere
Browse files

Don't handle interruptions too aggressively

This CL simplifies Element.prepareInterruption() so that we simply
reconcile between SceneStates that are part of the same transition (the
new or interrupted one). This means that we animate transition jumps
less than before, but I think that this is overall what we want.

See b/290930950#comment28 for details and before/after videos.

Bug: 290930950
Test: ElementTest. Existing tests already cover the use cases we are
 interested in.
Flag: com.android.systemui.scene_container
Change-Id: I096625fd1e05a470b849ad046e28b2284adb1228
parent 37f11639
Loading
Loading
Loading
Loading
+38 −77
Original line number Diff line number Diff line
@@ -371,96 +371,57 @@ private fun prepareInterruption(
    transition: TransitionState.Transition,
    previousTransition: TransitionState.Transition,
) {
    val previousUniqueState = reconcileStates(element, previousTransition)
    if (previousUniqueState == null) {
        reconcileStates(element, transition)
        return
    }

    val fromSceneState = element.sceneStates[transition.fromScene]
    val toSceneState = element.sceneStates[transition.toScene]
    val sceneStates = element.sceneStates
    sceneStates[previousTransition.fromScene]?.selfUpdateValuesBeforeInterruption()
    sceneStates[previousTransition.toScene]?.selfUpdateValuesBeforeInterruption()
    sceneStates[transition.fromScene]?.selfUpdateValuesBeforeInterruption()
    sceneStates[transition.toScene]?.selfUpdateValuesBeforeInterruption()

    if (
        fromSceneState == null ||
            toSceneState == null ||
            sharedElementTransformation(element.key, transition)?.enabled != false
    ) {
        // If there is only one copy of the element or if the element is shared, animate deltas in
        // both scenes.
        fromSceneState?.updateValuesBeforeInterruption(previousUniqueState)
        toSceneState?.updateValuesBeforeInterruption(previousUniqueState)
    }
    reconcileStates(element, previousTransition)
    reconcileStates(element, transition)
}

/**
 * Reconcile the state of [element] in the fromScene and toScene of [transition] so that the values
 * before interruption have their expected values, taking shared transitions into account.
 *
 * If the element had a unique state, i.e. it is shared in [transition] or it is only present in one
 * of the scenes, return it.
 */
private fun reconcileStates(
    element: Element,
    transition: TransitionState.Transition,
): Element.SceneState? {
    val fromSceneState = element.sceneStates[transition.fromScene]
    val toSceneState = element.sceneStates[transition.toScene]
    when {
        // Element is in both scenes.
        fromSceneState != null && toSceneState != null -> {
            val isSharedTransformationDisabled =
                sharedElementTransformation(element.key, transition)?.enabled == false
            when {
                // Element shared transition is disabled so the element is placed in both scenes.
                isSharedTransformationDisabled -> {
                    fromSceneState.updateValuesBeforeInterruption(fromSceneState)
                    toSceneState.updateValuesBeforeInterruption(toSceneState)
                    return null
) {
    val fromSceneState = element.sceneStates[transition.fromScene] ?: return
    val toSceneState = element.sceneStates[transition.toScene] ?: return
    if (!isSharedElementEnabled(element.key, transition)) {
        return
    }

    if (
        fromSceneState.offsetBeforeInterruption != Offset.Unspecified &&
            toSceneState.offsetBeforeInterruption == Offset.Unspecified
    ) {
        // Element is shared and placed in fromScene only.
                fromSceneState.lastOffset != Offset.Unspecified -> {
                    fromSceneState.updateValuesBeforeInterruption(fromSceneState)
        toSceneState.updateValuesBeforeInterruption(fromSceneState)
                    return fromSceneState
                }

    } else if (
        toSceneState.offsetBeforeInterruption != Offset.Unspecified &&
            fromSceneState.offsetBeforeInterruption == Offset.Unspecified
    ) {
        // Element is shared and placed in toScene only.
                toSceneState.lastOffset != Offset.Unspecified -> {
        fromSceneState.updateValuesBeforeInterruption(toSceneState)
                    toSceneState.updateValuesBeforeInterruption(toSceneState)
                    return toSceneState
                }

                // Element is in none of the scenes.
                else -> {
                    fromSceneState.updateValuesBeforeInterruption(null)
                    toSceneState.updateValuesBeforeInterruption(null)
                    return null
                }
            }
    }

        // Element is only in fromScene.
        fromSceneState != null -> {
            fromSceneState.updateValuesBeforeInterruption(fromSceneState)
            return fromSceneState
}

        // Element is only in toScene.
        toSceneState != null -> {
            toSceneState.updateValuesBeforeInterruption(toSceneState)
            return toSceneState
        }
        else -> return null
    }
private fun Element.SceneState.selfUpdateValuesBeforeInterruption() {
    offsetBeforeInterruption = lastOffset
    sizeBeforeInterruption = lastSize
    scaleBeforeInterruption = lastScale
    alphaBeforeInterruption = lastAlpha
}

private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState?) {
    offsetBeforeInterruption = lastState?.lastOffset ?: Offset.Unspecified
    sizeBeforeInterruption = lastState?.lastSize ?: Element.SizeUnspecified
    scaleBeforeInterruption = lastState?.lastScale ?: Scale.Unspecified
    alphaBeforeInterruption = lastState?.lastAlpha ?: Element.AlphaUnspecified
private fun Element.SceneState.updateValuesBeforeInterruption(lastState: Element.SceneState) {
    offsetBeforeInterruption = lastState.offsetBeforeInterruption
    sizeBeforeInterruption = lastState.sizeBeforeInterruption
    scaleBeforeInterruption = lastState.scaleBeforeInterruption
    alphaBeforeInterruption = lastState.alphaBeforeInterruption

    clearInterruptionDeltas()
}