Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +4 −1 Original line number Diff line number Diff line Loading @@ -121,6 +121,8 @@ private fun SceneScope.stateForQuickSettingsContent( ) } } is TransitionState.Transition.OverlayTransition -> TODO("b/359173565: Handle overlay transitions") } } Loading Loading @@ -212,7 +214,8 @@ private fun QuickSettingsContent( addView(view) } }, // When the view changes (e.g. due to a theme change), this will be recomposed // When the view changes (e.g. due to a theme change), this will be // recomposed // if needed and the new view will be attached to the FrameLayout here. update = { qsSceneAdapter.setState(state()) Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +8 −5 Original line number Diff line number Diff line Loading @@ -393,7 +393,8 @@ private class AnimatedStateImpl<T, Delta>( transition: TransitionState.Transition?, ): T? { if (transition == null) { return sharedValue[layoutImpl.state.transitionState.currentScene] return sharedValue[content] ?: sharedValue[layoutImpl.state.transitionState.currentScene] } val fromValue = sharedValue[transition.fromContent] Loading Loading @@ -424,10 +425,12 @@ private class AnimatedStateImpl<T, Delta>( val targetValues = sharedValue.targetValues val transition = if (element != null) { layoutImpl.elements[element]?.stateByContent?.let { sceneStates -> layoutImpl.state.currentTransitions.fastLastOrNull { transition -> transition.fromContent in sceneStates || transition.toContent in sceneStates } layoutImpl.elements[element]?.let { element -> elementState( layoutImpl.state.transitionStates, isInContent = { it in element.stateByContent }, ) as? TransitionState.Transition } } else { layoutImpl.state.currentTransitions.fastLastOrNull { transition -> Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +4 −1 Original line number Diff line number Diff line Loading @@ -43,12 +43,15 @@ internal fun CoroutineScope.animateToScene( } return when (transitionState) { is TransitionState.Idle -> { is TransitionState.Idle, is TransitionState.Transition.ShowOrHideOverlay, is TransitionState.Transition.ReplaceOverlay -> { animateToScene( layoutState, target, transitionKey, isInitiatedByUserInput = false, fromScene = transitionState.currentScene, replacedTransition = null, ) } Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +162 −55 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.round import androidx.compose.ui.util.fastCoerceIn import androidx.compose.ui.util.fastLastOrNull import androidx.compose.ui.util.fastForEachReversed import androidx.compose.ui.util.lerp import com.android.compose.animation.scene.content.Content import com.android.compose.animation.scene.content.state.TransitionState Loading Loading @@ -145,8 +145,9 @@ internal fun Modifier.element( // layout/drawing. // TODO(b/341072461): Revert this and read the current transitions in ElementNode directly once // we can ensure that SceneTransitionLayoutImpl will compose new contents first. val currentTransitions = layoutImpl.state.currentTransitions return then(ElementModifier(layoutImpl, currentTransitions, content, key)).testTag(key.testTag) val currentTransitionStates = layoutImpl.state.transitionStates return then(ElementModifier(layoutImpl, currentTransitionStates, content, key)) .testTag(key.testTag) } /** Loading @@ -155,20 +156,21 @@ internal fun Modifier.element( */ private data class ElementModifier( private val layoutImpl: SceneTransitionLayoutImpl, private val currentTransitions: List<TransitionState.Transition>, private val currentTransitionStates: List<TransitionState>, private val content: Content, private val key: ElementKey, ) : ModifierNodeElement<ElementNode>() { override fun create(): ElementNode = ElementNode(layoutImpl, currentTransitions, content, key) override fun create(): ElementNode = ElementNode(layoutImpl, currentTransitionStates, content, key) override fun update(node: ElementNode) { node.update(layoutImpl, currentTransitions, content, key) node.update(layoutImpl, currentTransitionStates, content, key) } } internal class ElementNode( private var layoutImpl: SceneTransitionLayoutImpl, private var currentTransitions: List<TransitionState.Transition>, private var currentTransitionStates: List<TransitionState>, private var content: Content, private var key: ElementKey, ) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode, TraversableNode { Loading Loading @@ -226,12 +228,12 @@ internal class ElementNode( fun update( layoutImpl: SceneTransitionLayoutImpl, currentTransitions: List<TransitionState.Transition>, currentTransitionStates: List<TransitionState>, content: Content, key: ElementKey, ) { check(layoutImpl == this.layoutImpl && content == this.content) this.currentTransitions = currentTransitions this.currentTransitionStates = currentTransitionStates removeNodeFromContentState() Loading Loading @@ -287,16 +289,45 @@ internal class ElementNode( measurable: Measurable, constraints: Constraints, ): MeasureResult { val transitions = currentTransitions val transition = elementTransition(layoutImpl, element, transitions) val elementState = elementState(layoutImpl, element, currentTransitionStates) if (elementState == null) { // If the element is not part of any transition, place it normally in its idle scene. val currentState = currentTransitionStates.last() val placeInThisContent = elementContentWhenIdle( layoutImpl, currentState.currentScene, currentState.currentOverlays, isInContent = { it in element.stateByContent }, ) == content.key return if (placeInThisContent) { placeNormally(measurable, constraints) } else { doNotPlace(measurable, constraints) } } val transition = elementState as? TransitionState.Transition // If this element is not supposed to be laid out now, either because it is not part of any // ongoing transition or the other content of its transition is overscrolling, then lay out // the element normally and don't place it. // If this element is not supposed to be laid out now because the other content of its // transition is overscrolling, then lay out the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.scene val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != content.key val isNotPartOfAnyOngoingTransitions = transitions.isNotEmpty() && transition == null if (isNotPartOfAnyOngoingTransitions || isOtherSceneOverscrolling) { if (isOtherSceneOverscrolling) { return doNotPlace(measurable, constraints) } val placeable = measure(layoutImpl, element, transition, stateInContent, measurable, constraints) stateInContent.lastSize = placeable.size() return layout(placeable.width, placeable.height) { place(elementState, placeable) } } private fun ApproachMeasureScope.doNotPlace( measurable: Measurable, constraints: Constraints ): MeasureResult { recursivelyClearPlacementValues() stateInContent.lastSize = Element.SizeUnspecified Loading @@ -304,14 +335,26 @@ internal class ElementNode( return layout(placeable.width, placeable.height) { /* Do not place */ } } val placeable = measure(layoutImpl, element, transition, stateInContent, measurable, constraints) private fun ApproachMeasureScope.placeNormally( measurable: Measurable, constraints: Constraints ): MeasureResult { val placeable = measurable.measure(constraints) stateInContent.lastSize = placeable.size() return layout(placeable.width, placeable.height) { place(transition, placeable) } return layout(placeable.width, placeable.height) { coordinates?.let { with(layoutImpl.lookaheadScope) { stateInContent.lastOffset = lookaheadScopeCoordinates.localPositionOf(it, Offset.Zero) } } placeable.place(0, 0) } } private fun Placeable.PlacementScope.place( transition: TransitionState.Transition?, elementState: TransitionState, placeable: Placeable, ) { with(layoutImpl.lookaheadScope) { Loading @@ -321,11 +364,12 @@ internal class ElementNode( coordinates ?: error("Element ${element.key} does not have any coordinates") // No need to place the element in this content if we don't want to draw it anyways. if (!shouldPlaceElement(layoutImpl, content.key, element, transition)) { if (!shouldPlaceElement(layoutImpl, content.key, element, elementState)) { recursivelyClearPlacementValues() return } val transition = elementState as? TransitionState.Transition val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) val targetOffset = computeValue( Loading Loading @@ -391,11 +435,15 @@ internal class ElementNode( return@placeWithLayer } val transition = elementTransition(layoutImpl, element, currentTransitions) if (!shouldPlaceElement(layoutImpl, content.key, element, transition)) { val elementState = elementState(layoutImpl, element, currentTransitionStates) if ( elementState == null || !shouldPlaceElement(layoutImpl, content.key, element, elementState) ) { return@placeWithLayer } val transition = elementState as? TransitionState.Transition alpha = elementAlpha(layoutImpl, element, transition, stateInContent) compositingStrategy = CompositingStrategy.ModulateAlpha } Loading Loading @@ -425,7 +473,9 @@ internal class ElementNode( override fun ContentDrawScope.draw() { element.wasDrawnInAnyContent = true val transition = elementTransition(layoutImpl, element, currentTransitions) val transition = elementState(layoutImpl, element, currentTransitionStates) as? TransitionState.Transition val drawScale = getDrawScale(layoutImpl, element, transition, stateInContent) if (drawScale == Scale.Default) { drawContent() Loading Loading @@ -468,21 +518,15 @@ internal class ElementNode( } } /** * The transition that we should consider for [element]. This is the last transition where one of * its contents contains the element. */ private fun elementTransition( /** The [TransitionState] that we should consider for [element]. */ private fun elementState( layoutImpl: SceneTransitionLayoutImpl, element: Element, transitions: List<TransitionState.Transition>, ): TransitionState.Transition? { val transition = transitions.fastLastOrNull { transition -> transition.fromContent in element.stateByContent || transition.toContent in element.stateByContent } transitionStates: List<TransitionState>, ): TransitionState? { val state = elementState(transitionStates, isInContent = { it in element.stateByContent }) val transition = state as? TransitionState.Transition val previousTransition = element.lastTransition element.lastTransition = transition Loading @@ -497,8 +541,67 @@ private fun elementTransition( } } return state } internal inline fun elementState( transitionStates: List<TransitionState>, isInContent: (ContentKey) -> Boolean, ): TransitionState? { val lastState = transitionStates.last() if (lastState is TransitionState.Idle) { check(transitionStates.size == 1) return lastState } // Find the last transition with a content that contains the element. transitionStates.fastForEachReversed { state -> val transition = state as TransitionState.Transition if (isInContent(transition.fromContent) || isInContent(transition.toContent)) { return transition } } return null } internal inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, idle: TransitionState.Idle, isInContent: (ContentKey) -> Boolean, ): ContentKey { val currentScene = idle.currentScene val overlays = idle.currentOverlays return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent) } private inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, currentScene: SceneKey, overlays: Set<OverlayKey>, isInContent: (ContentKey) -> Boolean, ): ContentKey { if (overlays.isEmpty()) { return currentScene } // Find the overlay with highest zIndex that contains the element. // TODO(b/353679003): Should we cache enabledOverlays into a List<> to avoid a lot of // allocations here? var currentOverlay: OverlayKey? = null for (overlay in overlays) { if ( isInContent(overlay) && (currentOverlay == null || (layoutImpl.overlay(overlay).zIndex > layoutImpl.overlay(currentOverlay).zIndex)) ) { currentOverlay = overlay } } return currentOverlay ?: currentScene } private fun prepareInterruption( layoutImpl: SceneTransitionLayoutImpl, Loading Loading @@ -693,11 +796,19 @@ private fun shouldPlaceElement( layoutImpl: SceneTransitionLayoutImpl, content: ContentKey, element: Element, transition: TransitionState.Transition?, elementState: TransitionState, ): Boolean { // Always place the element if we are idle. if (transition == null) { return true val transition = when (elementState) { is TransitionState.Idle -> { return content == elementContentWhenIdle( layoutImpl, elementState, isInContent = { it in element.stateByContent }, ) } is TransitionState.Transition -> elementState } // Don't place the element in this content if this content is not part of the current element Loading Loading @@ -741,16 +852,12 @@ internal fun shouldPlaceOrComposeSharedElement( val scenePicker = element.contentPicker val pickedScene = when (transition) { is TransitionState.Transition.ChangeCurrentScene -> { scenePicker.contentDuringTransition( element = element, transition = transition, fromContentZIndex = layoutImpl.scene(transition.fromScene).zIndex, toContentZIndex = layoutImpl.scene(transition.toScene).zIndex, fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex, toContentZIndex = layoutImpl.content(transition.toContent).zIndex, ) } } return pickedScene == content } Loading packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt +12 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,18 @@ class SceneKey( } } /** Key for an overlay. */ class OverlayKey( debugName: String, identity: Any = Object(), ) : ContentKey(debugName, identity) { override val testTag: String = "overlay:$debugName" override fun toString(): String { return "OverlayKey(debugName=$debugName)" } } /** Key for an element. */ open class ElementKey( debugName: String, Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt +4 −1 Original line number Diff line number Diff line Loading @@ -121,6 +121,8 @@ private fun SceneScope.stateForQuickSettingsContent( ) } } is TransitionState.Transition.OverlayTransition -> TODO("b/359173565: Handle overlay transitions") } } Loading Loading @@ -212,7 +214,8 @@ private fun QuickSettingsContent( addView(view) } }, // When the view changes (e.g. due to a theme change), this will be recomposed // When the view changes (e.g. due to a theme change), this will be // recomposed // if needed and the new view will be attached to the FrameLayout here. update = { qsSceneAdapter.setState(state()) Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt +8 −5 Original line number Diff line number Diff line Loading @@ -393,7 +393,8 @@ private class AnimatedStateImpl<T, Delta>( transition: TransitionState.Transition?, ): T? { if (transition == null) { return sharedValue[layoutImpl.state.transitionState.currentScene] return sharedValue[content] ?: sharedValue[layoutImpl.state.transitionState.currentScene] } val fromValue = sharedValue[transition.fromContent] Loading Loading @@ -424,10 +425,12 @@ private class AnimatedStateImpl<T, Delta>( val targetValues = sharedValue.targetValues val transition = if (element != null) { layoutImpl.elements[element]?.stateByContent?.let { sceneStates -> layoutImpl.state.currentTransitions.fastLastOrNull { transition -> transition.fromContent in sceneStates || transition.toContent in sceneStates } layoutImpl.elements[element]?.let { element -> elementState( layoutImpl.state.transitionStates, isInContent = { it in element.stateByContent }, ) as? TransitionState.Transition } } else { layoutImpl.state.currentTransitions.fastLastOrNull { transition -> Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateToScene.kt +4 −1 Original line number Diff line number Diff line Loading @@ -43,12 +43,15 @@ internal fun CoroutineScope.animateToScene( } return when (transitionState) { is TransitionState.Idle -> { is TransitionState.Idle, is TransitionState.Transition.ShowOrHideOverlay, is TransitionState.Transition.ReplaceOverlay -> { animateToScene( layoutState, target, transitionKey, isInitiatedByUserInput = false, fromScene = transitionState.currentScene, replacedTransition = null, ) } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt +162 −55 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ import androidx.compose.ui.unit.Constraints import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.round import androidx.compose.ui.util.fastCoerceIn import androidx.compose.ui.util.fastLastOrNull import androidx.compose.ui.util.fastForEachReversed import androidx.compose.ui.util.lerp import com.android.compose.animation.scene.content.Content import com.android.compose.animation.scene.content.state.TransitionState Loading Loading @@ -145,8 +145,9 @@ internal fun Modifier.element( // layout/drawing. // TODO(b/341072461): Revert this and read the current transitions in ElementNode directly once // we can ensure that SceneTransitionLayoutImpl will compose new contents first. val currentTransitions = layoutImpl.state.currentTransitions return then(ElementModifier(layoutImpl, currentTransitions, content, key)).testTag(key.testTag) val currentTransitionStates = layoutImpl.state.transitionStates return then(ElementModifier(layoutImpl, currentTransitionStates, content, key)) .testTag(key.testTag) } /** Loading @@ -155,20 +156,21 @@ internal fun Modifier.element( */ private data class ElementModifier( private val layoutImpl: SceneTransitionLayoutImpl, private val currentTransitions: List<TransitionState.Transition>, private val currentTransitionStates: List<TransitionState>, private val content: Content, private val key: ElementKey, ) : ModifierNodeElement<ElementNode>() { override fun create(): ElementNode = ElementNode(layoutImpl, currentTransitions, content, key) override fun create(): ElementNode = ElementNode(layoutImpl, currentTransitionStates, content, key) override fun update(node: ElementNode) { node.update(layoutImpl, currentTransitions, content, key) node.update(layoutImpl, currentTransitionStates, content, key) } } internal class ElementNode( private var layoutImpl: SceneTransitionLayoutImpl, private var currentTransitions: List<TransitionState.Transition>, private var currentTransitionStates: List<TransitionState>, private var content: Content, private var key: ElementKey, ) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode, TraversableNode { Loading Loading @@ -226,12 +228,12 @@ internal class ElementNode( fun update( layoutImpl: SceneTransitionLayoutImpl, currentTransitions: List<TransitionState.Transition>, currentTransitionStates: List<TransitionState>, content: Content, key: ElementKey, ) { check(layoutImpl == this.layoutImpl && content == this.content) this.currentTransitions = currentTransitions this.currentTransitionStates = currentTransitionStates removeNodeFromContentState() Loading Loading @@ -287,16 +289,45 @@ internal class ElementNode( measurable: Measurable, constraints: Constraints, ): MeasureResult { val transitions = currentTransitions val transition = elementTransition(layoutImpl, element, transitions) val elementState = elementState(layoutImpl, element, currentTransitionStates) if (elementState == null) { // If the element is not part of any transition, place it normally in its idle scene. val currentState = currentTransitionStates.last() val placeInThisContent = elementContentWhenIdle( layoutImpl, currentState.currentScene, currentState.currentOverlays, isInContent = { it in element.stateByContent }, ) == content.key return if (placeInThisContent) { placeNormally(measurable, constraints) } else { doNotPlace(measurable, constraints) } } val transition = elementState as? TransitionState.Transition // If this element is not supposed to be laid out now, either because it is not part of any // ongoing transition or the other content of its transition is overscrolling, then lay out // the element normally and don't place it. // If this element is not supposed to be laid out now because the other content of its // transition is overscrolling, then lay out the element normally and don't place it. val overscrollScene = transition?.currentOverscrollSpec?.scene val isOtherSceneOverscrolling = overscrollScene != null && overscrollScene != content.key val isNotPartOfAnyOngoingTransitions = transitions.isNotEmpty() && transition == null if (isNotPartOfAnyOngoingTransitions || isOtherSceneOverscrolling) { if (isOtherSceneOverscrolling) { return doNotPlace(measurable, constraints) } val placeable = measure(layoutImpl, element, transition, stateInContent, measurable, constraints) stateInContent.lastSize = placeable.size() return layout(placeable.width, placeable.height) { place(elementState, placeable) } } private fun ApproachMeasureScope.doNotPlace( measurable: Measurable, constraints: Constraints ): MeasureResult { recursivelyClearPlacementValues() stateInContent.lastSize = Element.SizeUnspecified Loading @@ -304,14 +335,26 @@ internal class ElementNode( return layout(placeable.width, placeable.height) { /* Do not place */ } } val placeable = measure(layoutImpl, element, transition, stateInContent, measurable, constraints) private fun ApproachMeasureScope.placeNormally( measurable: Measurable, constraints: Constraints ): MeasureResult { val placeable = measurable.measure(constraints) stateInContent.lastSize = placeable.size() return layout(placeable.width, placeable.height) { place(transition, placeable) } return layout(placeable.width, placeable.height) { coordinates?.let { with(layoutImpl.lookaheadScope) { stateInContent.lastOffset = lookaheadScopeCoordinates.localPositionOf(it, Offset.Zero) } } placeable.place(0, 0) } } private fun Placeable.PlacementScope.place( transition: TransitionState.Transition?, elementState: TransitionState, placeable: Placeable, ) { with(layoutImpl.lookaheadScope) { Loading @@ -321,11 +364,12 @@ internal class ElementNode( coordinates ?: error("Element ${element.key} does not have any coordinates") // No need to place the element in this content if we don't want to draw it anyways. if (!shouldPlaceElement(layoutImpl, content.key, element, transition)) { if (!shouldPlaceElement(layoutImpl, content.key, element, elementState)) { recursivelyClearPlacementValues() return } val transition = elementState as? TransitionState.Transition val currentOffset = lookaheadScopeCoordinates.localPositionOf(coords, Offset.Zero) val targetOffset = computeValue( Loading Loading @@ -391,11 +435,15 @@ internal class ElementNode( return@placeWithLayer } val transition = elementTransition(layoutImpl, element, currentTransitions) if (!shouldPlaceElement(layoutImpl, content.key, element, transition)) { val elementState = elementState(layoutImpl, element, currentTransitionStates) if ( elementState == null || !shouldPlaceElement(layoutImpl, content.key, element, elementState) ) { return@placeWithLayer } val transition = elementState as? TransitionState.Transition alpha = elementAlpha(layoutImpl, element, transition, stateInContent) compositingStrategy = CompositingStrategy.ModulateAlpha } Loading Loading @@ -425,7 +473,9 @@ internal class ElementNode( override fun ContentDrawScope.draw() { element.wasDrawnInAnyContent = true val transition = elementTransition(layoutImpl, element, currentTransitions) val transition = elementState(layoutImpl, element, currentTransitionStates) as? TransitionState.Transition val drawScale = getDrawScale(layoutImpl, element, transition, stateInContent) if (drawScale == Scale.Default) { drawContent() Loading Loading @@ -468,21 +518,15 @@ internal class ElementNode( } } /** * The transition that we should consider for [element]. This is the last transition where one of * its contents contains the element. */ private fun elementTransition( /** The [TransitionState] that we should consider for [element]. */ private fun elementState( layoutImpl: SceneTransitionLayoutImpl, element: Element, transitions: List<TransitionState.Transition>, ): TransitionState.Transition? { val transition = transitions.fastLastOrNull { transition -> transition.fromContent in element.stateByContent || transition.toContent in element.stateByContent } transitionStates: List<TransitionState>, ): TransitionState? { val state = elementState(transitionStates, isInContent = { it in element.stateByContent }) val transition = state as? TransitionState.Transition val previousTransition = element.lastTransition element.lastTransition = transition Loading @@ -497,8 +541,67 @@ private fun elementTransition( } } return state } internal inline fun elementState( transitionStates: List<TransitionState>, isInContent: (ContentKey) -> Boolean, ): TransitionState? { val lastState = transitionStates.last() if (lastState is TransitionState.Idle) { check(transitionStates.size == 1) return lastState } // Find the last transition with a content that contains the element. transitionStates.fastForEachReversed { state -> val transition = state as TransitionState.Transition if (isInContent(transition.fromContent) || isInContent(transition.toContent)) { return transition } } return null } internal inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, idle: TransitionState.Idle, isInContent: (ContentKey) -> Boolean, ): ContentKey { val currentScene = idle.currentScene val overlays = idle.currentOverlays return elementContentWhenIdle(layoutImpl, currentScene, overlays, isInContent) } private inline fun elementContentWhenIdle( layoutImpl: SceneTransitionLayoutImpl, currentScene: SceneKey, overlays: Set<OverlayKey>, isInContent: (ContentKey) -> Boolean, ): ContentKey { if (overlays.isEmpty()) { return currentScene } // Find the overlay with highest zIndex that contains the element. // TODO(b/353679003): Should we cache enabledOverlays into a List<> to avoid a lot of // allocations here? var currentOverlay: OverlayKey? = null for (overlay in overlays) { if ( isInContent(overlay) && (currentOverlay == null || (layoutImpl.overlay(overlay).zIndex > layoutImpl.overlay(currentOverlay).zIndex)) ) { currentOverlay = overlay } } return currentOverlay ?: currentScene } private fun prepareInterruption( layoutImpl: SceneTransitionLayoutImpl, Loading Loading @@ -693,11 +796,19 @@ private fun shouldPlaceElement( layoutImpl: SceneTransitionLayoutImpl, content: ContentKey, element: Element, transition: TransitionState.Transition?, elementState: TransitionState, ): Boolean { // Always place the element if we are idle. if (transition == null) { return true val transition = when (elementState) { is TransitionState.Idle -> { return content == elementContentWhenIdle( layoutImpl, elementState, isInContent = { it in element.stateByContent }, ) } is TransitionState.Transition -> elementState } // Don't place the element in this content if this content is not part of the current element Loading Loading @@ -741,16 +852,12 @@ internal fun shouldPlaceOrComposeSharedElement( val scenePicker = element.contentPicker val pickedScene = when (transition) { is TransitionState.Transition.ChangeCurrentScene -> { scenePicker.contentDuringTransition( element = element, transition = transition, fromContentZIndex = layoutImpl.scene(transition.fromScene).zIndex, toContentZIndex = layoutImpl.scene(transition.toScene).zIndex, fromContentZIndex = layoutImpl.content(transition.fromContent).zIndex, toContentZIndex = layoutImpl.content(transition.toContent).zIndex, ) } } return pickedScene == content } Loading
packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Key.kt +12 −0 Original line number Diff line number Diff line Loading @@ -63,6 +63,18 @@ class SceneKey( } } /** Key for an overlay. */ class OverlayKey( debugName: String, identity: Any = Object(), ) : ContentKey(debugName, identity) { override val testTag: String = "overlay:$debugName" override fun toString(): String { return "OverlayKey(debugName=$debugName)" } } /** Key for an element. */ open class ElementKey( debugName: String, Loading