[go: nahoru, domu]

blob: 55bd392da598b0e265b7a97edbd045a29070c5bf [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
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000020import androidx.compose.emptyContent
Leland Richardsonfcf76b32020-05-13 16:58:59 -070021import androidx.compose.mutableStateOf
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010022import androidx.test.filters.MediumTest
Adam Powell999a89b2020-03-11 09:08:07 -070023import androidx.ui.core.LayoutCoordinates
24import androidx.ui.core.Modifier
George Mountd02af602020-03-06 16:41:40 -080025import androidx.ui.core.onPositioned
Filip Pavlis1d4d1b832020-05-27 14:45:15 +010026import androidx.ui.core.testTag
Matvei Malkov201726d2020-03-13 14:03:54 +000027import androidx.ui.foundation.Box
Matvei Malkov323b7452020-05-01 16:57:52 +010028import androidx.ui.foundation.clickable
Adam Powell999a89b2020-03-11 09:08:07 -070029import androidx.ui.layout.fillMaxSize
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010030import androidx.ui.test.createComposeRule
Jelle Fresen11fc7062020-01-13 16:53:55 +000031import androidx.ui.test.doGesture
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010032import androidx.ui.test.findByTag
Jelle Fresen11fc7062020-01-13 16:53:55 +000033import androidx.ui.test.globalBounds
Filip Pavlis6fdb2502020-04-02 14:41:32 +010034import androidx.ui.test.runOnIdleCompose
35import androidx.ui.test.runOnUiThread
Jelle Fresen11fc7062020-01-13 16:53:55 +000036import androidx.ui.test.sendClick
George Mount8baef7a2020-01-21 13:40:57 -080037import androidx.ui.unit.IntPx
38import androidx.ui.unit.IntPxSize
Nader Jawad6df06122020-06-03 15:27:08 -070039import androidx.ui.geometry.Offset
George Mount842c8c12020-01-08 16:03:42 -080040import androidx.ui.unit.dp
Ryan Mentley7865a632019-08-20 20:10:29 -070041import androidx.ui.unit.height
Ryan Mentley7865a632019-08-20 20:10:29 -070042import androidx.ui.unit.width
Filip Pavlise63b30c2020-01-09 16:21:07 +000043import com.google.common.truth.Truth.assertThat
Matvei Malkov886ec6a2020-02-03 01:45:29 +000044import org.junit.Ignore
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010045import org.junit.Rule
46import org.junit.Test
47import org.junit.runner.RunWith
48import org.junit.runners.JUnit4
Jelle Fresen4c566312020-01-16 10:32:40 +000049import java.util.concurrent.CountDownLatch
50import java.util.concurrent.TimeUnit
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010051import kotlin.math.roundToInt
52
53@MediumTest
54@RunWith(JUnit4::class)
55class DrawerTest {
56
57 @get:Rule
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010058 val composeTestRule = createComposeRule(disableTransitions = true)
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010059
60 @Test
61 fun modalDrawer_testOffset_whenOpened() {
Nader Jawad6df06122020-06-03 15:27:08 -070062 var position: Offset? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010063 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010064 ModalDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Adam Powell999a89b2020-03-11 09:08:07 -070065 Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -070066 position = coords.localToGlobal(Offset.Zero)
Matvei Malkov201726d2020-03-13 14:03:54 +000067 })
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000068 }, bodyContent = emptyContent())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010069 }
Filip Pavlis6fdb2502020-04-02 14:41:32 +010070 runOnIdleCompose {
Nader Jawade6a9b332020-05-21 13:49:20 -070071 assertThat(position!!.x).isEqualTo(0f)
Filip Pavlise63b30c2020-01-09 16:21:07 +000072 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010073 }
74
75 @Test
76 fun modalDrawer_testOffset_whenClosed() {
Nader Jawad6df06122020-06-03 15:27:08 -070077 var position: Offset? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010078 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010079 ModalDrawerLayout(DrawerState.Closed, {}, drawerContent = {
Adam Powell999a89b2020-03-11 09:08:07 -070080 Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -070081 position = coords.localToGlobal(Offset.Zero)
Matvei Malkov201726d2020-03-13 14:03:54 +000082 })
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000083 }, bodyContent = emptyContent())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010084 }
85 val width = composeTestRule.displayMetrics.widthPixels
Filip Pavlis6fdb2502020-04-02 14:41:32 +010086 runOnIdleCompose {
Nader Jawad16e330a2020-05-21 21:21:01 -070087 assertThat(position!!.x.roundToInt()).isEqualTo(-width)
Filip Pavlise63b30c2020-01-09 16:21:07 +000088 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010089 }
90
91 @Test
92 fun modalDrawer_testEndPadding_whenOpened() {
George Mount8baef7a2020-01-21 13:40:57 -080093 var size: IntPxSize? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +010094 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +010095 ModalDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Adam Powell999a89b2020-03-11 09:08:07 -070096 Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
97 size = coords.size
98 })
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +000099 }, bodyContent = emptyContent())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100100 }
101
102 val width = composeTestRule.displayMetrics.widthPixels
Filip Pavlise63b30c2020-01-09 16:21:07 +0000103 composeTestRule.runOnIdleComposeWithDensity {
George Mount8baef7a2020-01-21 13:40:57 -0800104 assertThat(size!!.width.value)
Nader Jawadfeb99f82020-05-21 13:07:36 -0700105 .isEqualTo(width - 56.dp.toPx().roundToInt())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100106 }
107 }
108
109 @Test
110 fun bottomDrawer_testOffset_whenOpened() {
Nader Jawad6df06122020-06-03 15:27:08 -0700111 var position: Offset? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100112 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100113 BottomDrawerLayout(DrawerState.Opened, {}, drawerContent = {
Adam Powell999a89b2020-03-11 09:08:07 -0700114 Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -0700115 position = coords.localToGlobal(Offset.Zero)
Matvei Malkov201726d2020-03-13 14:03:54 +0000116 })
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +0000117 }, bodyContent = emptyContent())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100118 }
Filip Pavlise63b30c2020-01-09 16:21:07 +0000119
Matvei Malkov2270be12019-07-08 16:59:45 +0100120 val width = composeTestRule.displayMetrics.widthPixels
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100121 val height = composeTestRule.displayMetrics.heightPixels
Matvei Malkov2270be12019-07-08 16:59:45 +0100122 // temporary calculation of landscape screen
Matvei Malkovb5e3d8a2020-03-09 15:17:20 +0000123 val expectedHeight = if (width > height) 0 else (height / 2f).roundToInt()
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100124 runOnIdleCompose {
Nader Jawad16e330a2020-05-21 21:21:01 -0700125 assertThat(position!!.y.roundToInt()).isEqualTo(expectedHeight)
Filip Pavlise63b30c2020-01-09 16:21:07 +0000126 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100127 }
128
129 @Test
130 fun bottomDrawer_testOffset_whenClosed() {
Nader Jawad6df06122020-06-03 15:27:08 -0700131 var position: Offset? = null
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100132 composeTestRule.setMaterialContent {
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100133 BottomDrawerLayout(DrawerState.Closed, {}, drawerContent = {
Adam Powell999a89b2020-03-11 09:08:07 -0700134 Box(Modifier.fillMaxSize().onPositioned { coords: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -0700135 position = coords.localToGlobal(Offset.Zero)
Matvei Malkov201726d2020-03-13 14:03:54 +0000136 })
Louis Pullen-Freiliche46bcf02020-02-12 16:06:21 +0000137 }, bodyContent = emptyContent())
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100138 }
139 val height = composeTestRule.displayMetrics.heightPixels
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100140 runOnIdleCompose {
Nader Jawad16e330a2020-05-21 21:21:01 -0700141 assertThat(position!!.y.roundToInt()).isEqualTo(height)
Filip Pavlise63b30c2020-01-09 16:21:07 +0000142 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100143 }
144
145 @Test
Matvei Malkov886ec6a2020-02-03 01:45:29 +0000146 @Ignore("failing in postsubmit, fix in b/148751721")
Jelle Fresen4c566312020-01-16 10:32:40 +0000147 fun modalDrawer_openAndClose() {
George Mount8baef7a2020-01-21 13:40:57 -0800148 var contentWidth: IntPx? = null
Jelle Fresen4c566312020-01-16 10:32:40 +0000149 var openedLatch: CountDownLatch? = null
150 var closedLatch: CountDownLatch? = CountDownLatch(1)
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700151 val drawerState = mutableStateOf(DrawerState.Closed)
Jelle Fresen4c566312020-01-16 10:32:40 +0000152 composeTestRule.setMaterialContent {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100153 ModalDrawerLayout(drawerState.value, { drawerState.value = it },
154 drawerContent = {
155 Box(
156 Modifier.fillMaxSize().onPositioned { info: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -0700157 val pos = info.localToGlobal(Offset.Zero)
Nader Jawade6a9b332020-05-21 13:49:20 -0700158 if (pos.x == 0.0f) {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100159 // If fully opened, mark the openedLatch if present
160 openedLatch?.countDown()
Nader Jawad16e330a2020-05-21 21:21:01 -0700161 } else if (-pos.x.roundToInt() == contentWidth?.value) {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100162 // If fully closed, mark the closedLatch if present
163 closedLatch?.countDown()
Matvei Malkov9f27abf2020-05-19 15:15:56 +0100164 }
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100165 }
166 )
167 },
168 bodyContent = {
169 Box(Modifier.fillMaxSize()
170 .onPositioned { contentWidth = it.size.width })
171 })
Jelle Fresen4c566312020-01-16 10:32:40 +0000172 }
173 // Drawer should start in closed state
174 assertThat(closedLatch!!.await(5, TimeUnit.SECONDS)).isTrue()
175
176 // When the drawer state is set to Opened
177 openedLatch = CountDownLatch(1)
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100178 runOnIdleCompose {
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700179 drawerState.value = DrawerState.Opened
Jelle Fresen4c566312020-01-16 10:32:40 +0000180 }
181 // Then the drawer should be opened
182 assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
183
184 // When the drawer state is set to Closed
185 closedLatch = CountDownLatch(1)
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100186 runOnIdleCompose {
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700187 drawerState.value = DrawerState.Closed
Jelle Fresen4c566312020-01-16 10:32:40 +0000188 }
189 // Then the drawer should be closed
190 assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
191 }
192
193 @Test
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100194 fun modalDrawer_bodyContent_clickable() {
195 var drawerClicks = 0
196 var bodyClicks = 0
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700197 val drawerState = mutableStateOf(DrawerState.Closed)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100198 composeTestRule.setMaterialContent {
Aurimas Liutikas7a828d32019-10-07 17:16:05 -0700199 // emulate click on the screen
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100200 ModalDrawerLayout(drawerState.value, { drawerState.value = it },
201 drawerContent = {
202 Box(
203 Modifier.fillMaxSize().clickable { drawerClicks += 1 },
204 children = emptyContent()
205 )
206 },
207 bodyContent = {
208 Box(
209 Modifier.testTag("Drawer").fillMaxSize().clickable { bodyClicks += 1 },
210 children = emptyContent()
211 )
212 })
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100213 }
214
Jelle Fresen11fc7062020-01-13 16:53:55 +0000215 // Click in the middle of the drawer (which is the middle of the body)
216 findByTag("Drawer").doGesture { sendClick() }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100217
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100218 runOnIdleCompose {
Filip Pavlise63b30c2020-01-09 16:21:07 +0000219 assertThat(drawerClicks).isEqualTo(0)
220 assertThat(bodyClicks).isEqualTo(1)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100221
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700222 drawerState.value = DrawerState.Opened
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100223 }
Jelle Fresen11fc7062020-01-13 16:53:55 +0000224 sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100225
Jelle Fresen11fc7062020-01-13 16:53:55 +0000226 // Click on the left-center pixel of the drawer
227 findByTag("Drawer").doGesture {
Nader Jawade6a9b332020-05-21 13:49:20 -0700228 val left = 1.0f
Nader Jawad63153c12020-05-21 14:17:08 -0700229 val centerY = (globalBounds.height / 2)
Nader Jawad6df06122020-06-03 15:27:08 -0700230 sendClick(Offset(left, centerY))
Jelle Fresen11fc7062020-01-13 16:53:55 +0000231 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100232
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100233 runOnIdleCompose {
Filip Pavlise63b30c2020-01-09 16:21:07 +0000234 assertThat(drawerClicks).isEqualTo(1)
235 assertThat(bodyClicks).isEqualTo(1)
Filip Pavlis2b161e42019-11-22 17:40:08 +0000236 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100237 }
238
239 @Test
Matvei Malkov886ec6a2020-02-03 01:45:29 +0000240 @Ignore("failing in postsubmit, fix in b/148751721")
Jelle Fresen4c566312020-01-16 10:32:40 +0000241 fun bottomDrawer_openAndClose() {
George Mount8baef7a2020-01-21 13:40:57 -0800242 var contentHeight: IntPx? = null
243 var openedHeight: IntPx? = null
Jelle Fresen4c566312020-01-16 10:32:40 +0000244 var openedLatch: CountDownLatch? = null
245 var closedLatch: CountDownLatch? = CountDownLatch(1)
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700246 val drawerState = mutableStateOf(DrawerState.Closed)
Jelle Fresen4c566312020-01-16 10:32:40 +0000247 composeTestRule.setMaterialContent {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100248 BottomDrawerLayout(drawerState.value, { drawerState.value = it },
249 drawerContent = {
250 Box(Modifier.fillMaxSize().onPositioned { info: LayoutCoordinates ->
Nader Jawad6df06122020-06-03 15:27:08 -0700251 val pos = info.localToGlobal(Offset.Zero)
Nader Jawad16e330a2020-05-21 21:21:01 -0700252 if (pos.y.roundToInt() == openedHeight?.value) {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100253 // If fully opened, mark the openedLatch if present
254 openedLatch?.countDown()
Nader Jawad16e330a2020-05-21 21:21:01 -0700255 } else if (pos.y.roundToInt() == contentHeight?.value) {
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100256 // If fully closed, mark the closedLatch if present
257 closedLatch?.countDown()
258 }
259 })
260 },
261 bodyContent = {
262 Box(Modifier.fillMaxSize().onPositioned {
263 contentHeight = it.size.height
264 openedHeight = it.size.height * BottomDrawerOpenFraction
265 })
266 }
267 )
Jelle Fresen4c566312020-01-16 10:32:40 +0000268 }
269 // Drawer should start in closed state
270 assertThat(closedLatch!!.await(5, TimeUnit.SECONDS)).isTrue()
271
272 // When the drawer state is set to Opened
273 openedLatch = CountDownLatch(1)
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100274 runOnIdleCompose {
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700275 drawerState.value = DrawerState.Opened
Jelle Fresen4c566312020-01-16 10:32:40 +0000276 }
277 // Then the drawer should be opened
278 assertThat(openedLatch.await(5, TimeUnit.SECONDS)).isTrue()
279
280 // When the drawer state is set to Closed
281 closedLatch = CountDownLatch(1)
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100282 runOnIdleCompose {
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700283 drawerState.value = DrawerState.Closed
Jelle Fresen4c566312020-01-16 10:32:40 +0000284 }
285 // Then the drawer should be closed
286 assertThat(closedLatch.await(5, TimeUnit.SECONDS)).isTrue()
287 }
288
289 @Test
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100290 fun bottomDrawer_bodyContent_clickable() {
291 var drawerClicks = 0
292 var bodyClicks = 0
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700293 val drawerState = mutableStateOf(DrawerState.Closed)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100294 composeTestRule.setMaterialContent {
Aurimas Liutikas7a828d32019-10-07 17:16:05 -0700295 // emulate click on the screen
Filip Pavlis1d4d1b832020-05-27 14:45:15 +0100296 BottomDrawerLayout(drawerState.value, { drawerState.value = it },
297 drawerContent = {
298 Box(
299 Modifier.fillMaxSize().clickable { drawerClicks += 1 },
300 children = emptyContent()
301 )
302 },
303 bodyContent = {
304 Box(
305 Modifier.testTag("Drawer").fillMaxSize().clickable { bodyClicks += 1 },
306 children = emptyContent()
307 )
308 })
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100309 }
310
Jelle Fresen11fc7062020-01-13 16:53:55 +0000311 // Click in the middle of the drawer (which is the middle of the body)
312 findByTag("Drawer").doGesture { sendClick() }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100313
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100314 runOnIdleCompose {
Filip Pavlise63b30c2020-01-09 16:21:07 +0000315 assertThat(drawerClicks).isEqualTo(0)
316 assertThat(bodyClicks).isEqualTo(1)
317 }
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100318
Filip Pavlis6fdb2502020-04-02 14:41:32 +0100319 runOnUiThread {
Leland Richardsonfcf76b32020-05-13 16:58:59 -0700320 drawerState.value = DrawerState.Opened
Jelle Fresen11fc7062020-01-13 16:53:55 +0000321 }
322 sleep(100) // TODO(147586311): remove this sleep when opening the drawer triggers a wait
323
324 // Click on the bottom-center pixel of the drawer
325 findByTag("Drawer").doGesture {
326 val bounds = globalBounds
Nader Jawad63153c12020-05-21 14:17:08 -0700327 val centerX = bounds.width / 2
328 val bottom = bounds.height - 1.0f
Nader Jawad6df06122020-06-03 15:27:08 -0700329 sendClick(Offset(centerX, bottom))
Jelle Fresen11fc7062020-01-13 16:53:55 +0000330 }
331
332 assertThat(drawerClicks).isEqualTo(1)
333 assertThat(bodyClicks).isEqualTo(1)
Matvei Malkov7aa7fd22019-08-16 16:52:59 +0100334 }
Matvei Malkov2d37cbd2019-07-04 15:15:20 +0100335}