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.wm.shell.windowdecor 18 19 import android.app.ActivityManager 20 import android.graphics.PointF 21 import android.graphics.Rect 22 import android.util.MathUtils.abs 23 import android.util.MathUtils.max 24 import androidx.test.filters.SmallTest 25 import com.android.wm.shell.ShellTestCase 26 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_BOTTOM 27 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_LEFT 28 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_RIGHT 29 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_TOP 30 import com.android.wm.shell.windowdecor.DragPositioningCallback.CTRL_TYPE_UNDEFINED 31 import com.android.wm.shell.windowdecor.DragPositioningCallback.CtrlType 32 import com.google.common.truth.Truth.assertThat 33 import com.google.testing.junit.testparameterinjector.TestParameter 34 import com.google.testing.junit.testparameterinjector.TestParameterInjector 35 import kotlin.math.min 36 import org.junit.Before 37 import org.junit.Test 38 import org.junit.runner.RunWith 39 import org.mockito.Mock 40 import org.mockito.Mockito.spy 41 import org.mockito.Mockito.verify 42 import org.mockito.kotlin.any 43 import org.mockito.kotlin.argumentCaptor 44 import org.mockito.kotlin.doReturn 45 import org.mockito.kotlin.never 46 47 /** 48 * Tests for the [FixedAspectRatioTaskPositionerDecorator], written in parameterized form to check 49 * decorators behaviour for different variations of drag actions. 50 * 51 * Build/Install/Run: 52 * atest WMShellUnitTests:FixedAspectRatioTaskPositionerDecoratorTests 53 */ 54 @SmallTest 55 @RunWith(TestParameterInjector::class) 56 class FixedAspectRatioTaskPositionerDecoratorTests : ShellTestCase(){ 57 @Mock 58 private lateinit var mockDesktopWindowDecoration: DesktopModeWindowDecoration 59 @Mock 60 private lateinit var mockTaskPositioner: VeiledResizeTaskPositioner 61 62 private lateinit var decoratedTaskPositioner: FixedAspectRatioTaskPositionerDecorator 63 64 @Before setUpnull65 fun setUp() { 66 mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { 67 isResizeable = false 68 configuration.windowConfiguration.setBounds(PORTRAIT_BOUNDS) 69 } 70 doReturn(PORTRAIT_BOUNDS).`when`(mockTaskPositioner).onDragPositioningStart( 71 any(), any(), any(), any()) 72 doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningMove(any(), any(), any()) 73 doReturn(Rect()).`when`(mockTaskPositioner).onDragPositioningEnd(any(), any(), any()) 74 decoratedTaskPositioner = spy( 75 FixedAspectRatioTaskPositionerDecorator( 76 mockDesktopWindowDecoration, mockTaskPositioner) 77 ) 78 } 79 80 @Test testOnDragPositioningStart_noAdjustmentnull81 fun testOnDragPositioningStart_noAdjustment( 82 @TestParameter testCase: ResizeableOrNotResizingTestCases 83 ) { 84 val originalX = 0f 85 val originalY = 0f 86 mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { 87 isResizeable = testCase.isResizeable 88 } 89 90 decoratedTaskPositioner.onDragPositioningStart( 91 testCase.ctrlType, DISPLAY_ID, originalX, originalY) 92 93 val capturedValues = getLatestOnStartArguments() 94 assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType) 95 assertThat(capturedValues.x).isEqualTo(originalX) 96 assertThat(capturedValues.y).isEqualTo(originalY) 97 } 98 99 @Test testOnDragPositioningStart_cornerResize_noAdjustmentnull100 fun testOnDragPositioningStart_cornerResize_noAdjustment( 101 @TestParameter testCase: CornerResizeStartTestCases 102 ) { 103 val originalX = 0f 104 val originalY = 0f 105 106 decoratedTaskPositioner.onDragPositioningStart( 107 testCase.ctrlType, DISPLAY_ID, originalX, originalY) 108 109 val capturedValues = getLatestOnStartArguments() 110 assertThat(capturedValues.ctrlType).isEqualTo(testCase.ctrlType) 111 assertThat(capturedValues.x).isEqualTo(originalX) 112 assertThat(capturedValues.y).isEqualTo(originalY) 113 } 114 115 @Test testOnDragPositioningStart_edgeResize_ctrlTypeAdjustednull116 fun testOnDragPositioningStart_edgeResize_ctrlTypeAdjusted( 117 @TestParameter testCase: EdgeResizeStartTestCases, @TestParameter orientation: Orientation 118 ) { 119 val startingBounds = getAndMockBounds(orientation) 120 val startingPoint = getEdgeStartingPoint( 121 testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) 122 123 decoratedTaskPositioner.onDragPositioningStart( 124 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 125 126 val adjustedCtrlType = testCase.ctrlType + testCase.additionalEdgeCtrlType 127 val capturedValues = getLatestOnStartArguments() 128 assertThat(capturedValues.ctrlType).isEqualTo(adjustedCtrlType) 129 assertThat(capturedValues.x).isEqualTo(startingPoint.x) 130 assertThat(capturedValues.y).isEqualTo(startingPoint.y) 131 } 132 133 @Test testOnDragPositioningMove_noAdjustmentnull134 fun testOnDragPositioningMove_noAdjustment( 135 @TestParameter testCase: ResizeableOrNotResizingTestCases 136 ) { 137 val originalX = 0f 138 val originalY = 0f 139 decoratedTaskPositioner.onDragPositioningStart( 140 testCase.ctrlType, DISPLAY_ID, originalX, originalX) 141 mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { 142 isResizeable = testCase.isResizeable 143 } 144 145 decoratedTaskPositioner.onDragPositioningMove( 146 DISPLAY_ID, originalX + SMALL_DELTA, originalY + SMALL_DELTA) 147 148 val capturedValues = getLatestOnMoveArguments() 149 assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA) 150 assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA) 151 } 152 153 @Test testOnDragPositioningMove_cornerResize_invalidRegion_noResizenull154 fun testOnDragPositioningMove_cornerResize_invalidRegion_noResize( 155 @TestParameter testCase: InvalidCornerResizeTestCases, 156 @TestParameter orientation: Orientation 157 ) { 158 val startingBounds = getAndMockBounds(orientation) 159 val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) 160 161 decoratedTaskPositioner.onDragPositioningStart( 162 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 163 164 val updatedBounds = decoratedTaskPositioner.onDragPositioningMove( 165 DISPLAY_ID, 166 startingPoint.x + testCase.dragDelta.x, 167 startingPoint.y + testCase.dragDelta.y) 168 169 verify(mockTaskPositioner, never()).onDragPositioningMove(any(), any(), any()) 170 assertThat(updatedBounds).isEqualTo(startingBounds) 171 } 172 173 174 @Test testOnDragPositioningMove_cornerResize_validRegion_resizeToAdjustedCoordinatesnull175 fun testOnDragPositioningMove_cornerResize_validRegion_resizeToAdjustedCoordinates( 176 @TestParameter testCase: ValidCornerResizeTestCases, 177 @TestParameter orientation: Orientation 178 ) { 179 val startingBounds = getAndMockBounds(orientation) 180 val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) 181 182 decoratedTaskPositioner.onDragPositioningStart( 183 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 184 185 decoratedTaskPositioner.onDragPositioningMove( 186 DISPLAY_ID, 187 startingPoint.x + testCase.dragDelta.x, 188 startingPoint.y + testCase.dragDelta.y) 189 190 val adjustedDragDelta = calculateAdjustedDelta( 191 testCase.ctrlType, testCase.dragDelta, orientation) 192 val capturedValues = getLatestOnMoveArguments() 193 val absChangeX = abs(capturedValues.x - startingPoint.x) 194 val absChangeY = abs(capturedValues.y - startingPoint.y) 195 val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY) 196 assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x) 197 assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y) 198 assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO) 199 } 200 201 @Test testOnDragPositioningMove_edgeResize_resizeToAdjustedCoordinatesnull202 fun testOnDragPositioningMove_edgeResize_resizeToAdjustedCoordinates( 203 @TestParameter testCase: EdgeResizeTestCases, 204 @TestParameter orientation: Orientation 205 ) { 206 val startingBounds = getAndMockBounds(orientation) 207 val startingPoint = getEdgeStartingPoint( 208 testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) 209 210 decoratedTaskPositioner.onDragPositioningStart( 211 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 212 213 decoratedTaskPositioner.onDragPositioningMove( 214 DISPLAY_ID, 215 startingPoint.x + testCase.dragDelta.x, 216 startingPoint.y + testCase.dragDelta.y) 217 218 val adjustedDragDelta = calculateAdjustedDelta( 219 testCase.ctrlType + testCase.additionalEdgeCtrlType, 220 testCase.dragDelta, 221 orientation) 222 val capturedValues = getLatestOnMoveArguments() 223 val absChangeX = abs(capturedValues.x - startingPoint.x) 224 val absChangeY = abs(capturedValues.y - startingPoint.y) 225 val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY) 226 assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x) 227 assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y) 228 assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO) 229 } 230 231 @Test testOnDragPositioningEnd_noAdjustmentnull232 fun testOnDragPositioningEnd_noAdjustment( 233 @TestParameter testCase: ResizeableOrNotResizingTestCases 234 ) { 235 val originalX = 0f 236 val originalY = 0f 237 decoratedTaskPositioner.onDragPositioningStart(testCase.ctrlType, DISPLAY_ID, 238 originalX, originalX) 239 mockDesktopWindowDecoration.mTaskInfo = ActivityManager.RunningTaskInfo().apply { 240 isResizeable = testCase.isResizeable 241 } 242 243 decoratedTaskPositioner.onDragPositioningEnd( 244 DISPLAY_ID, originalX + SMALL_DELTA, originalY + SMALL_DELTA) 245 246 val capturedValues = getLatestOnEndArguments() 247 assertThat(capturedValues.x).isEqualTo(originalX + SMALL_DELTA) 248 assertThat(capturedValues.y).isEqualTo(originalY + SMALL_DELTA) 249 } 250 251 @Test testOnDragPositioningEnd_cornerResize_invalidRegion_endsAtPreviousValidPointnull252 fun testOnDragPositioningEnd_cornerResize_invalidRegion_endsAtPreviousValidPoint( 253 @TestParameter testCase: InvalidCornerResizeTestCases, 254 @TestParameter orientation: Orientation 255 ) { 256 val startingBounds = getAndMockBounds(orientation) 257 val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) 258 259 decoratedTaskPositioner.onDragPositioningStart( 260 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 261 262 decoratedTaskPositioner.onDragPositioningEnd( 263 DISPLAY_ID, 264 startingPoint.x + testCase.dragDelta.x, 265 startingPoint.y + testCase.dragDelta.y) 266 267 val capturedValues = getLatestOnEndArguments() 268 assertThat(capturedValues.x).isEqualTo(startingPoint.x) 269 assertThat(capturedValues.y).isEqualTo(startingPoint.y) 270 } 271 272 @Test testOnDragPositioningEnd_cornerResize_validRegion_endAtAdjustedCoordinatesnull273 fun testOnDragPositioningEnd_cornerResize_validRegion_endAtAdjustedCoordinates( 274 @TestParameter testCase: ValidCornerResizeTestCases, 275 @TestParameter orientation: Orientation 276 ) { 277 val startingBounds = getAndMockBounds(orientation) 278 val startingPoint = getCornerStartingPoint(testCase.ctrlType, startingBounds) 279 280 decoratedTaskPositioner.onDragPositioningStart( 281 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 282 283 decoratedTaskPositioner.onDragPositioningEnd( 284 DISPLAY_ID, 285 startingPoint.x + testCase.dragDelta.x, 286 startingPoint.y + testCase.dragDelta.y) 287 288 val adjustedDragDelta = calculateAdjustedDelta( 289 testCase.ctrlType, testCase.dragDelta, orientation) 290 val capturedValues = getLatestOnEndArguments() 291 val absChangeX = abs(capturedValues.x - startingPoint.x) 292 val absChangeY = abs(capturedValues.y - startingPoint.y) 293 val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY) 294 assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x) 295 assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y) 296 assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO) 297 } 298 299 @Test testOnDragPositioningEnd_edgeResize_endAtAdjustedCoordinatesnull300 fun testOnDragPositioningEnd_edgeResize_endAtAdjustedCoordinates( 301 @TestParameter testCase: EdgeResizeTestCases, 302 @TestParameter orientation: Orientation 303 ) { 304 val startingBounds = getAndMockBounds(orientation) 305 val startingPoint = getEdgeStartingPoint( 306 testCase.ctrlType, testCase.additionalEdgeCtrlType, startingBounds) 307 308 decoratedTaskPositioner.onDragPositioningStart( 309 testCase.ctrlType, DISPLAY_ID, startingPoint.x, startingPoint.y) 310 311 decoratedTaskPositioner.onDragPositioningEnd( 312 DISPLAY_ID, 313 startingPoint.x + testCase.dragDelta.x, 314 startingPoint.y + testCase.dragDelta.y) 315 316 val adjustedDragDelta = calculateAdjustedDelta( 317 testCase.ctrlType + testCase.additionalEdgeCtrlType, 318 testCase.dragDelta, 319 orientation) 320 val capturedValues = getLatestOnEndArguments() 321 val absChangeX = abs(capturedValues.x - startingPoint.x) 322 val absChangeY = abs(capturedValues.y - startingPoint.y) 323 val resultAspectRatio = max(absChangeX, absChangeY) / min(absChangeX, absChangeY) 324 assertThat(capturedValues.x).isEqualTo(startingPoint.x + adjustedDragDelta.x) 325 assertThat(capturedValues.y).isEqualTo(startingPoint.y + adjustedDragDelta.y) 326 assertThat(resultAspectRatio).isEqualTo(STARTING_ASPECT_RATIO) 327 } 328 329 /** 330 * Returns the most recent arguments passed to the `.onPositioningStart()` of the 331 * [mockTaskPositioner]. 332 */ getLatestOnStartArgumentsnull333 private fun getLatestOnStartArguments(): CtrlCoordinateCapture { 334 val captorCtrlType = argumentCaptor<Int>() 335 val captorCoordinates = argumentCaptor<Float>() 336 verify(mockTaskPositioner).onDragPositioningStart( 337 captorCtrlType.capture(), any(), captorCoordinates.capture(), captorCoordinates.capture()) 338 339 return CtrlCoordinateCapture(captorCtrlType.firstValue, captorCoordinates.firstValue, 340 captorCoordinates.secondValue) 341 } 342 343 /** 344 * Returns the most recent arguments passed to the `.onPositioningMove()` of the 345 * [mockTaskPositioner]. 346 */ getLatestOnMoveArgumentsnull347 private fun getLatestOnMoveArguments(): PointF { 348 val captorCoordinates = argumentCaptor<Float>() 349 verify(mockTaskPositioner).onDragPositioningMove( 350 any(), captorCoordinates.capture(), captorCoordinates.capture()) 351 352 return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue) 353 } 354 355 /** 356 * Returns the most recent arguments passed to the `.onPositioningEnd()` of the 357 * [mockTaskPositioner]. 358 */ getLatestOnEndArgumentsnull359 private fun getLatestOnEndArguments(): PointF { 360 val captorCoordinates = argumentCaptor<Float>() 361 verify(mockTaskPositioner).onDragPositioningEnd( 362 any(), captorCoordinates.capture(), captorCoordinates.capture()) 363 364 return PointF(captorCoordinates.firstValue, captorCoordinates.secondValue) 365 } 366 367 /** 368 * Mocks the app bounds to correspond with a given orientation and returns the mocked bounds. 369 */ getAndMockBoundsnull370 private fun getAndMockBounds(orientation: Orientation): Rect { 371 val mockBounds = if (orientation.isPortrait) PORTRAIT_BOUNDS else LANDSCAPE_BOUNDS 372 doReturn(mockBounds).`when`(mockTaskPositioner).onDragPositioningStart( 373 any(), any(), any(), any()) 374 doReturn(mockBounds).`when`(decoratedTaskPositioner).getBounds(any()) 375 return mockBounds 376 } 377 378 /** 379 * Calculates the corner point a given drag action should start from, based on the [ctrlType], 380 * given the [startingBounds]. 381 */ getCornerStartingPointnull382 private fun getCornerStartingPoint(@CtrlType ctrlType: Int, startingBounds: Rect): PointF { 383 return when (ctrlType) { 384 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT -> 385 PointF(startingBounds.right.toFloat(), startingBounds.bottom.toFloat()) 386 387 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT -> 388 PointF(startingBounds.left.toFloat(), startingBounds.bottom.toFloat()) 389 390 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT -> 391 PointF(startingBounds.right.toFloat(), startingBounds.top.toFloat()) 392 // CTRL_TYPE_TOP + CTRL_TYPE_LEFT 393 else -> 394 PointF(startingBounds.left.toFloat(), startingBounds.top.toFloat()) 395 } 396 } 397 398 /** 399 * Calculates the point along an edge the edge resize should start from, based on the starting 400 * edge ([edgeCtrlType]) and the additional edge we expect to resize ([additionalEdgeCtrlType]), 401 * given the [startingBounds]. 402 */ getEdgeStartingPointnull403 private fun getEdgeStartingPoint( 404 @CtrlType edgeCtrlType: Int, @CtrlType additionalEdgeCtrlType: Int, startingBounds: Rect 405 ): PointF { 406 val simulatedCorner = getCornerStartingPoint( 407 edgeCtrlType + additionalEdgeCtrlType, startingBounds) 408 when (additionalEdgeCtrlType) { 409 CTRL_TYPE_TOP -> { 410 simulatedCorner.offset(0f, -SMALL_DELTA) 411 return simulatedCorner 412 } 413 CTRL_TYPE_BOTTOM -> { 414 simulatedCorner.offset(0f, SMALL_DELTA) 415 return simulatedCorner 416 } 417 CTRL_TYPE_LEFT -> { 418 simulatedCorner.offset(SMALL_DELTA, 0f) 419 return simulatedCorner 420 } 421 // CTRL_TYPE_RIGHT 422 else -> { 423 simulatedCorner.offset(-SMALL_DELTA, 0f) 424 return simulatedCorner 425 } 426 } 427 } 428 429 /** 430 * Calculates the adjustments to the drag delta we expect for a given action and orientation. 431 */ calculateAdjustedDeltanull432 private fun calculateAdjustedDelta( 433 @CtrlType ctrlType: Int, delta: PointF, orientation: Orientation 434 ): PointF { 435 if ((abs(delta.x) < abs(delta.y) && delta.x != 0f) || delta.y == 0f) { 436 // Only respect x delta if it's less than y delta but non-zero (i.e there is a change 437 // in x to be applied), or if the y delta is zero (i.e there is no change in y to be 438 // applied). 439 val adjustedY = if (orientation.isPortrait) 440 delta.x * STARTING_ASPECT_RATIO else 441 delta.x / STARTING_ASPECT_RATIO 442 if (ctrlType.isBottomRightOrTopLeftCorner()) { 443 return PointF(delta.x, adjustedY) 444 } 445 return PointF(delta.x, -adjustedY) 446 } 447 // Respect y delta. 448 val adjustedX = if (orientation.isPortrait) 449 delta.y / STARTING_ASPECT_RATIO else 450 delta.y * STARTING_ASPECT_RATIO 451 if (ctrlType.isBottomRightOrTopLeftCorner()) { 452 return PointF(adjustedX, delta.y) 453 } 454 return PointF(-adjustedX, delta.y) 455 } 456 isBottomRightOrTopLeftCornernull457 private fun @receiver:CtrlType Int.isBottomRightOrTopLeftCorner(): Boolean { 458 return this == CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT || this == CTRL_TYPE_TOP + CTRL_TYPE_LEFT 459 } 460 461 private inner class CtrlCoordinateCapture(ctrl: Int, xValue: Float, yValue: Float) { 462 var ctrlType = ctrl 463 var x = xValue 464 var y = yValue 465 } 466 467 companion object { 468 private val PORTRAIT_BOUNDS = Rect(100, 100, 200, 400) 469 private val LANDSCAPE_BOUNDS = Rect(100, 100, 400, 200) 470 private val STARTING_ASPECT_RATIO = PORTRAIT_BOUNDS.height() / PORTRAIT_BOUNDS.width() 471 private const val LARGE_DELTA = 50f 472 private const val SMALL_DELTA = 30f 473 private const val DISPLAY_ID = 1 474 475 enum class Orientation( 476 val isPortrait: Boolean 477 ) { 478 PORTRAIT (true), 479 LANDSCAPE (false) 480 } 481 482 enum class ResizeableOrNotResizingTestCases( 483 val ctrlType: Int, 484 val isResizeable: Boolean 485 ) { 486 NotResizing (CTRL_TYPE_UNDEFINED, false), 487 Resizeable (CTRL_TYPE_RIGHT, true) 488 } 489 490 /** 491 * Tests cases for the start of a corner resize. 492 * @param ctrlType the control type of the corner the resize is initiated on. 493 */ 494 enum class CornerResizeStartTestCases( 495 val ctrlType: Int 496 ) { 497 BottomRightCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT), 498 BottomLeftCorner (CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT), 499 TopRightCorner (CTRL_TYPE_TOP + CTRL_TYPE_RIGHT), 500 TopLeftCorner (CTRL_TYPE_TOP + CTRL_TYPE_LEFT) 501 } 502 503 /** 504 * Tests cases for the moving and ending of a invalid corner resize. Where the compass point 505 * (e.g `SouthEast`) represents the direction of the drag. 506 * @param ctrlType the control type of the corner the resize is initiated on. 507 * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s 508 * corresponding corner point. Represented as a combination a different signed small and 509 * large deltas which correspond to the direction/angle of drag. 510 */ 511 enum class InvalidCornerResizeTestCases( 512 val ctrlType: Int, 513 val dragDelta: PointF 514 ) { 515 BottomRightCornerNorthEastDrag ( 516 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 517 PointF(LARGE_DELTA, -LARGE_DELTA)), 518 BottomRightCornerSouthWestDrag ( 519 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 520 PointF(-LARGE_DELTA, LARGE_DELTA)), 521 TopLeftCornerNorthEastDrag ( 522 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 523 PointF(LARGE_DELTA, -LARGE_DELTA)), 524 TopLeftCornerSouthWestDrag ( 525 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 526 PointF(-LARGE_DELTA, LARGE_DELTA)), 527 BottomLeftCornerSouthEastDrag ( 528 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 529 PointF(LARGE_DELTA, LARGE_DELTA)), 530 BottomLeftCornerNorthWestDrag ( 531 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 532 PointF(-LARGE_DELTA, -LARGE_DELTA)), 533 TopRightCornerSouthEastDrag ( 534 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 535 PointF(LARGE_DELTA, LARGE_DELTA)), 536 TopRightCornerNorthWestDrag ( 537 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 538 PointF(-LARGE_DELTA, -LARGE_DELTA)), 539 } 540 541 /** 542 * Tests cases for the moving and ending of a valid corner resize. Where the compass point 543 * (e.g `SouthEast`) represents the direction of the drag, followed by the expected 544 * behaviour in that direction (i.e `RespectY` means the y delta will be respected whereas 545 * `RespectX` means the x delta will be respected). 546 * @param ctrlType the control type of the corner the resize is initiated on. 547 * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s 548 * corresponding corner point. Represented as a combination a different signed small and 549 * large deltas which correspond to the direction/angle of drag. 550 */ 551 enum class ValidCornerResizeTestCases( 552 val ctrlType: Int, 553 val dragDelta: PointF, 554 ) { 555 BottomRightCornerSouthEastDragRespectY ( 556 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 557 PointF(+LARGE_DELTA, SMALL_DELTA)), 558 BottomRightCornerSouthEastDragRespectX ( 559 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 560 PointF(SMALL_DELTA, LARGE_DELTA)), 561 BottomRightCornerNorthWestDragRespectY ( 562 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 563 PointF(-LARGE_DELTA, -SMALL_DELTA)), 564 BottomRightCornerNorthWestDragRespectX ( 565 CTRL_TYPE_BOTTOM + CTRL_TYPE_RIGHT, 566 PointF(-SMALL_DELTA, -LARGE_DELTA)), 567 TopLeftCornerSouthEastDragRespectY ( 568 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 569 PointF(LARGE_DELTA, SMALL_DELTA)), 570 TopLeftCornerSouthEastDragRespectX ( 571 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 572 PointF(SMALL_DELTA, LARGE_DELTA)), 573 TopLeftCornerNorthWestDragRespectY ( 574 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 575 PointF(-LARGE_DELTA, -SMALL_DELTA)), 576 TopLeftCornerNorthWestDragRespectX ( 577 CTRL_TYPE_TOP + CTRL_TYPE_LEFT, 578 PointF(-SMALL_DELTA, -LARGE_DELTA)), 579 BottomLeftCornerSouthWestDragRespectY ( 580 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 581 PointF(-LARGE_DELTA, SMALL_DELTA)), 582 BottomLeftCornerSouthWestDragRespectX ( 583 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 584 PointF(-SMALL_DELTA, LARGE_DELTA)), 585 BottomLeftCornerNorthEastDragRespectY ( 586 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 587 PointF(LARGE_DELTA, -SMALL_DELTA)), 588 BottomLeftCornerNorthEastDragRespectX ( 589 CTRL_TYPE_BOTTOM + CTRL_TYPE_LEFT, 590 PointF(SMALL_DELTA, -LARGE_DELTA)), 591 TopRightCornerSouthWestDragRespectY ( 592 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 593 PointF(-LARGE_DELTA, SMALL_DELTA)), 594 TopRightCornerSouthWestDragRespectX ( 595 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 596 PointF(-SMALL_DELTA, LARGE_DELTA)), 597 TopRightCornerNorthEastDragRespectY ( 598 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 599 PointF(LARGE_DELTA, -SMALL_DELTA)), 600 TopRightCornerNorthEastDragRespectX ( 601 CTRL_TYPE_TOP + CTRL_TYPE_RIGHT, 602 PointF(+SMALL_DELTA, -LARGE_DELTA)) 603 } 604 605 /** 606 * Tests cases for the start of an edge resize. 607 * @param ctrlType the control type of the edge the resize is initiated on. 608 * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl 609 * type. 610 */ 611 enum class EdgeResizeStartTestCases( 612 val ctrlType: Int, 613 val additionalEdgeCtrlType: Int 614 ) { 615 BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM), 616 TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP), 617 BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM), 618 TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP), 619 RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT), 620 LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT), 621 RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT), 622 LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT) 623 } 624 625 /** 626 * Tests cases for the moving and ending of an edge resize. 627 * @param ctrlType the control type of the edge the resize is initiated on. 628 * @param additionalEdgeCtrlType the expected additional edge to be included in the ctrl 629 * type. 630 * @param dragDelta the delta of the attempted drag action, from the [ctrlType]'s 631 * corresponding edge point. Represented as a combination a different signed small and 632 * large deltas which correspond to the direction/angle of drag. 633 */ 634 enum class EdgeResizeTestCases( 635 val ctrlType: Int, 636 val additionalEdgeCtrlType: Int, 637 val dragDelta: PointF 638 ) { 639 BottomOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_BOTTOM, PointF(-SMALL_DELTA, 0f)), 640 TopOfLeftEdgeResize (CTRL_TYPE_LEFT, CTRL_TYPE_TOP, PointF(-SMALL_DELTA, 0f)), 641 BottomOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_BOTTOM, PointF(SMALL_DELTA, 0f)), 642 TopOfRightEdgeResize (CTRL_TYPE_RIGHT, CTRL_TYPE_TOP, PointF(SMALL_DELTA, 0f)), 643 RightOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_RIGHT, PointF(0f, -SMALL_DELTA)), 644 LeftOfTopEdgeResize (CTRL_TYPE_TOP, CTRL_TYPE_LEFT, PointF(0f, -SMALL_DELTA)), 645 RightOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_RIGHT, PointF(0f, SMALL_DELTA)), 646 LeftOfBottomEdgeResize (CTRL_TYPE_BOTTOM, CTRL_TYPE_LEFT, PointF(0f, SMALL_DELTA)) 647 } 648 } 649 } 650