[go: nahoru, domu]

blob: 6e37a8e6bbf4c633e7f7cb1131ac139c63c3bff3 [file] [log] [blame]
Andrey Kulikovb87ddf62020-03-31 17:27:27 +01001/*
2 * Copyright 2020 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
17package androidx.ui.core.test
18
Andrey Kulikovd1d483b2020-06-29 19:11:31 +010019import android.view.View
20import android.view.ViewGroup
21import android.widget.FrameLayout
22import android.widget.LinearLayout
23import android.widget.ScrollView
24import androidx.compose.Recomposer
Adam Powell5f07ae82020-03-30 14:36:42 -070025import androidx.compose.getValue
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010026import androidx.compose.mutableStateOf
Adam Powell5f07ae82020-03-30 14:36:42 -070027import androidx.compose.setValue
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010028import androidx.test.filters.SmallTest
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010029import androidx.ui.core.Layout
George Mount1cc5db92020-03-31 10:12:56 -070030import androidx.ui.core.LayoutCoordinates
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010031import androidx.ui.core.Modifier
George Mount1cc5db92020-03-31 10:12:56 -070032import androidx.ui.core.boundsInParent
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010033import androidx.ui.core.globalPosition
34import androidx.ui.core.onChildPositioned
35import androidx.ui.core.onPositioned
George Mount1cc5db92020-03-31 10:12:56 -070036import androidx.ui.core.positionInParent
Filip Pavlisa1dc2642020-07-15 19:23:33 +010037import androidx.ui.core.positionInRoot
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010038import androidx.ui.core.setContent
39import androidx.ui.framework.test.TestActivity
George Mount1cc5db92020-03-31 10:12:56 -070040import androidx.ui.unit.PxBounds
Nader Jawad6df06122020-06-03 15:27:08 -070041import androidx.ui.geometry.Offset
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010042import org.junit.Assert.assertEquals
43import org.junit.Assert.assertFalse
44import org.junit.Assert.assertTrue
45import org.junit.Before
46import org.junit.Rule
47import org.junit.Test
48import org.junit.runner.RunWith
49import org.junit.runners.JUnit4
50import java.util.concurrent.CountDownLatch
51import java.util.concurrent.TimeUnit
52
53@SmallTest
54@RunWith(JUnit4::class)
55class OnPositionedTest {
56
Aurimas Liutikas506ab64d2020-06-02 14:37:26 -070057 @Suppress("DEPRECATION")
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010058 @get:Rule
Aurimas Liutikas506ab64d2020-06-02 14:37:26 -070059 val rule = androidx.test.rule.ActivityTestRule<TestActivity>(TestActivity::class.java)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010060 private lateinit var activity: TestActivity
61
62 @Before
63 fun setup() {
64 activity = rule.activity
65 activity.hasFocusLatch.await(5, TimeUnit.SECONDS)
66 }
67
68 @Test
69 fun handlesChildrenNodeMoveCorrectly() {
George Mount8f237572020-04-30 12:08:30 -070070 val size = 50
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010071 var index by mutableStateOf(0)
72 var latch = CountDownLatch(2)
Nader Jawad63153c12020-05-21 14:17:08 -070073 var wrap1Position = 0f
74 var wrap2Position = 0f
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010075 rule.runOnUiThread {
Andrey Kulikov1526ea52020-04-07 18:43:27 +010076 activity.setContent {
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010077 SimpleRow {
78 for (i in 0 until 2) {
79 if (index == i) {
80 Wrap(
81 minWidth = size,
82 minHeight = size,
83 modifier = Modifier.onPositioned { coordinates ->
Nader Jawad63153c12020-05-21 14:17:08 -070084 wrap1Position = coordinates.globalPosition.x
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010085 latch.countDown()
86 }
87 )
88 } else {
89 Wrap(
90 minWidth = size,
91 minHeight = size,
92 modifier = Modifier.onPositioned { coordinates ->
Nader Jawad63153c12020-05-21 14:17:08 -070093 wrap2Position = coordinates.globalPosition.x
Andrey Kulikovb87ddf62020-03-31 17:27:27 +010094 latch.countDown()
95 }
96 )
97 }
98 }
99 }
100 }
101 }
102 assertTrue(latch.await(1, TimeUnit.SECONDS))
Nader Jawad63153c12020-05-21 14:17:08 -0700103 assertEquals(0f, wrap1Position)
George Mount8f237572020-04-30 12:08:30 -0700104 assertEquals(size.toFloat(), wrap2Position)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100105 latch = CountDownLatch(2)
106 rule.runOnUiThread {
107 index = 1
108 }
109 assertTrue(latch.await(1, TimeUnit.SECONDS))
George Mount8f237572020-04-30 12:08:30 -0700110 assertEquals(size.toFloat(), wrap1Position)
Nader Jawad63153c12020-05-21 14:17:08 -0700111 assertEquals(0f, wrap2Position)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100112 }
113
114 @Test
115 fun callbacksAreCalledWhenChildResized() {
George Mount8f237572020-04-30 12:08:30 -0700116 var size by mutableStateOf(10)
117 var realSize = 0
118 var realChildSize = 0
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100119 var latch = CountDownLatch(1)
120 var childLatch = CountDownLatch(1)
121 rule.runOnUiThreadIR {
122 activity.setContent {
George Mount8f237572020-04-30 12:08:30 -0700123 AtLeastSize(size = 20, modifier = Modifier.onChildPositioned {
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100124 realSize = it.size.width
125 latch.countDown()
126 }) {
127 Wrap(minWidth = size, minHeight = size, modifier = Modifier.onPositioned {
128 realChildSize = it.size.width
129 childLatch.countDown()
130 })
131 }
132 }
133 }
134
135 assertTrue(latch.await(1, TimeUnit.SECONDS))
136 assertTrue(childLatch.await(1, TimeUnit.SECONDS))
George Mount8f237572020-04-30 12:08:30 -0700137 assertEquals(10, realSize)
138 assertEquals(10, realChildSize)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100139
140 latch = CountDownLatch(1)
141 childLatch = CountDownLatch(1)
142 rule.runOnUiThread {
George Mount8f237572020-04-30 12:08:30 -0700143 size = 15
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100144 }
145
146 assertTrue(latch.await(1, TimeUnit.SECONDS))
147 assertTrue(childLatch.await(1, TimeUnit.SECONDS))
George Mount8f237572020-04-30 12:08:30 -0700148 assertEquals(15, realSize)
149 assertEquals(15, realChildSize)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100150 }
151
152 @Test
153 fun callbackCalledForChildWhenParentMoved() {
George Mount8f237572020-04-30 12:08:30 -0700154 var position by mutableStateOf(0)
Nader Jawad6df06122020-06-03 15:27:08 -0700155 var childGlobalPosition = Offset(0f, 0f)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100156 var latch = CountDownLatch(1)
157 rule.runOnUiThreadIR {
Andrey Kulikov1526ea52020-04-07 18:43:27 +0100158 activity.setContent {
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100159 Layout(
Anastasia Soboleva5e382dd2020-06-17 21:51:38 +0100160 measureBlock = { measurables, constraints ->
George Mount8f237572020-04-30 12:08:30 -0700161 layout(10, 10) {
162 measurables[0].measure(constraints).place(position, 0)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100163 }
164 },
165 children = {
166 Wrap(
George Mount8f237572020-04-30 12:08:30 -0700167 minWidth = 10,
168 minHeight = 10
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100169 ) {
170 Wrap(
George Mount8f237572020-04-30 12:08:30 -0700171 minWidth = 10,
172 minHeight = 10,
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100173 modifier = Modifier.onPositioned { coordinates ->
Filip Pavlisa1dc2642020-07-15 19:23:33 +0100174 childGlobalPosition = coordinates.positionInRoot
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100175 latch.countDown()
176 }
177 )
178 }
179 }
180 )
181 }
182 }
183
184 assertTrue(latch.await(1, TimeUnit.SECONDS))
185
186 latch = CountDownLatch(1)
187 rule.runOnUiThread {
George Mount8f237572020-04-30 12:08:30 -0700188 position = 10
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100189 }
190
191 assertTrue(latch.await(1, TimeUnit.SECONDS))
Nader Jawad6df06122020-06-03 15:27:08 -0700192 assertEquals(Offset(10f, 0f), childGlobalPosition)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100193 }
194
195 @Test
196 fun callbacksAreCalledOnlyForPositionedChildren() {
197 val latch = CountDownLatch(1)
198 var wrap1OnPositionedCalled = false
199 var wrap2OnPositionedCalled = false
200 var onChildPositionedCalledTimes = 0
201 rule.runOnUiThread {
Andrey Kulikov1526ea52020-04-07 18:43:27 +0100202 activity.setContent {
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100203 Layout(
204 modifier = Modifier.onChildPositioned {
205 onChildPositionedCalledTimes++
206 },
Anastasia Soboleva5e382dd2020-06-17 21:51:38 +0100207 measureBlock = { measurables, constraints ->
George Mount8f237572020-04-30 12:08:30 -0700208 layout(10, 10) {
209 measurables[1].measure(constraints).place(0, 0)
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100210 }
211 },
212 children = {
213 Wrap(
George Mount8f237572020-04-30 12:08:30 -0700214 minWidth = 10,
215 minHeight = 10,
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100216 modifier = Modifier.onPositioned {
217 wrap1OnPositionedCalled = true
218 }
219 )
220 Wrap(
George Mount8f237572020-04-30 12:08:30 -0700221 minWidth = 10,
222 minHeight = 10,
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100223 modifier = Modifier.onPositioned {
224 wrap2OnPositionedCalled = true
225 }
226 ) {
227 Wrap(
George Mount8f237572020-04-30 12:08:30 -0700228 minWidth = 10,
229 minHeight = 10,
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100230 modifier = Modifier.onPositioned {
231 latch.countDown()
232 }
233 )
234 }
235 }
236 )
237 }
238 }
239
240 assertTrue(latch.await(1, TimeUnit.SECONDS))
241 assertFalse(wrap1OnPositionedCalled)
242 assertTrue(wrap2OnPositionedCalled)
243 assertEquals(1, onChildPositionedCalledTimes)
244 }
George Mount1cc5db92020-03-31 10:12:56 -0700245
246 @Test
247 fun testPositionInParent() {
248 val positionedLatch = CountDownLatch(1)
249 var coordinates: LayoutCoordinates? = null
250
251 rule.runOnUiThread {
Andrey Kulikov1526ea52020-04-07 18:43:27 +0100252 activity.setContent {
George Mount8f237572020-04-30 12:08:30 -0700253 FixedSize(10,
254 PaddingModifier(5) +
George Mount1cc5db92020-03-31 10:12:56 -0700255 Modifier.onPositioned {
256 coordinates = it
257 positionedLatch.countDown()
258 }
259 ) {
260 }
261 }
262 }
263 assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
264
265 rule.runOnUiThread {
Nader Jawad6df06122020-06-03 15:27:08 -0700266 assertEquals(Offset(5f, 5f), coordinates!!.positionInParent)
George Mount1cc5db92020-03-31 10:12:56 -0700267
268 var root = coordinates!!
269 while (root.parentCoordinates != null) {
270 root = root.parentCoordinates!!
271 }
272
Nader Jawad6df06122020-06-03 15:27:08 -0700273 assertEquals(Offset.Zero, root.positionInParent)
George Mount1cc5db92020-03-31 10:12:56 -0700274 }
275 }
276
277 @Test
278 fun testBoundsInParent() {
279 val positionedLatch = CountDownLatch(1)
280 var coordinates: LayoutCoordinates? = null
281
282 rule.runOnUiThread {
Andrey Kulikov1526ea52020-04-07 18:43:27 +0100283 activity.setContent {
George Mount8f237572020-04-30 12:08:30 -0700284 FixedSize(10,
285 PaddingModifier(5) +
George Mount1cc5db92020-03-31 10:12:56 -0700286 Modifier.onPositioned {
287 coordinates = it
288 positionedLatch.countDown()
289 }
290 ) {
291 }
292 }
293 }
294 assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
295
296 rule.runOnUiThread {
Nader Jawad63153c12020-05-21 14:17:08 -0700297 assertEquals(PxBounds(5f, 5f, 15f, 15f), coordinates!!.boundsInParent)
George Mount1cc5db92020-03-31 10:12:56 -0700298
299 var root = coordinates!!
300 while (root.parentCoordinates != null) {
301 root = root.parentCoordinates!!
302 }
303
Nader Jawad63153c12020-05-21 14:17:08 -0700304 assertEquals(PxBounds(0f, 0f, 20f, 20f), root.boundsInParent)
George Mount1cc5db92020-03-31 10:12:56 -0700305 }
306 }
Andrey Kulikovd1d483b2020-06-29 19:11:31 +0100307
308 @Test
309 fun onPositionedIsCalledWhenComposeContainerIsScrolled() {
310 var positionedLatch = CountDownLatch(1)
311 var coordinates: LayoutCoordinates? = null
312 var scrollView: ScrollView? = null
313
314 rule.runOnUiThread {
315 scrollView = ScrollView(rule.activity)
316 activity.setContentView(scrollView, ViewGroup.LayoutParams(100, 100))
317 val frameLayout = FrameLayout(rule.activity)
318 scrollView!!.addView(frameLayout)
319 frameLayout.setContent(Recomposer.current()) {
320 Layout({}, modifier = Modifier.onPositioned {
321 coordinates = it
322 positionedLatch.countDown()
323 }) { _, _ ->
324 layout(100, 200) {}
325 }
326 }
327 }
328 assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
329 val startY = coordinates!!.globalPosition.y
330 positionedLatch = CountDownLatch(1)
331
332 rule.runOnUiThread {
333 scrollView!!.scrollBy(0, 50)
334 }
335
336 assertTrue(
337 "OnPositioned is not called when the container scrolled",
338 positionedLatch.await(1, TimeUnit.SECONDS)
339 )
340 assertEquals(startY - 50f, coordinates!!.globalPosition.y)
341 }
342
343 @Test
344 fun onPositionedIsCalledWhenComposeContainerPositionChanged() {
345 var positionedLatch = CountDownLatch(1)
346 var coordinates: LayoutCoordinates? = null
347 var topView: View? = null
348
349 rule.runOnUiThread {
350 val linearLayout = LinearLayout(rule.activity)
351 linearLayout.orientation = LinearLayout.VERTICAL
352 activity.setContentView(linearLayout, ViewGroup.LayoutParams(100, 200))
353 topView = View(rule.activity)
354 linearLayout.addView(topView!!, ViewGroup.LayoutParams(100, 100))
355 val frameLayout = FrameLayout(rule.activity)
356 linearLayout.addView(frameLayout, ViewGroup.LayoutParams(100, 100))
357 frameLayout.setContent(Recomposer.current()) {
358 Layout({}, modifier = Modifier.onPositioned {
359 coordinates = it
360 positionedLatch.countDown()
361 }) { _, constraints ->
362 layout(constraints.maxWidth, constraints.maxHeight) {}
363 }
364 }
365 }
366 assertTrue(positionedLatch.await(1, TimeUnit.SECONDS))
367 val startY = coordinates!!.globalPosition.y
368 positionedLatch = CountDownLatch(1)
369
370 rule.runOnUiThread {
371 topView!!.visibility = View.GONE
372 }
373
374 assertTrue("OnPositioned is not called when the container moved",
375 positionedLatch.await(1, TimeUnit.SECONDS))
376 assertEquals(startY - 100f, coordinates!!.globalPosition.y)
377 }
Andrey Kulikovb87ddf62020-03-31 17:27:27 +0100378}