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 com.android.systemui.communal.ui.viewmodel 18 19 import androidx.compose.foundation.gestures.DraggableAnchors 20 import androidx.compose.runtime.snapshots.Snapshot 21 import androidx.test.ext.junit.runners.AndroidJUnit4 22 import androidx.test.filters.SmallTest 23 import com.android.systemui.SysuiTestCase 24 import com.android.systemui.coroutines.collectLastValue 25 import com.android.systemui.kosmos.testScope 26 import com.android.systemui.lifecycle.activateIn 27 import com.android.systemui.testKosmos 28 import com.google.common.truth.Truth.assertThat 29 import kotlinx.coroutines.test.TestScope 30 import kotlinx.coroutines.test.runCurrent 31 import kotlinx.coroutines.test.runTest 32 import org.junit.Before 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 36 @SmallTest 37 @RunWith(AndroidJUnit4::class) 38 class ResizeableItemFrameViewModelTest : SysuiTestCase() { 39 private val kosmos = testKosmos() 40 private val testScope = kosmos.testScope 41 private val underTest = kosmos.resizeableItemFrameViewModel 42 43 /** Total viewport height of the entire grid */ 44 private val viewportHeightPx = 100 45 /** Total amount of vertical padding around the viewport */ 46 private val verticalContentPaddingPx = 20f 47 48 private val singleSpanGrid = 49 GridLayout( 50 verticalItemSpacingPx = 10f, 51 verticalContentPaddingPx = verticalContentPaddingPx, 52 viewportHeightPx = viewportHeightPx, 53 currentRow = 0, 54 currentSpan = 1, 55 maxHeightPx = Int.MAX_VALUE, 56 minHeightPx = 0, 57 resizeMultiple = 1, 58 totalSpans = 1, 59 ) 60 61 @Before setUpnull62 fun setUp() { 63 underTest.activateIn(testScope) 64 } 65 66 @Test testDefaultStatenull67 fun testDefaultState() { 68 val topState = underTest.topDragState 69 assertThat(topState.currentValue).isEqualTo(0) 70 assertThat(topState.offset).isEqualTo(0f) 71 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 72 73 val bottomState = underTest.bottomDragState 74 assertThat(bottomState.currentValue).isEqualTo(0) 75 assertThat(bottomState.offset).isEqualTo(0f) 76 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 77 } 78 79 @Test testSingleSpanGridnull80 fun testSingleSpanGrid() = 81 testScope.runTest { 82 updateGridLayout(singleSpanGrid) 83 84 val topState = underTest.topDragState 85 assertThat(topState.currentValue).isEqualTo(0) 86 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 87 88 val bottomState = underTest.bottomDragState 89 assertThat(bottomState.currentValue).isEqualTo(0) 90 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 91 } 92 93 /** 94 * Verifies element in first row which is already at the minimum size can only be expanded 95 * downwards. 96 */ 97 @Test testTwoSpanGrid_elementInFirstRow_sizeSingleSpannull98 fun testTwoSpanGrid_elementInFirstRow_sizeSingleSpan() = 99 testScope.runTest { 100 updateGridLayout(singleSpanGrid.copy(currentRow = 0, totalSpans = 2)) 101 val topState = underTest.topDragState 102 assertThat(topState.currentValue).isEqualTo(0) 103 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 104 105 val bottomState = underTest.bottomDragState 106 assertThat(bottomState.currentValue).isEqualTo(0) 107 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 45f) 108 } 109 110 /** 111 * Verifies element in second row which is already at the minimum size can only be expanded 112 * upwards. 113 */ 114 @Test testTwoSpanGrid_elementInSecondRow_sizeSingleSpannull115 fun testTwoSpanGrid_elementInSecondRow_sizeSingleSpan() = 116 testScope.runTest { 117 updateGridLayout(singleSpanGrid.copy(currentRow = 1, totalSpans = 2)) 118 val topState = underTest.topDragState 119 assertThat(topState.currentValue).isEqualTo(0) 120 assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -45f) 121 122 val bottomState = underTest.bottomDragState 123 assertThat(bottomState.currentValue).isEqualTo(0) 124 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 125 } 126 127 /** 128 * Verifies element in first row which is already at full size (2 span) can only be shrunk from 129 * the bottom. 130 */ 131 @Test testTwoSpanGrid_elementInFirstRow_sizeTwoSpannull132 fun testTwoSpanGrid_elementInFirstRow_sizeTwoSpan() = 133 testScope.runTest { 134 val adjustedGridLayout = singleSpanGrid.copy(currentSpan = 2, totalSpans = 2) 135 136 updateGridLayout(adjustedGridLayout) 137 138 val topState = underTest.topDragState 139 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 140 assertThat(topState.currentValue).isEqualTo(0) 141 142 val bottomState = underTest.bottomDragState 143 assertThat(bottomState.anchors.toList()).containsExactly(-1 to -45f, 0 to 0f) 144 assertThat(bottomState.currentValue).isEqualTo(0) 145 } 146 147 /** 148 * Verifies element in a middle row at minimum size can be expanded from either top or bottom. 149 */ 150 @Test testThreeSpanGrid_elementInMiddleRow_sizeOneSpannull151 fun testThreeSpanGrid_elementInMiddleRow_sizeOneSpan() = 152 testScope.runTest { 153 val adjustedGridLayout = 154 singleSpanGrid.copy(currentRow = 1, currentSpan = 1, totalSpans = 3) 155 156 updateGridLayout(adjustedGridLayout) 157 158 val topState = underTest.topDragState 159 assertThat(topState.currentValue).isEqualTo(0) 160 assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -30f) 161 162 val bottomState = underTest.bottomDragState 163 assertThat(bottomState.currentValue).isEqualTo(0) 164 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 30f) 165 } 166 167 @Test testThreeSpanGrid_elementInTopRow_sizeOneSpannull168 fun testThreeSpanGrid_elementInTopRow_sizeOneSpan() = 169 testScope.runTest { 170 val adjustedGridLayout = 171 singleSpanGrid.copy(currentRow = 0, currentSpan = 1, totalSpans = 3) 172 173 updateGridLayout(adjustedGridLayout) 174 175 val topState = underTest.topDragState 176 assertThat(topState.currentValue).isEqualTo(0) 177 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 178 179 val bottomState = underTest.bottomDragState 180 assertThat(bottomState.currentValue).isEqualTo(0) 181 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 30f, 2 to 60f) 182 } 183 184 @Test testSixSpanGrid_minSpanThree_itemInFourthRow_sizeThreeSpansnull185 fun testSixSpanGrid_minSpanThree_itemInFourthRow_sizeThreeSpans() = 186 testScope.runTest { 187 val adjustedGridLayout = 188 singleSpanGrid.copy( 189 currentRow = 3, 190 currentSpan = 3, 191 resizeMultiple = 3, 192 totalSpans = 6, 193 ) 194 195 updateGridLayout(adjustedGridLayout) 196 197 val topState = underTest.topDragState 198 assertThat(topState.currentValue).isEqualTo(0) 199 assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -3 to -45f) 200 201 val bottomState = underTest.bottomDragState 202 assertThat(bottomState.currentValue).isEqualTo(0) 203 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 204 } 205 206 @Test testTwoSpanGrid_elementMovesFromFirstRowToSecondRownull207 fun testTwoSpanGrid_elementMovesFromFirstRowToSecondRow() = 208 testScope.runTest { 209 val firstRowLayout = 210 singleSpanGrid.copy( 211 currentRow = 0, 212 currentSpan = 1, 213 resizeMultiple = 1, 214 totalSpans = 2, 215 ) 216 updateGridLayout(firstRowLayout) 217 218 val topState = underTest.topDragState 219 val bottomState = underTest.bottomDragState 220 221 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 222 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 45f) 223 224 val secondRowLayout = firstRowLayout.copy(currentRow = 1) 225 updateGridLayout(secondRowLayout) 226 227 assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -45f) 228 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 229 } 230 231 @Test <lambda>null232 fun testTwoSpanGrid_expandElementFromBottom() = runTestWithSnapshots { 233 val resizeInfo by collectLastValue(underTest.resizeInfo) 234 235 val adjustedGridLayout = singleSpanGrid.copy(resizeMultiple = 1, totalSpans = 2) 236 237 updateGridLayout(adjustedGridLayout) 238 239 underTest.bottomDragState.anchoredDrag { dragTo(45f) } 240 241 assertThat(resizeInfo).isEqualTo(ResizeInfo(1, DragHandle.BOTTOM)) 242 } 243 244 @Test <lambda>null245 fun testThreeSpanGrid_expandMiddleElementUpwards() = runTestWithSnapshots { 246 val resizeInfo by collectLastValue(underTest.resizeInfo) 247 updateGridLayout(singleSpanGrid.copy(currentRow = 1, totalSpans = 3)) 248 249 underTest.topDragState.anchoredDrag { dragTo(-30f) } 250 assertThat(resizeInfo).isEqualTo(ResizeInfo(1, DragHandle.TOP)) 251 } 252 253 @Test <lambda>null254 fun testThreeSpanGrid_expandTopElementDownBy2Spans() = runTestWithSnapshots { 255 val resizeInfo by collectLastValue(underTest.resizeInfo) 256 updateGridLayout(singleSpanGrid.copy(totalSpans = 3)) 257 258 assertThat(resizeInfo).isNull() 259 underTest.bottomDragState.anchoredDrag { dragTo(60f) } 260 assertThat(resizeInfo).isEqualTo(ResizeInfo(2, DragHandle.BOTTOM)) 261 } 262 263 @Test <lambda>null264 fun testTwoSpanGrid_shrinkElementFromBottom() = runTestWithSnapshots { 265 val resizeInfo by collectLastValue(underTest.resizeInfo) 266 updateGridLayout(singleSpanGrid.copy(totalSpans = 2, currentSpan = 2)) 267 268 assertThat(resizeInfo).isNull() 269 underTest.bottomDragState.anchoredDrag { dragTo(-45f) } 270 assertThat(resizeInfo).isEqualTo(ResizeInfo(-1, DragHandle.BOTTOM)) 271 } 272 273 @Test testRowInfoBecomesNull_revertsBackToDefaultnull274 fun testRowInfoBecomesNull_revertsBackToDefault() = 275 testScope.runTest { 276 val gridLayout = singleSpanGrid.copy(currentRow = 1, resizeMultiple = 1, totalSpans = 3) 277 updateGridLayout(gridLayout) 278 279 val topState = underTest.topDragState 280 assertThat(topState.anchors.toList()).containsExactly(0 to 0f, -1 to -30f) 281 282 val bottomState = underTest.bottomDragState 283 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, 1 to 30f) 284 285 // Set currentRow to null to simulate the row info becoming null 286 updateGridLayout(gridLayout.copy(currentRow = null)) 287 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 288 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 289 } 290 291 @Test testEqualMaxAndMinHeight_cannotResizenull292 fun testEqualMaxAndMinHeight_cannotResize() = 293 testScope.runTest { 294 val heightPx = 20 295 updateGridLayout( 296 singleSpanGrid.copy(maxHeightPx = heightPx, minHeightPx = heightPx, totalSpans = 2) 297 ) 298 299 val topState = underTest.topDragState 300 val bottomState = underTest.bottomDragState 301 302 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 303 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 304 } 305 306 @Test testMinHeightTwoRows_canExpandButNotShrinknull307 fun testMinHeightTwoRows_canExpandButNotShrink() = 308 testScope.runTest { 309 val threeRowGrid = 310 singleSpanGrid.copy( 311 maxHeightPx = 80, 312 minHeightPx = 50, 313 totalSpans = 3, 314 currentSpan = 2, 315 currentRow = 0, 316 ) 317 318 updateGridLayout(threeRowGrid) 319 320 val topState = underTest.topDragState 321 val bottomState = underTest.bottomDragState 322 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 323 assertThat(bottomState.anchors.toList()).containsAtLeast(0 to 0f, 1 to 30f) 324 } 325 326 @Test testMaxHeightTwoRows_canShrinkButNotExpandnull327 fun testMaxHeightTwoRows_canShrinkButNotExpand() = 328 testScope.runTest { 329 val threeRowGrid = 330 singleSpanGrid.copy( 331 maxHeightPx = 50, 332 minHeightPx = 20, 333 totalSpans = 3, 334 currentSpan = 2, 335 currentRow = 0, 336 ) 337 338 updateGridLayout(threeRowGrid) 339 340 val topState = underTest.topDragState 341 val bottomState = underTest.bottomDragState 342 343 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, -1 to -30f) 344 345 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 346 } 347 348 @Test testMinHeightEqualToAvailableSpan_cannotResizenull349 fun testMinHeightEqualToAvailableSpan_cannotResize() = 350 testScope.runTest { 351 val twoRowGrid = 352 singleSpanGrid.copy( 353 minHeightPx = (viewportHeightPx - verticalContentPaddingPx.toInt()), 354 totalSpans = 2, 355 currentSpan = 2, 356 ) 357 358 updateGridLayout(twoRowGrid) 359 360 val topState = underTest.topDragState 361 val bottomState = underTest.bottomDragState 362 363 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 364 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 365 } 366 367 @Test testMaxSpansLessThanCurrentSpannull368 fun testMaxSpansLessThanCurrentSpan() = 369 testScope.runTest { 370 // heightPerSpan = 371 // (viewportHeightPx - verticalContentPaddingPx - (totalSpans - 1) 372 // * verticalItemSpacingPx) / totalSpans 373 // = 145.3333 374 // maxSpans = (maxHeightPx + verticalItemSpacing) / 375 // (heightPerSpanPx + verticalItemSpacingPx) 376 // = 4.72 377 // This is invalid because the max span calculation comes out to be less than 378 // the current span. Ensure we handle this case correctly. 379 val layout = 380 GridLayout( 381 verticalItemSpacingPx = 100f, 382 currentRow = 0, 383 minHeightPx = 480, 384 maxHeightPx = 1060, 385 currentSpan = 6, 386 resizeMultiple = 3, 387 totalSpans = 6, 388 viewportHeightPx = 1600, 389 verticalContentPaddingPx = 228f, 390 ) 391 updateGridLayout(layout) 392 393 val topState = underTest.topDragState 394 val bottomState = underTest.bottomDragState 395 396 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 397 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f, -3 to -736f) 398 } 399 400 @Test testCanExpand_atTopPosition_withMultipleAnchors_returnsTruenull401 fun testCanExpand_atTopPosition_withMultipleAnchors_returnsTrue() = 402 testScope.runTest { 403 val twoRowGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 1, currentRow = 0) 404 405 updateGridLayout(twoRowGrid) 406 assertThat(underTest.canExpand()).isTrue() 407 assertThat(underTest.bottomDragState.anchors.toList()) 408 .containsAtLeast(0 to 0f, 1 to 45f) 409 } 410 411 @Test testCanExpand_atTopPosition_withSingleAnchors_returnsFalsenull412 fun testCanExpand_atTopPosition_withSingleAnchors_returnsFalse() = 413 testScope.runTest { 414 val oneRowGrid = singleSpanGrid.copy(totalSpans = 1, currentSpan = 1, currentRow = 0) 415 updateGridLayout(oneRowGrid) 416 assertThat(underTest.canExpand()).isFalse() 417 } 418 419 @Test testCanExpand_atBottomPosition_withMultipleAnchors_returnsTruenull420 fun testCanExpand_atBottomPosition_withMultipleAnchors_returnsTrue() = 421 testScope.runTest { 422 val twoRowGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 1, currentRow = 1) 423 updateGridLayout(twoRowGrid) 424 assertThat(underTest.canExpand()).isTrue() 425 assertThat(underTest.topDragState.anchors.toList()).containsAtLeast(0 to 0f, -1 to -45f) 426 } 427 428 @Test testCanShrink_atMinimumHeight_returnsFalsenull429 fun testCanShrink_atMinimumHeight_returnsFalse() = 430 testScope.runTest { 431 val oneRowGrid = singleSpanGrid.copy(totalSpans = 1, currentSpan = 1, currentRow = 0) 432 updateGridLayout(oneRowGrid) 433 assertThat(underTest.canShrink()).isFalse() 434 } 435 436 @Test <lambda>null437 fun testCanShrink_atFullSize_checksBottomDragState() = runTestWithSnapshots { 438 val twoSpanGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 2, currentRow = 0) 439 updateGridLayout(twoSpanGrid) 440 441 assertThat(underTest.canShrink()).isTrue() 442 assertThat(underTest.bottomDragState.anchors.toList()).containsAtLeast(0 to 0f, -1 to -45f) 443 } 444 445 @Test <lambda>null446 fun testResizeByAccessibility_expandFromBottom_usesTopDragState() = runTestWithSnapshots { 447 val resizeInfo by collectLastValue(underTest.resizeInfo) 448 449 val twoSpanGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 1, currentRow = 1) 450 updateGridLayout(twoSpanGrid) 451 452 underTest.expandToNextAnchor() 453 454 assertThat(resizeInfo).isEqualTo(ResizeInfo(1, DragHandle.TOP)) 455 } 456 457 @Test <lambda>null458 fun testResizeByAccessibility_expandFromTop_usesBottomDragState() = runTestWithSnapshots { 459 val resizeInfo by collectLastValue(underTest.resizeInfo) 460 461 val twoSpanGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 1, currentRow = 0) 462 updateGridLayout(twoSpanGrid) 463 464 underTest.expandToNextAnchor() 465 466 assertThat(resizeInfo).isEqualTo(ResizeInfo(1, DragHandle.BOTTOM)) 467 } 468 469 @Test <lambda>null470 fun testResizeByAccessibility_shrinkFromFull_usesBottomDragState() = runTestWithSnapshots { 471 val resizeInfo by collectLastValue(underTest.resizeInfo) 472 473 val twoSpanGrid = singleSpanGrid.copy(totalSpans = 2, currentSpan = 2, currentRow = 0) 474 updateGridLayout(twoSpanGrid) 475 476 underTest.shrinkToNextAnchor() 477 478 assertThat(resizeInfo).isEqualTo(ResizeInfo(-1, DragHandle.BOTTOM)) 479 } 480 481 @Test <lambda>null482 fun testResizeByAccessibility_cannotResizeAtMinSize() = runTestWithSnapshots { 483 val resizeInfo by collectLastValue(underTest.resizeInfo) 484 485 // Set up grid at minimum size 486 val minSizeGrid = 487 singleSpanGrid.copy( 488 totalSpans = 2, 489 currentSpan = 1, 490 minHeightPx = singleSpanGrid.minHeightPx, 491 currentRow = 0, 492 ) 493 updateGridLayout(minSizeGrid) 494 495 underTest.shrinkToNextAnchor() 496 497 assertThat(resizeInfo).isNull() 498 } 499 500 @Test(expected = IllegalArgumentException::class) testIllegalState_maxHeightLessThanMinHeightnull501 fun testIllegalState_maxHeightLessThanMinHeight() = 502 testScope.runTest { 503 updateGridLayout(singleSpanGrid.copy(maxHeightPx = 50, minHeightPx = 100)) 504 } 505 506 @Test(expected = IllegalArgumentException::class) testIllegalState_currentSpanExceedsTotalSpansnull507 fun testIllegalState_currentSpanExceedsTotalSpans() = 508 testScope.runTest { updateGridLayout(singleSpanGrid.copy(currentSpan = 3, totalSpans = 2)) } 509 510 @Test(expected = IllegalArgumentException::class) testIllegalState_resizeMultipleZeroOrNegativenull511 fun testIllegalState_resizeMultipleZeroOrNegative() = 512 testScope.runTest { updateGridLayout(singleSpanGrid.copy(resizeMultiple = 0)) } 513 514 @Test <lambda>null515 fun testZeroHeights_cannotResize() = runTestWithSnapshots { 516 val zeroHeightGrid = 517 singleSpanGrid.copy( 518 totalSpans = 2, 519 currentSpan = 1, 520 currentRow = 0, 521 minHeightPx = 0, 522 maxHeightPx = 0, 523 ) 524 updateGridLayout(zeroHeightGrid) 525 526 val topState = underTest.topDragState 527 val bottomState = underTest.bottomDragState 528 assertThat(topState.anchors.toList()).containsExactly(0 to 0f) 529 assertThat(bottomState.anchors.toList()).containsExactly(0 to 0f) 530 } 531 updateGridLayoutnull532 private fun TestScope.updateGridLayout(gridLayout: GridLayout) { 533 underTest.setGridLayoutInfo( 534 verticalItemSpacingPx = gridLayout.verticalItemSpacingPx, 535 currentRow = gridLayout.currentRow, 536 maxHeightPx = gridLayout.maxHeightPx, 537 minHeightPx = gridLayout.minHeightPx, 538 currentSpan = gridLayout.currentSpan, 539 resizeMultiple = gridLayout.resizeMultiple, 540 totalSpans = gridLayout.totalSpans, 541 viewportHeightPx = gridLayout.viewportHeightPx, 542 verticalContentPaddingPx = gridLayout.verticalContentPaddingPx, 543 ) 544 runCurrent() 545 } 546 <lambda>null547 private fun DraggableAnchors<Int>.toList() = buildList { 548 for (index in 0 until this@toList.size) { 549 add(anchorAt(index) to positionAt(index)) 550 } 551 } 552 runTestWithSnapshotsnull553 private fun runTestWithSnapshots(testBody: suspend TestScope.() -> Unit) { 554 val globalWriteObserverHandle = 555 Snapshot.registerGlobalWriteObserver { 556 // This is normally done by the compose runtime. 557 Snapshot.sendApplyNotifications() 558 } 559 560 try { 561 testScope.runTest(testBody = testBody) 562 } finally { 563 globalWriteObserverHandle.dispose() 564 } 565 } 566 567 private data class GridLayout( 568 val verticalItemSpacingPx: Float, 569 val verticalContentPaddingPx: Float, 570 val viewportHeightPx: Int, 571 val currentRow: Int?, 572 val currentSpan: Int, 573 val maxHeightPx: Int, 574 val minHeightPx: Int, 575 val resizeMultiple: Int, 576 val totalSpans: Int, 577 ) 578 } 579