1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 package org
.chromium
.chromoting
;
7 import android
.content
.Context
;
8 import android
.os
.SystemClock
;
9 import android
.test
.InstrumentationTestCase
;
10 import android
.test
.suitebuilder
.annotation
.SmallTest
;
11 import android
.view
.InputDevice
;
12 import android
.view
.MotionEvent
;
13 import android
.view
.ViewConfiguration
;
15 import org
.chromium
.base
.test
.util
.Feature
;
17 /** Tests for {@link SwipePinchDetector}. */
18 public class SwipePinchDetectorTest
extends InstrumentationTestCase
{
19 private SwipePinchDetector mDetector
;
20 private float mTouchSlop
;
21 private MotionEvent
.PointerProperties
[] mPointers
;
23 // Stores the current finger positions, for convenience in writing tests. These values are
24 // initialized during setUp().
25 private MotionEvent
.PointerCoords
[] mCurrentPositions
;
29 Context context
= getInstrumentation().getTargetContext();
30 mDetector
= new SwipePinchDetector(context
);
31 mTouchSlop
= ViewConfiguration
.get(context
).getScaledTouchSlop();
32 MotionEvent
.PointerProperties pointer0
= new MotionEvent
.PointerProperties();
34 MotionEvent
.PointerProperties pointer1
= new MotionEvent
.PointerProperties();
36 mPointers
= new MotionEvent
.PointerProperties
[] {pointer0
, pointer1
};
38 MotionEvent
.PointerCoords position0
= new MotionEvent
.PointerCoords();
39 MotionEvent
.PointerCoords position1
= new MotionEvent
.PointerCoords();
40 mCurrentPositions
= new MotionEvent
.PointerCoords
[] {position0
, position1
};
42 // The starting points are arbitrary, but non-zero to ensure that the tests detect relative,
43 // not absolute, motion.
44 mCurrentPositions
[0].x
= 100;
45 mCurrentPositions
[0].y
= 200;
46 mCurrentPositions
[1].x
= 300;
47 mCurrentPositions
[1].y
= 400;
51 * Simulates a 2-finger event. The action parameter should be MotionEvent.ACTION_POINTER_DOWN,
52 * MotionEvent.ACTION_MOVE or MotionEvent.ACTION_POINTER_UP.
54 private void injectEvent(int action
) {
55 final long eventTime
= SystemClock
.uptimeMillis();
56 MotionEvent event
= MotionEvent
.obtain(eventTime
, eventTime
, action
, 2, mPointers
,
57 mCurrentPositions
, 0, 0, 1, 1, 0, 0, InputDevice
.SOURCE_TOUCHSCREEN
, 0);
58 mDetector
.onTouchEvent(event
);
61 /** Verifies that a simple swipe gesture is recognized as a swipe. */
63 @Feature({"Chromoting"})
64 public void testSwipeRecognition() throws Exception
{
65 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
66 assertFalse(mDetector
.isSwiping());
67 assertFalse(mDetector
.isPinching());
69 // Any distance greater than the touch-slop threshold should work.
70 mCurrentPositions
[0].y
+= mTouchSlop
* 2;
71 mCurrentPositions
[1].y
+= mTouchSlop
* 2;
72 injectEvent(MotionEvent
.ACTION_MOVE
);
73 assertTrue(mDetector
.isSwiping());
74 assertFalse(mDetector
.isPinching());
77 /** Verifies that a simple pinch gesture is recognized. */
79 @Feature({"Chromoting"})
80 public void testPinchRecognition() throws Exception
{
81 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
82 assertFalse(mDetector
.isSwiping());
83 assertFalse(mDetector
.isPinching());
85 // Any distance greater than the touch-slop threshold should work.
86 mCurrentPositions
[0].x
-= mTouchSlop
* 2;
87 mCurrentPositions
[1].x
+= mTouchSlop
* 2;
88 injectEvent(MotionEvent
.ACTION_MOVE
);
89 assertFalse(mDetector
.isSwiping());
90 assertTrue(mDetector
.isPinching());
93 /** Verifies that motion less than touch-slop does not trigger anything. */
95 @Feature({"Chromoting"})
96 public void testNoMotion() throws Exception
{
97 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
98 mCurrentPositions
[0].x
+= mTouchSlop
/ 2;
99 mCurrentPositions
[0].y
+= mTouchSlop
/ 2;
100 mCurrentPositions
[1].x
-= mTouchSlop
/ 2;
101 mCurrentPositions
[1].y
-= mTouchSlop
/ 2;
102 injectEvent(MotionEvent
.ACTION_MOVE
);
103 assertFalse(mDetector
.isSwiping());
104 assertFalse(mDetector
.isPinching());
107 /** Verifies that a pinch with one finger stationary is detected. */
109 @Feature({"Chromoting"})
110 public void testOneFingerStationary() throws Exception
{
111 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
113 // The triggering threshold in this case (one finger stationary) is mTouchSlop * 2;
114 mCurrentPositions
[1].x
+= mTouchSlop
* 3;
115 injectEvent(MotionEvent
.ACTION_MOVE
);
116 assertFalse(mDetector
.isSwiping());
117 assertTrue(mDetector
.isPinching());
119 // Do the same test for the other finger.
120 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
121 mCurrentPositions
[0].x
+= mTouchSlop
* 3;
122 injectEvent(MotionEvent
.ACTION_MOVE
);
123 assertFalse(mDetector
.isSwiping());
124 assertTrue(mDetector
.isPinching());
128 * Verifies that a pinch is recognized, when the fingers cross the motion threshold at
132 @Feature({"Chromoting"})
133 public void testUnevenPinch() throws Exception
{
134 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
135 for (int i
= 0; i
< 50; i
++) {
136 mCurrentPositions
[0].x
-= 2;
137 mCurrentPositions
[1].x
+= 3;
138 injectEvent(MotionEvent
.ACTION_MOVE
);
141 assertFalse(mDetector
.isSwiping());
142 assertTrue(mDetector
.isPinching());
145 /** Same test as testUnevenPinch() except the slow/fast fingers are reversed. */
147 @Feature({"Chromoting"})
148 public void testUnevenPinch2() throws Exception
{
149 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
150 for (int i
= 0; i
< 50; i
++) {
151 mCurrentPositions
[0].x
-= 3;
152 mCurrentPositions
[1].x
+= 2;
153 injectEvent(MotionEvent
.ACTION_MOVE
);
156 assertFalse(mDetector
.isSwiping());
157 assertTrue(mDetector
.isPinching());
160 /** Verifies that a swipe is recognized, even if the fingers move at different rates. */
162 @Feature({"Chromoting"})
163 public void testUnevenSwipe() throws Exception
{
164 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
165 for (int i
= 0; i
< 50; i
++) {
166 // The fingers need to move similarly enough so that one finger moves a distance of
167 // 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
168 // Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
169 mCurrentPositions
[0].y
+= 2;
170 mCurrentPositions
[1].y
+= 3;
171 injectEvent(MotionEvent
.ACTION_MOVE
);
174 assertTrue(mDetector
.isSwiping());
175 assertFalse(mDetector
.isPinching());
178 /** Same test as testUnevenSwipe() except the slow/fast fingers are reversed. */
180 @Feature({"Chromoting"})
181 public void testUnevenSwipe2() throws Exception
{
182 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
183 for (int i
= 0; i
< 50; i
++) {
184 // The fingers need to move similarly enough so that one finger moves a distance of
185 // 2 * mTouchSlop after the other finger moves a distance of mTouchSlop.
186 // Otherwise the gesture would be mis-detected as a one-finger-stationary pinch.
187 mCurrentPositions
[0].y
+= 3;
188 mCurrentPositions
[1].y
+= 2;
189 injectEvent(MotionEvent
.ACTION_MOVE
);
192 assertTrue(mDetector
.isSwiping());
193 assertFalse(mDetector
.isPinching());
196 /** Verifies that the detector is reset when a gesture terminates or a new gesture begins. */
198 @Feature({"Chromoting"})
199 public void testDetectorReset() throws Exception
{
200 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
201 mCurrentPositions
[0].x
+= mTouchSlop
* 3;
202 injectEvent(MotionEvent
.ACTION_MOVE
);
203 assertTrue(mDetector
.isPinching());
205 // ACTION_POINTER_UP should terminate the gesture.
206 injectEvent(MotionEvent
.ACTION_POINTER_UP
);
207 assertFalse(mDetector
.isPinching());
209 // Repeat the same test, but use ACTION_POINTER_DOWN to start a new gesture, which should
210 // terminate the current one.
211 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
212 mCurrentPositions
[0].x
+= mTouchSlop
* 3;
213 injectEvent(MotionEvent
.ACTION_MOVE
);
214 assertTrue(mDetector
.isPinching());
215 injectEvent(MotionEvent
.ACTION_POINTER_DOWN
);
216 assertFalse(mDetector
.isPinching());