summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jordan Demeulenaere <jdemeulenaere@google.com> 2023-10-12 12:40:55 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-10-12 12:40:55 +0000
commit1016e95f6eb624688277f8998fcd5674d4eaaf80 (patch)
treecbd514bb24ada3abe68635990d9ee1ebc63c5a27
parentf7f16510ff7e7adcc510c97aaeb70f2f8e483ab8 (diff)
parent028dbf434343981d96ac65fe19f5268eea3fcb68 (diff)
Merge changes I6b4d256d,Ib62baf67,Ia9427c81 into main
* changes: Rename Key.name to Key.debugName Add support for movable elements Revert "[flexiglass] Added isUserInputOngoing to transition model"
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt23
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt12
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt10
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt180
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt12
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt9
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt36
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt2
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt5
-rw-r--r--packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt62
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt207
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt4
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt14
-rw-r--r--packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt18
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt27
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt10
25 files changed, 537 insertions, 155 deletions
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
index 60c3fd3c4cdb..88944f10eab9 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/AnimateToScene.kt
@@ -108,7 +108,7 @@ private fun CoroutineScope.animate(
) {
val fromScene = layoutImpl.state.transitionState.currentScene
val isUserInput =
- (layoutImpl.state.transitionState as? TransitionState.Transition)?.isInitiatedByUserInput
+ (layoutImpl.state.transitionState as? TransitionState.Transition)?.isUserInputDriven
?: false
val animationSpec = layoutImpl.transitions.transitionSpec(fromScene, target).spec
@@ -119,23 +119,9 @@ private fun CoroutineScope.animate(
val targetProgress = if (reversed) 0f else 1f
val transition =
if (reversed) {
- OneOffTransition(
- fromScene = target,
- toScene = fromScene,
- currentScene = target,
- isUserInput,
- isUserInputOngoing = false,
- animatable,
- )
+ OneOffTransition(target, fromScene, currentScene = target, isUserInput, animatable)
} else {
- OneOffTransition(
- fromScene = fromScene,
- toScene = target,
- currentScene = target,
- isUserInput,
- isUserInputOngoing = false,
- animatable,
- )
+ OneOffTransition(fromScene, target, currentScene = target, isUserInput, animatable)
}
// Change the current layout state to use this new transition.
@@ -156,8 +142,7 @@ private class OneOffTransition(
override val fromScene: SceneKey,
override val toScene: SceneKey,
override val currentScene: SceneKey,
- override val isInitiatedByUserInput: Boolean,
- override val isUserInputOngoing: Boolean,
+ override val isUserInputDriven: Boolean,
private val animatable: Animatable<Float, AnimationVector1D>,
) : TransitionState.Transition {
override val progress: Float
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
index 3bcd920fb02b..ce96bbfc7976 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Element.kt
@@ -21,6 +21,7 @@ import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.movableContentOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
@@ -59,6 +60,17 @@ internal class Element(val key: ElementKey) {
/** The mapping between a scene and the values/state this element has in that scene, if any. */
val sceneValues = SnapshotStateMap<SceneKey, TargetValues>()
+ /**
+ * The movable content of this element, if this element is composed using
+ * [SceneScope.MovableElement].
+ */
+ val movableContent by
+ // This is only accessed from the composition (main) thread, so no need to use the default
+ // lock of lazy {} to synchronize.
+ lazy(mode = LazyThreadSafetyMode.NONE) {
+ movableContentOf { content: @Composable () -> Unit -> content() }
+ }
+
override fun toString(): String {
return "Element(key=$key)"
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
index b7acc48e2865..bc015eedb1b4 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt
@@ -22,7 +22,7 @@ import androidx.annotation.VisibleForTesting
* A base class to create unique keys, associated to an [identity] that is used to check the
* equality of two key instances.
*/
-sealed class Key(val name: String, val identity: Any) {
+sealed class Key(val debugName: String, val identity: Any) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (this.javaClass != other?.javaClass) return false
@@ -34,7 +34,7 @@ sealed class Key(val name: String, val identity: Any) {
}
override fun toString(): String {
- return "Key(name=$name)"
+ return "Key(debugName=$debugName)"
}
}
@@ -49,7 +49,7 @@ class SceneKey(
val rootElementKey = ElementKey(name, identity)
override fun toString(): String {
- return "SceneKey(name=$name)"
+ return "SceneKey(debugName=$debugName)"
}
}
@@ -71,7 +71,7 @@ class ElementKey(
}
override fun toString(): String {
- return "ElementKey(name=$name)"
+ return "ElementKey(debugName=$debugName)"
}
companion object {
@@ -89,6 +89,6 @@ class ElementKey(
/** Key for a shared value of an element. */
class ValueKey(name: String, identity: Any = Object()) : Key(name, identity) {
override fun toString(): String {
- return "ValueKey(name=$name)"
+ return "ValueKey(debugName=$debugName)"
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt
new file mode 100644
index 000000000000..11bbf2aa987e
--- /dev/null
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/MovableElement.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import android.graphics.Picture
+import android.util.Log
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithCache
+import androidx.compose.ui.graphics.Canvas
+import androidx.compose.ui.graphics.drawscope.draw
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.layout.layout
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.IntSize
+
+private const val TAG = "MovableElement"
+
+private object MovableElementScopeImpl : MovableElementScope
+
+@Composable
+internal fun MovableElement(
+ layoutImpl: SceneTransitionLayoutImpl,
+ scene: Scene,
+ key: ElementKey,
+ modifier: Modifier,
+ content: @Composable MovableElementScope.() -> Unit,
+) {
+ Box(modifier.element(layoutImpl, scene, key)) {
+ // Get the Element from the map. It will always be the same and we don't want to recompose
+ // every time an element is added/removed from SceneTransitionLayoutImpl.elements, so we
+ // disable read observation during the look-up in that map.
+ val element = Snapshot.withoutReadObservation { layoutImpl.elements.getValue(key) }
+
+ // The [Picture] to which we save the last drawing commands of this element. This is
+ // necessary because the content of this element might not be composed in this scene, in
+ // which case we still need to draw it.
+ val picture = remember { Picture() }
+
+ if (shouldComposeMovableElement(layoutImpl, scene.key, element)) {
+ Box(
+ Modifier.drawWithCache {
+ val width = size.width.toInt()
+ val height = size.height.toInt()
+
+ onDrawWithContent {
+ // Save the draw commands into [picture] for later to draw the last content
+ // even when this movable content is not composed.
+ val pictureCanvas = Canvas(picture.beginRecording(width, height))
+ draw(this, this.layoutDirection, pictureCanvas, this.size) {
+ this@onDrawWithContent.drawContent()
+ }
+ picture.endRecording()
+
+ // Draw the content.
+ drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+ }
+ }
+ ) {
+ element.movableContent { MovableElementScopeImpl.content() }
+ }
+ } else {
+ // If we are not composed, we draw the previous drawing commands at the same size as the
+ // movable content when it was composed in this scene.
+ val sceneValues = element.sceneValues.getValue(scene.key)
+
+ Spacer(
+ Modifier.layout { measurable, _ ->
+ val size =
+ sceneValues.targetSize.takeIf { it != Element.SizeUnspecified }
+ ?: IntSize.Zero
+ val placeable =
+ measurable.measure(Constraints.fixed(size.width, size.height))
+ layout(size.width, size.height) { placeable.place(0, 0) }
+ }
+ .drawBehind {
+ drawIntoCanvas { canvas -> canvas.nativeCanvas.drawPicture(picture) }
+ }
+ )
+ }
+ }
+}
+
+private fun shouldComposeMovableElement(
+ layoutImpl: SceneTransitionLayoutImpl,
+ scene: SceneKey,
+ element: Element,
+): Boolean {
+ val transitionState = layoutImpl.state.transitionState
+
+ // If we are idle, there is only one [scene] that is composed so we can compose our movable
+ // content here.
+ if (transitionState is TransitionState.Idle) {
+ check(transitionState.currentScene == scene)
+ return true
+ }
+
+ val fromScene = (transitionState as TransitionState.Transition).fromScene
+ val toScene = transitionState.toScene
+ if (fromScene == toScene) {
+ check(fromScene == scene)
+ return true
+ }
+
+ val fromReady = layoutImpl.isSceneReady(fromScene)
+ val toReady = layoutImpl.isSceneReady(toScene)
+
+ val otherScene =
+ when (scene) {
+ fromScene -> toScene
+ toScene -> fromScene
+ else ->
+ error(
+ "shouldComposeMovableElement(scene=$scene) called with fromScene=$fromScene " +
+ "and toScene=$toScene"
+ )
+ }
+
+ val isShared = otherScene in element.sceneValues
+
+ if (isShared && !toReady && !fromReady) {
+ // This should usually not happen given that fromScene should be ready, but let's log a
+ // warning here in case it does so it helps debugging flicker issues caused by this part of
+ // the code.
+ Log.w(
+ TAG,
+ "MovableElement $element might have to be composed for the first time in both " +
+ "fromScene=$fromScene and toScene=$toScene. This will probably lead to a flicker " +
+ "where the size of the element will jump from IntSize.Zero to its actual size " +
+ "during the transition."
+ )
+ }
+
+ // Element is not shared in this transition.
+ if (!isShared) {
+ return true
+ }
+
+ // toScene is not ready (because we are composing it for the first time), so we compose it there
+ // first. This is the most common scenario when starting a transition that has a shared movable
+ // element.
+ if (!toReady) {
+ return scene == toScene
+ }
+
+ // This should usually not happen, but if we are also composing for the first time in fromScene
+ // then we should compose it there only.
+ if (!fromReady) {
+ return scene == fromScene
+ }
+
+ // If we are ready in both scenes, then compose in the scene that has the highest zIndex (unless
+ // it is a background) given that this is the one that is going to be drawn.
+ val isHighestScene = layoutImpl.scene(scene).zIndex > layoutImpl.scene(otherScene).zIndex
+ return if (element.key.isBackground) {
+ !isHighestScene
+ } else {
+ isHighestScene
+ }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
index 1b79dbdee510..ccdec6ea8c5e 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/ObservableTransitionState.kt
@@ -52,14 +52,7 @@ sealed class ObservableTransitionState {
* scene, this value will remain true after the pointer is no longer touching the screen and
* will be true in any transition created to animate back to the original position.
*/
- val isInitiatedByUserInput: Boolean,
-
- /**
- * Whether user input is currently driving the transition. For example, if a user is
- * dragging a pointer, this emits true. Once they lift their finger, this emits false while
- * the transition completes/settles.
- */
- val isUserInputOngoing: Flow<Boolean>,
+ val isUserInputDriven: Boolean,
) : ObservableTransitionState()
}
@@ -80,8 +73,7 @@ fun SceneTransitionLayoutState.observableTransitionState(): Flow<ObservableTrans
fromScene = state.fromScene,
toScene = state.toScene,
progress = snapshotFlow { state.progress },
- isInitiatedByUserInput = state.isInitiatedByUserInput,
- isUserInputOngoing = snapshotFlow { state.isUserInputOngoing },
+ isUserInputDriven = state.isUserInputDriven,
)
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
index 3985233bd197..3fd6828fca6b 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Scene.kt
@@ -90,4 +90,13 @@ private class SceneScopeImpl(
canOverflow,
)
}
+
+ @Composable
+ override fun MovableElement(
+ key: ElementKey,
+ modifier: Modifier,
+ content: @Composable MovableElementScope.() -> Unit,
+ ) {
+ MovableElement(layoutImpl, scene, key, modifier, content)
+ }
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 58c7bdbf3d71..4283c0e61df8 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -85,6 +85,13 @@ interface SceneTransitionLayoutScope {
)
}
+/**
+ * A DSL marker to prevent people from nesting calls to Modifier.element() inside a MovableElement,
+ * which is not supported.
+ */
+@DslMarker annotation class ElementDsl
+
+@ElementDsl
interface SceneScope {
/**
* Tag an element identified by [key].
@@ -95,12 +102,37 @@ interface SceneScope {
* Additionally, this [key] will be used to detect elements that are shared between scenes to
* automatically interpolate their size, offset and [shared values][animateSharedValueAsState].
*
+ * Note that shared elements tagged using this function will be duplicated in each scene they
+ * are part of, so any **internal** state (e.g. state created using `remember {
+ * mutableStateOf(...) }`) will be lost. If you need to preserve internal state, you should use
+ * [MovableElement] instead.
+ *
+ * @see MovableElement
+ *
* TODO(b/291566282): Migrate this to the new Modifier Node API and remove the @Composable
* constraint.
*/
@Composable fun Modifier.element(key: ElementKey): Modifier
/**
+ * Create a *movable* element identified by [key].
+ *
+ * This creates an element that will be automatically shared when present in multiple scenes and
+ * that can be transformed during transitions, the same way that [element] does. The major
+ * difference with [element] is that elements created with [MovableElement] will be "moved" and
+ * composed only once during transitions (as opposed to [element] that duplicates shared
+ * elements) so that any internal state is preserved during and after the transition.
+ *
+ * @see element
+ */
+ @Composable
+ fun MovableElement(
+ key: ElementKey,
+ modifier: Modifier,
+ content: @Composable MovableElementScope.() -> Unit,
+ )
+
+ /**
* Animate some value of a shared element.
*
* @param value the value of this shared value in the current scene.
@@ -126,6 +158,10 @@ interface SceneScope {
): State<T>
}
+// TODO(b/291053742): Add animateSharedValueAsState(targetValue) without any ValueKey and ElementKey
+// arguments to allow sharing values inside a movable element.
+@ElementDsl interface MovableElementScope
+
/** An action performed by the user. */
sealed interface UserAction
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index b3a7a8e9f874..4952270cb5f2 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -199,4 +199,6 @@ internal class SceneTransitionLayoutImpl(
return readyScenes.containsKey(transition.fromScene) &&
readyScenes.containsKey(transition.toScene)
}
+
+ internal fun isSceneReady(scene: SceneKey): Boolean = readyScenes.containsKey(scene)
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
index b9f83c545122..7a21211c3dde 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitionLayoutState.kt
@@ -70,9 +70,6 @@ sealed interface TransitionState {
val progress: Float
/** Whether the transition was triggered by user input rather than being programmatic. */
- val isInitiatedByUserInput: Boolean
-
- /** Whether user input is currently driving the transition. */
- val isUserInputOngoing: Boolean
+ val isUserInputDriven: Boolean
}
}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
index e275fcaf4572..1cbfe3057ff0 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SwipeToScene.kt
@@ -66,7 +66,7 @@ internal fun Modifier.swipeToScene(
// swipe in the other direction.
val startDragImmediately =
state == transition &&
- !transition.isUserInputOngoing &&
+ transition.isAnimatingOffset &&
!currentScene.shouldEnableSwipes(orientation.opposite())
// The velocity threshold at which the intent of the user is to swipe up or down. It is the same
@@ -126,7 +126,7 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition
override val progress: Float
get() {
- val offset = if (isUserInputOngoing) dragOffset else offsetAnimatable.value
+ val offset = if (isAnimatingOffset) offsetAnimatable.value else dragOffset
if (distance == 0f) {
// This can happen only if fromScene == toScene.
error(
@@ -137,15 +137,16 @@ private class SwipeTransition(initialScene: Scene) : TransitionState.Transition
return offset / distance
}
- override val isInitiatedByUserInput = true
-
- var _isUserInputOngoing by mutableStateOf(false)
- override val isUserInputOngoing: Boolean
- get() = _isUserInputOngoing
+ override val isUserInputDriven = true
/** The current offset caused by the drag gesture. */
var dragOffset by mutableFloatStateOf(0f)
+ /**
+ * Whether the offset is animated (the user lifted their finger) or if it is driven by gesture.
+ */
+ var isAnimatingOffset by mutableStateOf(false)
+
/** The animatable used to animate the offset once the user lifted its finger. */
val offsetAnimatable = Animatable(0f, visibilityThreshold = OffsetVisibilityThreshold)
@@ -208,11 +209,9 @@ private fun onDragStarted(
transition: SwipeTransition,
orientation: Orientation,
) {
- transition._isUserInputOngoing = true
-
if (layoutImpl.state.transitionState == transition) {
// This [transition] was already driving the animation: simply take over it.
- if (!transition.isUserInputOngoing) {
+ if (transition.isAnimatingOffset) {
// Stop animating and start from where the current offset. Setting the animation job to
// `null` will effectively cancel the animation.
transition.stopOffsetAnimation()
@@ -457,29 +456,30 @@ private fun CoroutineScope.animateOffset(
) {
transition.startOffsetAnimation {
launch {
- if (transition.isUserInputOngoing) {
- transition.offsetAnimatable.snapTo(transition.dragOffset)
- }
- transition._isUserInputOngoing = false
-
- transition.offsetAnimatable.animateTo(
- targetOffset,
- // TODO(b/290184746): Make this spring spec configurable.
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = OffsetVisibilityThreshold
- ),
- initialVelocity = initialVelocity,
- )
+ if (!transition.isAnimatingOffset) {
+ transition.offsetAnimatable.snapTo(transition.dragOffset)
+ }
+ transition.isAnimatingOffset = true
+
+ transition.offsetAnimatable.animateTo(
+ targetOffset,
+ // TODO(b/290184746): Make this spring spec configurable.
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = OffsetVisibilityThreshold
+ ),
+ initialVelocity = initialVelocity,
+ )
- // Now that the animation is done, the state should be idle. Note that if the state
- // was changed since this animation started, some external code changed it and we
- // shouldn't do anything here. Note also that this job will be cancelled in the case
- // where the user intercepts this swipe.
- if (layoutImpl.state.transitionState == transition) {
- layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
+ // Now that the animation is done, the state should be idle. Note that if the state
+ // was changed since this animation started, some external code changed it and we
+ // shouldn't do anything here. Note also that this job will be cancelled in the case
+ // where the user intercepts this swipe.
+ if (layoutImpl.state.transitionState == transition) {
+ layoutImpl.state.transitionState = TransitionState.Idle(targetScene)
+ }
}
- }
+ .also { it.invokeOnCompletion { transition.isAnimatingOffset = false } }
}
}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
new file mode 100644
index 000000000000..4204cd5f0da0
--- /dev/null
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/MovableElementTest.kt
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.hasParent
+import androidx.compose.ui.test.hasText
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.test.assertSizeIsEqualTo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class MovableElementTest {
+ @get:Rule val rule = createComposeRule()
+
+ /** An element that displays a counter that is incremented whenever this element is clicked. */
+ @Composable
+ private fun Counter(modifier: Modifier = Modifier) {
+ var count by remember { mutableIntStateOf(0) }
+ Box(modifier.fillMaxSize().clickable { count++ }) { Text("count: $count") }
+ }
+
+ @Composable
+ private fun SceneScope.MovableCounter(key: ElementKey, modifier: Modifier) {
+ MovableElement(key, modifier) { Counter() }
+ }
+
+ @Test
+ fun modifierElementIsDuplicatedDuringTransitions() {
+ rule.testTransition(
+ fromSceneContent = {
+ Box(Modifier.element(TestElements.Foo).size(50.dp)) { Counter() }
+ },
+ toSceneContent = { Box(Modifier.element(TestElements.Foo).size(100.dp)) { Counter() } },
+ transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) },
+ fromScene = TestScenes.SceneA,
+ toScene = TestScenes.SceneB,
+ ) {
+ before {
+ // Click 3 times on the counter.
+ rule.onNodeWithText("count: 0").assertIsDisplayed().performClick()
+ rule.onNodeWithText("count: 1").assertIsDisplayed().performClick()
+ rule.onNodeWithText("count: 2").assertIsDisplayed().performClick()
+ rule
+ .onNodeWithText("count: 3")
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(50.dp, 50.dp)
+
+ // There are no other counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(1)
+ }
+
+ at(32) {
+ // In the middle of the transition, there are 2 copies of the counter: the previous
+ // one from scene A (equal to 3) and the new one from scene B (equal to 0).
+ rule
+ .onNode(
+ hasText("count: 3") and
+ hasParent(isElement(TestElements.Foo, scene = TestScenes.SceneA))
+ )
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(75.dp, 75.dp)
+
+ rule
+ .onNode(
+ hasText("count: 0") and
+ hasParent(isElement(TestElements.Foo, scene = TestScenes.SceneB))
+ )
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(75.dp, 75.dp)
+
+ // There are exactly 2 counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(2)
+ }
+
+ after {
+ // At the end of the transition, only the counter from scene B is composed.
+ rule
+ .onNodeWithText("count: 0")
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(100.dp, 100.dp)
+
+ // There are no other counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(1)
+ }
+ }
+ }
+
+ @Test
+ fun movableElementIsMovedAndComposedOnlyOnce() {
+ rule.testTransition(
+ fromSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(50.dp)) },
+ toSceneContent = { MovableCounter(TestElements.Foo, Modifier.size(100.dp)) },
+ transition = { spec = tween(durationMillis = 16 * 4, easing = LinearEasing) },
+ fromScene = TestScenes.SceneA,
+ toScene = TestScenes.SceneB,
+ ) {
+ before {
+ // Click 3 times on the counter.
+ rule.onNodeWithText("count: 0").assertIsDisplayed().performClick()
+ rule.onNodeWithText("count: 1").assertIsDisplayed().performClick()
+ rule.onNodeWithText("count: 2").assertIsDisplayed().performClick()
+ rule
+ .onNodeWithText("count: 3")
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(50.dp, 50.dp)
+
+ // There are no other counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(1)
+ }
+
+ at(32) {
+ // During the transition, there is a single counter that is moved, with the current
+ // value.
+ rule
+ .onNode(hasText("count: 3"))
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(75.dp, 75.dp)
+
+ // There are no other counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(1)
+ }
+
+ after {
+ // At the end of the transition, the counter still has the current value.
+ rule
+ .onNodeWithText("count: 3")
+ .assertIsDisplayed()
+ .assertSizeIsEqualTo(100.dp, 100.dp)
+
+ // There are no other counters.
+ assertThat(
+ rule
+ .onAllNodesWithText("count: ", substring = true)
+ .fetchSemanticsNodes()
+ .size
+ )
+ .isEqualTo(1)
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index 328866ea76ca..5afd420a5e16 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -117,7 +117,7 @@ class SceneTransitionLayoutTest {
.size(size)
.background(Color.Red)
.element(TestElements.Foo)
- .testTag(TestElements.Foo.name)
+ .testTag(TestElements.Foo.debugName)
) {
// Offset the single child of Foo by some animated shared offset.
val offset by animateSharedDpAsState(childOffset, TestValues.Value1, TestElements.Foo)
@@ -129,7 +129,7 @@ class SceneTransitionLayoutTest {
}
.size(30.dp)
.background(Color.Blue)
- .testTag(TestElements.Bar.name)
+ .testTag(TestElements.Bar.debugName)
)
}
}
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
index 53ed2b5d3317..df3b72aa5533 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/SwipeToSceneTest.kt
@@ -63,7 +63,7 @@ class SwipeToSceneTest {
{ currentScene = it },
EmptyTestTransitions,
state = layoutState,
- modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.name),
+ modifier = Modifier.size(LayoutWidth, LayoutHeight).testTag(TestElements.Foo.debugName),
) {
scene(
TestScenes.SceneA,
@@ -122,8 +122,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isInitiatedByUserInput).isTrue()
- assertThat(transition.isUserInputOngoing).isTrue()
+ assertThat(transition.isUserInputDriven).isTrue()
// Release the finger. We should now be animating back to A (currentScene = SceneA) given
// that 55dp < positional threshold.
@@ -135,8 +134,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneB)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(55.dp / LayoutWidth)
- assertThat(transition.isInitiatedByUserInput).isTrue()
- assertThat(transition.isUserInputOngoing).isFalse()
+ assertThat(transition.isUserInputDriven).isTrue()
// Wait for the animation to finish. We should now be in scene A.
rule.waitForIdle()
@@ -158,8 +156,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneA)
assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isInitiatedByUserInput).isTrue()
- assertThat(transition.isUserInputOngoing).isTrue()
+ assertThat(transition.isUserInputDriven).isTrue()
// Release the finger. We should now be animating to C (currentScene = SceneC) given
// that 56dp >= positional threshold.
@@ -171,8 +168,7 @@ class SwipeToSceneTest {
assertThat(transition.toScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.currentScene).isEqualTo(TestScenes.SceneC)
assertThat(transition.progress).isEqualTo(56.dp / LayoutHeight)
- assertThat(transition.isInitiatedByUserInput).isTrue()
- assertThat(transition.isUserInputOngoing).isFalse()
+ assertThat(transition.isUserInputDriven).isTrue()
// Wait for the animation to finish. We should now be in scene C.
rule.waitForIdle()
diff --git a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
index 268057fd2f2c..e0ae1be69aaf 100644
--- a/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/core/tests/src/com/android/compose/animation/scene/TestTransition.kt
@@ -22,13 +22,13 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
+import androidx.compose.ui.test.SemanticsMatcher
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionCollection
import androidx.compose.ui.test.hasParent
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.junit4.ComposeContentTestRule
import androidx.compose.ui.test.onAllNodesWithTag
-import androidx.compose.ui.test.onNodeWithTag
@DslMarker annotation class TransitionTestDsl
@@ -63,6 +63,8 @@ interface TransitionTestBuilder {
@TransitionTestDsl
interface TransitionTestAssertionScope {
+ fun isElement(element: ElementKey, scene: SceneKey? = null): SemanticsMatcher
+
/**
* Assert on [element].
*
@@ -130,15 +132,19 @@ fun ComposeContentTestRule.testTransition(
val test = transitionTest(builder)
val assertionScope =
object : TransitionTestAssertionScope {
+ override fun isElement(element: ElementKey, scene: SceneKey?): SemanticsMatcher {
+ return if (scene == null) {
+ hasTestTag(element.testTag)
+ } else {
+ hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag))
+ }
+ }
+
override fun onElement(
element: ElementKey,
scene: SceneKey?
): SemanticsNodeInteraction {
- return if (scene == null) {
- onNodeWithTag(element.testTag)
- } else {
- onNode(hasTestTag(element.testTag) and hasParent(hasTestTag(scene.testTag)))
- }
+ return onNode(isElement(element, scene))
}
override fun onSharedElement(element: ElementKey): SemanticsNodeInteractionCollection {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index 0da562bcb3bb..2e93a09deb30 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -161,8 +161,7 @@ private fun SceneTransitionObservableTransitionState.toModel(): ObservableTransi
fromScene = fromScene.toModel().key,
toScene = toScene.toModel().key,
progress = progress,
- isInitiatedByUserInput = isInitiatedByUserInput,
- isUserInputOngoing = isUserInputOngoing,
+ isUserInputDriven = isUserInputDriven,
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
index f704894e56e2..3927873f8ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/ObservableTransitionState.kt
@@ -42,13 +42,6 @@ sealed class ObservableTransitionState {
* scene, this value will remain true after the pointer is no longer touching the screen and
* will be true in any transition created to animate back to the original position.
*/
- val isInitiatedByUserInput: Boolean,
-
- /**
- * Whether user input is currently driving the transition. For example, if a user is
- * dragging a pointer, this emits true. Once they lift their finger, this emits false while
- * the transition completes/settles.
- */
- val isUserInputOngoing: Flow<Boolean>,
+ val isUserInputDriven: Boolean,
) : ObservableTransitionState()
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 6117f9f80e6c..e487a6fb9617 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -261,7 +261,7 @@ constructor(
when (state) {
is ObservableTransitionState.Idle -> false
is ObservableTransitionState.Transition ->
- state.isInitiatedByUserInput &&
+ state.isUserInputDriven &&
(state.toScene == sceneKey || state.fromScene == sceneKey)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index 62f9a9dcce70..20d4eb907944 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -810,7 +810,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
flowOf(.5f),
false,
- isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -826,8 +825,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
SceneKey.Gone,
flowOf(.5f),
- false,
- isUserInputOngoing = flowOf(false),
+ false
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -844,8 +842,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Gone,
SceneKey.Bouncer,
flowOf(.5f),
- false,
- isUserInputOngoing = flowOf(false),
+ false
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Bouncer, null), "reason")
@@ -863,8 +860,7 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Bouncer,
SceneKey.Gone,
flowOf(.5f),
- false,
- isUserInputOngoing = flowOf(false),
+ false
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
@@ -880,7 +876,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Lockscreen,
flowOf(.5f),
false,
- isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Lockscreen, null), "reason")
@@ -898,7 +893,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
SceneKey.Gone,
flowOf(.5f),
false,
- isUserInputOngoing = flowOf(false),
)
runCurrent()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone, null), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
index 9ee22c89405d..b32905fd3b79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractorTest.kt
@@ -204,8 +204,7 @@ class KeyguardInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Lockscreen,
progress = flowOf(0f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
runCurrent()
assertThat(isAnimate).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 2e16577bb24f..61dd69a8126b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -52,7 +52,6 @@ import com.google.common.truth.Truth.assertWithMessage
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -463,8 +462,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
fromScene = getCurrentSceneInUi(),
toScene = to.key,
progress = progressFlow,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
runCurrent()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
index 740c6d9329df..432bd0f2a050 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/data/repository/SceneContainerRepositoryTest.kt
@@ -29,7 +29,6 @@ import com.android.systemui.scene.shared.model.SceneModel
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
@@ -120,8 +119,7 @@ class SceneContainerRepositoryTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
index 31d26c0d88f9..8b23d183f1a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/interactor/SceneInteractorTest.kt
@@ -83,8 +83,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(reflectedTransitionState).isEqualTo(transitionState.value)
@@ -122,8 +121,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = underTest.desiredScene.value.key,
toScene = SceneKey.Shade,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(transitionTo).isEqualTo(SceneKey.Shade)
@@ -160,8 +158,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
val transitioning by
@@ -180,8 +177,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.QuickSettings,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
underTest.setTransitionState(transitionState)
@@ -198,8 +194,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
val transitioning by
@@ -227,8 +222,7 @@ class SceneInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Lockscreen,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(transitioning).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
index 3b9621e5c6e0..7b13de657657 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/domain/startable/SceneContainerStartableTest.kt
@@ -109,8 +109,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Shade), "reason")
@@ -123,8 +122,7 @@ class SceneContainerStartableTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.Gone,
progress = flowOf(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
assertThat(isVisible).isTrue()
sceneInteractor.onSceneChanged(SceneModel(SceneKey.Gone), "reason")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index bcb060ddb417..81382a44def6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -60,7 +60,6 @@ import dagger.BindsInstance
import dagger.Component
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
@@ -595,8 +594,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -633,8 +631,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -670,8 +667,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.Shade,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -947,8 +943,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -985,8 +980,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = SceneKey.Lockscreen,
toScene = key,
progress = progress,
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = true,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -1023,8 +1017,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -1061,8 +1054,7 @@ class ShadeInteractorTest : SysuiTestCase() {
fromScene = key,
toScene = SceneKey.Lockscreen,
progress = progress,
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = true,
)
)
sceneInteractor.setTransitionState(transitionState)
@@ -1097,9 +1089,8 @@ class ShadeInteractorTest : SysuiTestCase() {
ObservableTransitionState.Transition(
fromScene = SceneKey.Lockscreen,
toScene = SceneKey.QuickSettings,
- progress = MutableStateFlow(0f),
- isInitiatedByUserInput = true,
- isUserInputOngoing = flowOf(false),
+ progress = progress,
+ isUserInputDriven = true,
)
)
sceneInteractor.setTransitionState(transitionState)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
index bb20d94e7d39..607cdab12f56 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeHeaderViewModelTest.kt
@@ -17,7 +17,6 @@ import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnec
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
@@ -85,8 +84,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.Shade,
toScene = SceneKey.QuickSettings,
progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
)
@@ -104,8 +102,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.QuickSettings,
toScene = SceneKey.Shade,
progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
)
@@ -123,8 +120,7 @@ class ShadeHeaderViewModelTest : SysuiTestCase() {
fromScene = SceneKey.Gone,
toScene = SceneKey.Shade,
progress = MutableStateFlow(0.5f),
- isInitiatedByUserInput = false,
- isUserInputOngoing = flowOf(false),
+ isUserInputDriven = false,
)
)
)