1 /*
2  * Copyright (C) 2023 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 com.android.compose.animation.scene.transformation
18 
19 import android.platform.test.annotations.MotionTest
20 import androidx.compose.animation.core.LinearEasing
21 import androidx.compose.animation.core.tween
22 import androidx.compose.foundation.layout.Box
23 import androidx.compose.foundation.layout.size
24 import androidx.compose.runtime.Composable
25 import androidx.compose.ui.Modifier
26 import androidx.compose.ui.unit.dp
27 import androidx.test.ext.junit.runners.AndroidJUnit4
28 import com.android.compose.animation.scene.SceneScope
29 import com.android.compose.animation.scene.TestElements
30 import com.android.compose.animation.scene.TransitionBuilder
31 import com.android.compose.animation.scene.TransitionRecordingSpec
32 import com.android.compose.animation.scene.featureOfElement
33 import com.android.compose.animation.scene.recordTransition
34 import org.junit.Rule
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import platform.test.motion.compose.ComposeFeatureCaptures
38 import platform.test.motion.compose.createComposeMotionTestRule
39 import platform.test.motion.testing.createGoldenPathManager
40 
41 @RunWith(AndroidJUnit4::class)
42 @MotionTest
43 class AnchoredSizeTest {
44     private val goldenPaths =
45         createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
46 
47     @get:Rule val motionRule = createComposeMotionTestRule(goldenPaths)
48 
49     @Test
testAnchoredSizeEnternull50     fun testAnchoredSizeEnter() {
51         assertBarSizeMatchesGolden(
52             fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
53             toSceneContent = {
54                 Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
55                 Box(Modifier.size(200.dp, 60.dp).element(TestElements.Bar))
56             },
57             transition = {
58                 spec = tween(16 * 4, easing = LinearEasing)
59                 anchoredSize(TestElements.Bar, TestElements.Foo)
60             }
61         )
62     }
63 
64     @Test
testAnchoredSizeExitnull65     fun testAnchoredSizeExit() {
66         assertBarSizeMatchesGolden(
67             fromSceneContent = {
68                 Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo))
69                 Box(Modifier.size(100.dp, 100.dp).element(TestElements.Bar))
70             },
71             toSceneContent = { Box(Modifier.size(200.dp, 60.dp).element(TestElements.Foo)) },
72             transition = {
73                 // Scale during 4 frames.
74                 spec = tween(16 * 4, easing = LinearEasing)
75                 anchoredSize(TestElements.Bar, TestElements.Foo)
76             }
77         )
78     }
79 
80     @Test
testAnchoredWidthOnlynull81     fun testAnchoredWidthOnly() {
82         assertBarSizeMatchesGolden(
83             fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
84             toSceneContent = {
85                 Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
86                 Box(Modifier.size(200.dp, 60.dp).element(TestElements.Bar))
87             },
88             transition = {
89                 spec = tween(16 * 4, easing = LinearEasing)
90                 anchoredSize(TestElements.Bar, TestElements.Foo, anchorHeight = false)
91             },
92         )
93     }
94 
95     @Test
testAnchoredHeightOnlynull96     fun testAnchoredHeightOnly() {
97         assertBarSizeMatchesGolden(
98             fromSceneContent = { Box(Modifier.size(100.dp, 100.dp).element(TestElements.Foo)) },
99             toSceneContent = {
100                 Box(Modifier.size(50.dp, 50.dp).element(TestElements.Foo))
101                 Box(Modifier.size(200.dp, 60.dp).element(TestElements.Bar))
102             },
103             transition = {
104                 spec = tween(16 * 4, easing = LinearEasing)
105                 anchoredSize(TestElements.Bar, TestElements.Foo, anchorWidth = false)
106             }
107         )
108     }
109 
assertBarSizeMatchesGoldennull110     private fun assertBarSizeMatchesGolden(
111         fromSceneContent: @Composable SceneScope.() -> Unit,
112         toSceneContent: @Composable SceneScope.() -> Unit,
113         transition: TransitionBuilder.() -> Unit,
114     ) {
115         val recordingSpec =
116             TransitionRecordingSpec(recordAfter = true) {
117                 featureOfElement(TestElements.Bar, ComposeFeatureCaptures.dpSize)
118             }
119 
120         val motion =
121             motionRule.recordTransition(fromSceneContent, toSceneContent, transition, recordingSpec)
122 
123         motionRule.assertThat(motion).timeSeriesMatchesGolden()
124     }
125 }
126