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

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

Always store the target state in a scene

This CL ensures that we always store the target state of an element in a
scene, even if it is not placed in that scene (for instance because we
are overscrolling on the other transition scene).

Bug: 27298915
Test: ElementTest
Flag: com.android.systemui.scene_container
Change-Id: I4ae91fa3f7c8ad33375682eed037910a6bdfed91
parent 3cf549bd
Loading
Loading
Loading
Loading
+14 −12
Original line number Diff line number Diff line
@@ -252,6 +252,9 @@ internal class ElementNode(
        measurable: Measurable,
        constraints: Constraints,
    ): MeasureResult {
        // Update the size this element has in this scene when idle.
        sceneState.targetSize = lookaheadSize

        val transitions = currentTransitions
        val transition = elementTransition(element, transitions)

@@ -268,7 +271,16 @@ internal class ElementNode(

            val placeable = measurable.measure(constraints)
            sceneState.lastSize = placeable.size()
            return layout(placeable.width, placeable.height) {}

            this as LookaheadScope
            return layout(placeable.width, placeable.height) {
                // Update the offset (relative to the SceneTransitionLayout) this element has in
                // this scene when idle.
                coordinates?.let { coords ->
                    sceneState.targetOffset =
                        lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
                }
            }
        }

        val placeable =
@@ -700,13 +712,6 @@ private fun ApproachMeasureScope.measure(
    measurable: Measurable,
    constraints: Constraints,
): Placeable {
    // Update the size this element has in this scene when idle.
    val targetSizeInScene = lookaheadSize
    if (targetSizeInScene != sceneState.targetSize) {
        // TODO(b/290930950): Better handle when this changes to avoid instant size jumps.
        sceneState.targetSize = targetSizeInScene
    }

    // Some lambdas called (max once) by computeValue() will need to measure [measurable], in which
    // case we store the resulting placeable here to make sure the element is not measured more than
    // once.
@@ -847,10 +852,7 @@ private fun ApproachMeasureScope.place(
        // when idle.
        val coords = coordinates ?: error("Element ${element.key} does not have any coordinates")
        val targetOffsetInScene = lookaheadScopeCoordinates.localLookaheadPositionOf(coords)
        if (targetOffsetInScene != sceneState.targetOffset) {
            // TODO(b/290930950): Better handle when this changes to avoid instant offset jumps.
        sceneState.targetOffset = targetOffsetInScene
        }

        // No need to place the element in this scene if we don't want to draw it anyways.
        if (!shouldPlaceElement(layoutImpl, scene, element, transition)) {
+44 −0
Original line number Diff line number Diff line
@@ -1331,4 +1331,48 @@ class ElementTest {
            .onNode(isElement(TestElements.Foo, SceneB))
            .assertPositionInRootIsEqualTo(offsetInB.x, offsetInB.y)
    }

    @Test
    fun targetStateIsSetEvenWhenNotPlaced() {
        // Start directly at A => B but with progress < 0f to overscroll on A.
        val state =
            rule.runOnUiThread {
                MutableSceneTransitionLayoutStateImpl(
                        SceneA,
                        transitions { overscroll(SceneA, Orientation.Horizontal) {} }
                    )
                    .apply {
                        startTransition(
                            transition(
                                from = SceneA,
                                to = SceneB,
                                progress = { -1f },
                                orientation = Orientation.Horizontal
                            ),
                            transitionKey = null,
                        )
                    }
            }

        lateinit var layoutImpl: SceneTransitionLayoutImpl
        rule.setContent {
            SceneTransitionLayoutForTesting(
                state,
                Modifier.size(100.dp),
                onLayoutImpl = { layoutImpl = it },
            ) {
                scene(SceneA) {}
                scene(SceneB) { Box(Modifier.element(TestElements.Foo)) }
            }
        }

        assertThat(layoutImpl.elements).containsKey(TestElements.Foo)
        val foo = layoutImpl.elements.getValue(TestElements.Foo)

        assertThat(foo.sceneStates).containsKey(SceneB)
        val bState = foo.sceneStates.getValue(SceneB)

        assertThat(bState.targetSize).isNotEqualTo(Element.SizeUnspecified)
        assertThat(bState.targetOffset).isNotEqualTo(Offset.Unspecified)
    }
}