1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package platform.test.motion.compose
18
19 import androidx.compose.ui.semantics.SemanticsNode
20 import androidx.compose.ui.test.SemanticsMatcher
21 import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
22 import androidx.compose.ui.unit.DpOffset
23 import androidx.compose.ui.unit.DpSize
24 import androidx.compose.ui.unit.IntSize
25 import androidx.compose.ui.unit.toSize
26 import platform.test.motion.compose.values.MotionTestValues
27 import platform.test.motion.golden.FeatureCapture
28 import platform.test.motion.golden.TimeSeriesCaptureScope
29 import platform.test.motion.golden.asDataPoint
30
31 /** Common, generic [FeatureCapture] implementations for Compose. */
32 object ComposeFeatureCaptures {
33 /** Size of a node in pixels. */
<lambda>null34 val size = FeatureCapture<SemanticsNode, IntSize>("size") { it.size.asDataPoint() }
35 /** Size of a node in DPs. */
36 val dpSize =
<lambda>null37 FeatureCapture<SemanticsNode, DpSize>("size") {
38 with(it.layoutInfo.density) { it.size.toSize().toDpSize().asDataPoint() }
39 }
40 /**
41 * The position of this node relative to the root of this Compose hierarchy, with no clipping
42 * applied.
43 */
44 val positionInRoot =
<lambda>null45 FeatureCapture<SemanticsNode, DpOffset>("position") {
46 with(it.layoutInfo.density) {
47 DpOffset(it.positionInRoot.x.toDp(), it.positionInRoot.y.toDp()).asDataPoint()
48 }
49 }
50
51 /**
52 * Captures the `alpha` value of a node.
53 *
54 * IMPORTANT: the alpha-value can only be captured if it has been exported in the production
55 * code, see [MotionTestValues.alpha]
56 */
57 val alpha =
<lambda>null58 FeatureCapture<SemanticsNode, Float>("alpha") {
59 it.config[MotionTestValues.alpha.semanticsPropertyKey].asDataPoint()
60 }
61 }
62
63 /**
64 * Captures the feature using [capture] from a node found via [matcher].
65 *
66 * If zero or more than one matching node is found, `DataPoint.notFound()` is recorded.
67 */
TimeSeriesCaptureScopenull68 fun TimeSeriesCaptureScope<SemanticsNodeInteractionsProvider>.feature(
69 matcher: SemanticsMatcher,
70 capture: FeatureCapture<SemanticsNode, *>,
71 name: String = capture.name,
72 ) {
73 on({
74 try {
75 it.onNode(matcher).fetchSemanticsNode()
76 } catch (e: AssertionError) {
77 null
78 }
79 }) {
80 feature(capture, name)
81 }
82 }
83