[go: nahoru, domu]

blob: 56b6eb954ce98b84ea39e266f88e832a1ce8349c [file] [log] [blame]
Matvei Malkov2d37cbd2019-07-04 15:15:20 +01001/*
2 * Copyright 2019 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.material
18
Jelle Fresen11fc7062020-01-13 16:53:55 +000019import android.os.SystemClock.sleep
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010020import androidx.compose.Model
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010021import androidx.test.filters.MediumTest
Jelle Fresen4c566312020-01-16 10:32:40 +000022import androidx.ui.core.OnChildPositioned
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010023import androidx.ui.core.OnPositioned
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010024import androidx.ui.core.TestTag
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010025import androidx.ui.foundation.Clickable
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010026import androidx.ui.layout.Container
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010027import androidx.ui.semantics.Semantics
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010028import androidx.ui.test.createComposeRule
Jelle Fresen11fc7062020-01-13 16:53:55 +000029import androidx.ui.test.doGesture
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010030import androidx.ui.test.findByTag
Jelle Fresen11fc7062020-01-13 16:53:55 +000031import androidx.ui.test.globalBounds
32import androidx.ui.test.sendClick
George Mount8baef7a2020-01-21 13:40:57 -080033import androidx.ui.unit.IntPx
34import androidx.ui.unit.IntPxSize
George Mount842c8c12020-01-08 16:03:42 -080035import androidx.ui.unit.PxPosition
George Mount842c8c12020-01-08 16:03:42 -080036import androidx.ui.unit.dp
Ryan Mentley7865a632019-08-20 20:10:29 -070037import androidx.ui.unit.height
Jelle Fresen11fc7062020-01-13 16:53:55 +000038import androidx.ui.unit.px
George Mount842c8c12020-01-08 16:03:42 -080039import androidx.ui.unit.round
Ryan Mentley7865a632019-08-20 20:10:29 -070040import androidx.ui.unit.width
Filip Pavlise63b30c2020-01-09 16:21:07 +000041import com.google.common.truth.Truth.assertThat
Matvei Malkov886ec6a2020-02-03 01:45:29 +000042import org.junit.Ignore
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010043import org.junit.Rule
44import org.junit.Test
45import org.junit.runner.RunWith
46import org.junit.runners.JUnit4
Jelle Fresen4c566312020-01-16 10:32:40 +000047import java.util.concurrent.CountDownLatch
48import java.util.concurrent.TimeUnit
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010049import kotlin.math.roundToInt
50
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010051@Model
52data class DrawerStateHolder(var state: DrawerState)
53
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010054@MediumTest
55@RunWith(JUnit4::class)
56class DrawerTest {
57
58 @get:Rule
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010059 val composeTestRule = createComposeRule(disableTransitions = true)
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010060
61 @Test
62 fun modalDrawer_testOffset_whenOpened() {
63 var position: PxPosition? = null
64 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010065 ModalDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010066 Container(expanded = true) {
67 OnPositioned { coords ->
68 position = coords.localToGlobal(PxPosition.Origin)
69 }
70 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010071 }) {}
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010072 }
Filip Pavlise63b30c2020-01-09 16:21:07 +000073 composeTestRule.runOnIdleCompose {
74 assertThat(position!!.x.value).isEqualTo(0f)
75 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010076 }
77
78 @Test
79 fun modalDrawer_testOffset_whenClosed() {
80 var position: PxPosition? = null
81 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010082 ModalDrawerLayout(DrawerState.Closed, {}, drawerContent = {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010083 Container(expanded = true) {
84 OnPositioned { coords ->
85 position = coords.localToGlobal(PxPosition.Origin)
86 }
87 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010088 }) {}
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010089 }
90 val width = composeTestRule.displayMetrics.widthPixels
Filip Pavlise63b30c2020-01-09 16:21:07 +000091 composeTestRule.runOnIdleCompose {
92 assertThat(position!!.x.round().value).isEqualTo(-width)
93 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010094 }
95
96 @Test
97 fun modalDrawer_testEndPadding_whenOpened() {
George Mount8baef7a2020-01-21 13:40:57 -080098 var size: IntPxSize? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010099 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100100 ModalDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100101 Container(expanded = true) {
102 OnPositioned { coords ->
103 size = coords.size
104 }
105 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100106 }) {}
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100107 }
108
109 val width = composeTestRule.displayMetrics.widthPixels
Filip Pavlise63b30c2020-01-09 16:21:07 +0000110 composeTestRule.runOnIdleComposeWithDensity {
George Mount8baef7a2020-01-21 13:40:57 -0800111 assertThat(size!!.width.value)
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100112 .isEqualTo(width - 56.dp.toPx().round().value)
113 }
114 }
115
116 @Test
117 fun bottomDrawer_testOffset_whenOpened() {
118 var position: PxPosition? = null
119 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100120 BottomDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100121 Container(expanded = true) {
122 OnPositioned { coords ->
123 position = coords.localToGlobal(PxPosition.Origin)
124 }
125 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100126 }) {}
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100127 }
Filip Pavlise63b30c2020-01-09 16:21:07 +0000128
Matvei Malkov2270be12019-07-08 16:59:45 +0100129 val width = composeTestRule.displayMetrics.widthPixels
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100130 val height = composeTestRule.displayMetrics.heightPixels
Matvei Malkov2270be12019-07-08 16:59:45 +0100131 // temporary calculation of landscape screen
132 val expectedHeight = if (width > height) height else (height / 2f).roundToInt()
Filip Pavlise63b30c2020-01-09 16:21:07 +0000133 composeTestRule.runOnIdleCompose {
134 assertThat(position!!.y.round().value).isEqualTo(expectedHeight)
135 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100136 }
137
138 @Test
139 fun bottomDrawer_testOffset_whenClosed() {
140 var position: PxPosition? = null
141 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100142 BottomDrawerLayout(DrawerState.Closed, {}, drawerContent = {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100143 Container(expanded = true) {
144 OnPositioned { coords ->
145 position = coords.localToGlobal(PxPosition.Origin)
146 }
147 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100148 }) {}
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100149 }
150 val height = composeTestRule.displayMetrics.heightPixels
Filip Pavlise63b30c2020-01-09 16:21:07 +0000151 composeTestRule.runOnIdleCompose {
152 assertThat(position!!.y.round().value).isEqualTo(height)
153 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100154 }
155
156 @Test
157 fun staticDrawer_testWidth_whenOpened() {
158 composeTestRule
Matvei Malkov804bee42019-07-16 16:24:06 +0100159 .setMaterialContentAndCollectSizes {
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100160 StaticDrawer {
161 Container(expanded = true) {}
162 }
163 }
164 .assertWidthEqualsTo(256.dp)
165 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100166
167 @Test
Matvei Malkov886ec6a2020-02-03 01:45:29 +0000168 @Ignore("failing in postsubmit, fix in b/148751721")
Jelle Fresen4c566312020-01-16 10:32:40 +0000169 fun modalDrawer_openAndClose() {
George Mount8baef7a2020-01-21 13:40:57 -0800170 var contentWidth: IntPx? = null
Jelle Fresen4c566312020-01-16 10:32:40 +0000171 var openedLatch: CountDownLatch? = null
172 var closedLatch: CountDownLatch? = CountDownLatch(1)
173 val drawerState = DrawerStateHolder(DrawerState.Closed)
174 composeTestRule.setMaterialContent {
175 TestTag("Drawer") {
176 Semantics(container = true) {
177 ModalDrawerLayout(drawerState.state, { drawerState.state = it },
178 drawerContent = {
179 OnChildPositioned({ info ->
George Mount8baef7a2020-01-21 13:40:57 -0800180 val pos = info.localToGlobal(PxPosition.Origin)
Jelle Fresen4c566312020-01-16 10:32:40 +0000181 if (pos.x == 0.px) {
182 // If fully opened, mark the openedLatch if present
183 openedLatch?.countDown()
George Mount8baef7a2020-01-21 13:40:57 -0800184 } else if (-pos.x.round() == contentWidth) {
Jelle Fresen4c566312020-01-16 10:32:40 +0000185 // If fully closed, mark the closedLatch if present
186 closedLatch?.countDown()
187 }
188 }) {
189 Container(expanded = true) {}
190 }
191 },
192 bodyContent = {
193 OnChildPositioned({ contentWidth = it.size.width }) {
194 Container(expanded = true) {}
195 }
196 })
197 }
198 }
199 }
200 // Drawer should start in closed state
201 assertThat(closedLatch!!.await(5, TimeUnit.SECONDS)).isTrue()
202
203 // When the drawer state is set to Opened
204 openedLatch = CountDownLatch(1)
205 composeTestRule.runOnIdleCompose {
206 drawerState.state = DrawerState.Opened
207 }
208 // Then the drawer should be opened
209 assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
210
211 // When the drawer state is set to Closed
212 closedLatch = CountDownLatch(1)
213 composeTestRule.runOnIdleCompose {
214 drawerState.state = DrawerState.Closed
215 }
216 // Then the drawer should be closed
217 assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
218 }
219
220 @Test
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100221 fun modalDrawer_bodyContent_clickable() {
222 var drawerClicks = 0
223 var bodyClicks = 0
224 val drawerState = DrawerStateHolder(DrawerState.Closed)
225 composeTestRule.setMaterialContent {
Aurimas Liutikas7a828d32019-10-07 17:16:05 -0700226 // emulate click on the screen
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100227 TestTag("Drawer") {
228 Semantics(container = true) {
229 ModalDrawerLayout(drawerState.state, { drawerState.state = it },
230 drawerContent = {
231 Clickable(onClick = { drawerClicks += 1 }) {
232 Container(expanded = true) {}
233 }
234 },
235 bodyContent = {
236 Clickable(onClick = { bodyClicks += 1 }) {
237 Container(expanded = true) {}
238 }
239 })
240 }
241 }
242 }
243
Jelle Fresen11fc7062020-01-13 16:53:55 +0000244 // Click in the middle of the drawer (which is the middle of the body)
245 findByTag("Drawer").doGesture { sendClick() }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100246
Filip Pavlis2b161e42019-11-22 17:40:08 +0000247 composeTestRule.runOnIdleCompose {
Filip Pavlise63b30c2020-01-09 16:21:07 +0000248 assertThat(drawerClicks).isEqualTo(0)
249 assertThat(bodyClicks).isEqualTo(1)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100250
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100251 drawerState.state = DrawerState.Opened
252 }
Jelle Fresen11fc7062020-01-13 16:53:55 +0000253 sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100254
Jelle Fresen11fc7062020-01-13 16:53:55 +0000255 // Click on the left-center pixel of the drawer
256 findByTag("Drawer").doGesture {
Ryan Mentley7865a632019-08-20 20:10:29 -0700257 val left = 1.px
Jelle Fresen11fc7062020-01-13 16:53:55 +0000258 val centerY = globalBounds.height / 2
Ryan Mentley7865a632019-08-20 20:10:29 -0700259 sendClick(PxPosition(left, centerY))
Jelle Fresen11fc7062020-01-13 16:53:55 +0000260 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100261
Filip Pavlis2b161e42019-11-22 17:40:08 +0000262 composeTestRule.runOnIdleCompose {
Filip Pavlise63b30c2020-01-09 16:21:07 +0000263 assertThat(drawerClicks).isEqualTo(1)
264 assertThat(bodyClicks).isEqualTo(1)
Filip Pavlis2b161e42019-11-22 17:40:08 +0000265 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100266 }
267
268 @Test
Matvei Malkov886ec6a2020-02-03 01:45:29 +0000269 @Ignore("failing in postsubmit, fix in b/148751721")
Jelle Fresen4c566312020-01-16 10:32:40 +0000270 fun bottomDrawer_openAndClose() {
George Mount8baef7a2020-01-21 13:40:57 -0800271 var contentHeight: IntPx? = null
272 var openedHeight: IntPx? = null
Jelle Fresen4c566312020-01-16 10:32:40 +0000273 var openedLatch: CountDownLatch? = null
274 var closedLatch: CountDownLatch? = CountDownLatch(1)
275 val drawerState = DrawerStateHolder(DrawerState.Closed)
276 composeTestRule.setMaterialContent {
277 TestTag("Drawer") {
278 Semantics(container = true) {
279 BottomDrawerLayout(drawerState.state, { drawerState.state = it },
280 drawerContent = {
281 OnChildPositioned({ info ->
George Mount8baef7a2020-01-21 13:40:57 -0800282 val pos = info.localToGlobal(PxPosition.Origin)
283 if (pos.y.round() == openedHeight) {
Jelle Fresen4c566312020-01-16 10:32:40 +0000284 // If fully opened, mark the openedLatch if present
285 openedLatch?.countDown()
George Mount8baef7a2020-01-21 13:40:57 -0800286 } else if (pos.y.round() == contentHeight) {
Jelle Fresen4c566312020-01-16 10:32:40 +0000287 // If fully closed, mark the closedLatch if present
288 closedLatch?.countDown()
289 }
290 }) {
291 Container(expanded = true) {}
292 }
293 },
294 bodyContent = {
295 OnChildPositioned({
296 contentHeight = it.size.height
297 openedHeight = it.size.height * BottomDrawerOpenFraction
298 }) {
299 Container(expanded = true) {}
300 }
301 })
302 }
303 }
304 }
305 // Drawer should start in closed state
306 assertThat(closedLatch!!.await(5, TimeUnit.SECONDS)).isTrue()
307
308 // When the drawer state is set to Opened
309 openedLatch = CountDownLatch(1)
310 composeTestRule.runOnIdleCompose {
311 drawerState.state = DrawerState.Opened
312 }
313 // Then the drawer should be opened
314 assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
315
316 // When the drawer state is set to Closed
317 closedLatch = CountDownLatch(1)
318 composeTestRule.runOnIdleCompose {
319 drawerState.state = DrawerState.Closed
320 }
321 // Then the drawer should be closed
322 assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
323 }
324
325 @Test
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100326 fun bottomDrawer_bodyContent_clickable() {
327 var drawerClicks = 0
328 var bodyClicks = 0
329 val drawerState = DrawerStateHolder(DrawerState.Closed)
330 composeTestRule.setMaterialContent {
Aurimas Liutikas7a828d32019-10-07 17:16:05 -0700331 // emulate click on the screen
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100332 TestTag("Drawer") {
333 Semantics(container = true) {
334 BottomDrawerLayout(drawerState.state, { drawerState.state = it },
335 drawerContent = {
336 Clickable(onClick = { drawerClicks += 1 }) {
337 Container(expanded = true) {}
338 }
339 },
340 bodyContent = {
341 Clickable(onClick = { bodyClicks += 1 }) {
342 Container(expanded = true) {}
343 }
344 })
345 }
346 }
347 }
348
Jelle Fresen11fc7062020-01-13 16:53:55 +0000349 // Click in the middle of the drawer (which is the middle of the body)
350 findByTag("Drawer").doGesture { sendClick() }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100351
Filip Pavlise63b30c2020-01-09 16:21:07 +0000352 composeTestRule.runOnIdleCompose {
353 assertThat(drawerClicks).isEqualTo(0)
354 assertThat(bodyClicks).isEqualTo(1)
355 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100356
Jelle Fresen11fc7062020-01-13 16:53:55 +0000357 composeTestRule.runOnUiThread {
358 drawerState.state = DrawerState.Opened
359 }
360 sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
361
362 // Click on the bottom-center pixel of the drawer
363 findByTag("Drawer").doGesture {
364 val bounds = globalBounds
365 val centerX = bounds.width / 2
Ryan Mentley7865a632019-08-20 20:10:29 -0700366 val bottom = bounds.height - 1.px
367 sendClick(PxPosition(centerX, bottom))
Jelle Fresen11fc7062020-01-13 16:53:55 +0000368 }
369
370 assertThat(drawerClicks).isEqualTo(1)
371 assertThat(bodyClicks).isEqualTo(1)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100372 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100373}