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

Commit 500a5280 authored by Mike Schneider's avatar Mike Schneider Committed by Android (Google) Code Review
Browse files

Merge "Move STL specific FeatureCapture / DataPointTypes to testing utilities" into main

parents fd3893de a32356a1
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.compose.animation.scene.testing

import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.Element
import com.android.compose.animation.scene.Element.Companion.AlphaUnspecified
import com.android.compose.animation.scene.Element.Companion.SizeUnspecified
import com.android.compose.animation.scene.ElementModifier
import com.android.compose.animation.scene.Scale

@@ -28,6 +31,12 @@ val SemanticsNode.lastAlphaForTesting: Float?
val SemanticsNode.lastScaleForTesting: Scale?
    get() = elementState.lastScale.takeIf { it != Scale.Unspecified }

val SemanticsNode.lastOffsetForTesting: Offset?
    get() = elementState.lastOffset.takeIf { it != Offset.Unspecified }

val SemanticsNode.lastSizeForTesting: IntSize?
    get() = elementState.lastSize.takeIf { it != SizeUnspecified }

private val SemanticsNode.elementState: Element.State
    get() {
        val elementModifier =
+84 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.ui.geometry.Offset
import androidx.compose.ui.geometry.isFinite
import androidx.compose.ui.geometry.isUnspecified
import org.json.JSONObject
import platform.test.motion.golden.DataPointType
import platform.test.motion.golden.UnknownTypeException

fun Scale.asDataPoint() = DataPointTypes.scale.makeDataPoint(this)

object DataPointTypes {
    val scale: DataPointType<Scale> =
        DataPointType(
            "scale",
            jsonToValue = {
                when (it) {
                    "unspecified" -> Scale.Unspecified
                    "default" -> Scale.Default
                    "zero" -> Scale.Zero
                    is JSONObject -> {
                        val pivot = it.get("pivot")
                        Scale(
                            scaleX = it.getDouble("x").toFloat(),
                            scaleY = it.getDouble("y").toFloat(),
                            pivot =
                                when (pivot) {
                                    "unspecified" -> Offset.Unspecified
                                    "infinite" -> Offset.Infinite
                                    is JSONObject ->
                                        Offset(
                                            pivot.getDouble("x").toFloat(),
                                            pivot.getDouble("y").toFloat(),
                                        )
                                    else -> throw UnknownTypeException()
                                },
                        )
                    }
                    else -> throw UnknownTypeException()
                }
            },
            valueToJson = {
                when (it) {
                    Scale.Unspecified -> "unspecified"
                    Scale.Default -> "default"
                    Scale.Zero -> "zero"
                    else -> {
                        JSONObject().apply {
                            put("x", it.scaleX)
                            put("y", it.scaleY)
                            put(
                                "pivot",
                                when {
                                    it.pivot.isUnspecified -> "unspecified"
                                    !it.pivot.isFinite -> "infinite"
                                    else ->
                                        JSONObject().apply {
                                            put("x", it.pivot.x)
                                            put("y", it.pivot.y)
                                        }
                                },
                            )
                        }
                    }
                }
            },
        )
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.ui.geometry.Offset
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.DataPointTypes.scale
import com.android.compose.animation.scene.testing.lastAlphaForTesting
import com.android.compose.animation.scene.testing.lastOffsetForTesting
import com.android.compose.animation.scene.testing.lastScaleForTesting
import com.android.compose.animation.scene.testing.lastSizeForTesting
import platform.test.motion.compose.DataPointTypes.intSize
import platform.test.motion.compose.DataPointTypes.offset
import platform.test.motion.golden.DataPoint
import platform.test.motion.golden.DataPointTypes
import platform.test.motion.golden.FeatureCapture

/**
 * [FeatureCapture] implementations to record animated state of [SceneTransitionLayout] [Element].
 */
object FeatureCaptures {

    val elementAlpha =
        FeatureCapture<SemanticsNode, Float>("alpha") {
            DataPoint.of(it.lastAlphaForTesting, DataPointTypes.float)
        }

    val elementScale =
        FeatureCapture<SemanticsNode, Scale>("scale") {
            DataPoint.of(it.lastScaleForTesting, scale)
        }

    val elementOffset =
        FeatureCapture<SemanticsNode, Offset>("offset") {
            DataPoint.of(it.lastOffsetForTesting, offset)
        }

    val elementSize =
        FeatureCapture<SemanticsNode, IntSize>("size") {
            DataPoint.of(it.lastSizeForTesting, intSize)
        }
}
+3 −82
Original line number Diff line number Diff line
@@ -30,22 +30,17 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.isFinite
import androidx.compose.ui.geometry.isUnspecified
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.FeatureCaptures.elementAlpha
import com.android.compose.animation.scene.FeatureCaptures.elementScale
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.compose.animation.scene.Scale
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.isElement
import com.android.compose.animation.scene.testing.lastAlphaForTesting
import com.android.compose.animation.scene.testing.lastScaleForTesting
import com.android.compose.theme.PlatformTheme
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.domain.interactor.bouncerInteractor
@@ -71,12 +66,12 @@ import com.android.systemui.scene.ui.composable.Scene
import com.android.systemui.scene.ui.composable.SceneContainer
import com.android.systemui.scene.ui.view.sceneJankMonitorFactory
import com.android.systemui.testKosmos
import kotlin.test.Ignore
import kotlin.time.Duration.Companion.seconds
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import org.json.JSONObject
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -89,14 +84,8 @@ import platform.test.motion.compose.MotionControl
import platform.test.motion.compose.feature
import platform.test.motion.compose.recordMotion
import platform.test.motion.compose.runTest
import platform.test.motion.golden.DataPoint
import platform.test.motion.golden.DataPointType
import platform.test.motion.golden.DataPointTypes
import platform.test.motion.golden.FeatureCapture
import platform.test.motion.golden.UnknownTypeException
import platform.test.screenshot.DeviceEmulationSpec
import platform.test.screenshot.Displays.Phone
import kotlin.test.Ignore

/** MotionTest for the Bouncer Predictive Back animation */
@LargeTest
@@ -280,72 +269,4 @@ class BouncerPredictiveBackTest : SysuiTestCase() {

        override suspend fun onActivated() = awaitCancellation()
    }

    companion object {
        private val elementAlpha =
            FeatureCapture<SemanticsNode, Float>("alpha") {
                DataPoint.of(it.lastAlphaForTesting, DataPointTypes.float)
            }

        private val elementScale =
            FeatureCapture<SemanticsNode, Scale>("scale") {
                DataPoint.of(it.lastScaleForTesting, scale)
            }

        private val scale: DataPointType<Scale> =
            DataPointType(
                "scale",
                jsonToValue = {
                    when (it) {
                        "unspecified" -> Scale.Unspecified
                        "default" -> Scale.Default
                        "zero" -> Scale.Zero
                        is JSONObject -> {
                            val pivot = it.get("pivot")
                            Scale(
                                scaleX = it.getDouble("x").toFloat(),
                                scaleY = it.getDouble("y").toFloat(),
                                pivot =
                                    when (pivot) {
                                        "unspecified" -> Offset.Unspecified
                                        "infinite" -> Offset.Infinite
                                        is JSONObject ->
                                            Offset(
                                                pivot.getDouble("x").toFloat(),
                                                pivot.getDouble("y").toFloat(),
                                            )
                                        else -> throw UnknownTypeException()
                                    },
                            )
                        }
                        else -> throw UnknownTypeException()
                    }
                },
                valueToJson = {
                    when (it) {
                        Scale.Unspecified -> "unspecified"
                        Scale.Default -> "default"
                        Scale.Zero -> "zero"
                        else -> {
                            JSONObject().apply {
                                put("x", it.scaleX)
                                put("y", it.scaleY)
                                put(
                                    "pivot",
                                    when {
                                        it.pivot.isUnspecified -> "unspecified"
                                        !it.pivot.isFinite -> "infinite"
                                        else ->
                                            JSONObject().apply {
                                                put("x", it.pivot.x)
                                                put("y", it.pivot.y)
                                            }
                                    },
                                )
                            }
                        }
                    }
                },
            )
    }
}