• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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