|
1 package org.mozilla.gecko.tests; |
|
2 |
|
3 import android.app.Instrumentation; |
|
4 import android.os.SystemClock; |
|
5 import android.util.FloatMath; |
|
6 import android.util.Log; |
|
7 import android.view.MotionEvent; |
|
8 |
|
9 class MotionEventHelper { |
|
10 private static final String LOGTAG = "RobocopMotionEventHelper"; |
|
11 |
|
12 private static final long DRAG_EVENTS_PER_SECOND = 20; // 20 move events per second when doing a drag |
|
13 |
|
14 private final Instrumentation mInstrumentation; |
|
15 private final int mSurfaceOffsetX; |
|
16 private final int mSurfaceOffsetY; |
|
17 |
|
18 public MotionEventHelper(Instrumentation inst, int surfaceOffsetX, int surfaceOffsetY) { |
|
19 mInstrumentation = inst; |
|
20 mSurfaceOffsetX = surfaceOffsetX; |
|
21 mSurfaceOffsetY = surfaceOffsetY; |
|
22 Log.i(LOGTAG, "Initialized using offset (" + mSurfaceOffsetX + "," + mSurfaceOffsetY + ")"); |
|
23 } |
|
24 |
|
25 public long down(float x, float y) { |
|
26 Log.d(LOGTAG, "Triggering down at (" + x + "," + y + ")"); |
|
27 long downTime = SystemClock.uptimeMillis(); |
|
28 MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0); |
|
29 try { |
|
30 mInstrumentation.sendPointerSync(event); |
|
31 } finally { |
|
32 event.recycle(); |
|
33 event = null; |
|
34 } |
|
35 return downTime; |
|
36 } |
|
37 |
|
38 public long move(long downTime, float x, float y) { |
|
39 return move(downTime, SystemClock.uptimeMillis(), x, y); |
|
40 } |
|
41 |
|
42 public long move(long downTime, long moveTime, float x, float y) { |
|
43 Log.d(LOGTAG, "Triggering move to (" + x + "," + y + ")"); |
|
44 MotionEvent event = MotionEvent.obtain(downTime, moveTime, MotionEvent.ACTION_MOVE, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0); |
|
45 try { |
|
46 mInstrumentation.sendPointerSync(event); |
|
47 } finally { |
|
48 event.recycle(); |
|
49 event = null; |
|
50 } |
|
51 return downTime; |
|
52 } |
|
53 |
|
54 public long up(long downTime, float x, float y) { |
|
55 return up(downTime, SystemClock.uptimeMillis(), x, y); |
|
56 } |
|
57 |
|
58 public long up(long downTime, long upTime, float x, float y) { |
|
59 Log.d(LOGTAG, "Triggering up at (" + x + "," + y + ")"); |
|
60 MotionEvent event = MotionEvent.obtain(downTime, upTime, MotionEvent.ACTION_UP, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0); |
|
61 try { |
|
62 mInstrumentation.sendPointerSync(event); |
|
63 } finally { |
|
64 event.recycle(); |
|
65 event = null; |
|
66 } |
|
67 return -1L; |
|
68 } |
|
69 |
|
70 public Thread dragAsync(final float startX, final float startY, final float endX, final float endY, final long durationMillis) { |
|
71 Thread t = new Thread() { |
|
72 @Override |
|
73 public void run() { |
|
74 int numEvents = (int)(durationMillis * DRAG_EVENTS_PER_SECOND / 1000); |
|
75 float eventDx = (endX - startX) / numEvents; |
|
76 float eventDy = (endY - startY) / numEvents; |
|
77 long downTime = down(startX, startY); |
|
78 for (int i = 0; i < numEvents - 1; i++) { |
|
79 downTime = move(downTime, startX + (eventDx * i), startY + (eventDy * i)); |
|
80 try { |
|
81 Thread.sleep(1000L / DRAG_EVENTS_PER_SECOND); |
|
82 } catch (InterruptedException ie) { |
|
83 ie.printStackTrace(); |
|
84 } |
|
85 } |
|
86 // sleep a bit before sending the last move so that the calculated |
|
87 // fling velocity is low and we don't end up doing a fling afterwards. |
|
88 try { |
|
89 Thread.sleep(1000L); |
|
90 } catch (InterruptedException ie) { |
|
91 ie.printStackTrace(); |
|
92 } |
|
93 // do the last one using endX/endY directly to avoid rounding errors |
|
94 downTime = move(downTime, endX, endY); |
|
95 downTime = up(downTime, endX, endY); |
|
96 } |
|
97 }; |
|
98 t.start(); |
|
99 return t; |
|
100 } |
|
101 |
|
102 public void dragSync(float startX, float startY, float endX, float endY, long durationMillis) { |
|
103 try { |
|
104 dragAsync(startX, startY, endX, endY, durationMillis).join(); |
|
105 mInstrumentation.waitForIdleSync(); |
|
106 } catch (InterruptedException ie) { |
|
107 ie.printStackTrace(); |
|
108 } |
|
109 } |
|
110 |
|
111 public void dragSync(float startX, float startY, float endX, float endY) { |
|
112 dragSync(startX, startY, endX, endY, 1000); |
|
113 } |
|
114 |
|
115 public Thread flingAsync(final float startX, final float startY, final float endX, final float endY, final float velocity) { |
|
116 // note that the first move after the touch-down is used to get over the panning threshold, and |
|
117 // is basically cancelled out. this means we need to generate (at least) two move events, with |
|
118 // the last move event hitting the target velocity. to do this we just slice the total distance |
|
119 // in half, assuming the first half will get us over the panning threshold and the second half |
|
120 // will trigger the fling. |
|
121 final float dx = (endX - startX) / 2; |
|
122 final float dy = (endY - startY) / 2; |
|
123 float distance = FloatMath.sqrt((dx * dx) + (dy * dy)); |
|
124 final long time = (long)(distance / velocity); |
|
125 if (time <= 0) { |
|
126 throw new IllegalArgumentException( "Fling parameters require too small a time period" ); |
|
127 } |
|
128 Thread t = new Thread() { |
|
129 @Override |
|
130 public void run() { |
|
131 long downTime = down(startX, startY); |
|
132 downTime = move(downTime, downTime + time, startX + dx, startY + dy); |
|
133 downTime = move(downTime, downTime + time + time, endX, endY); |
|
134 downTime = up(downTime, downTime + time, endX, endY); |
|
135 } |
|
136 }; |
|
137 t.start(); |
|
138 return t; |
|
139 } |
|
140 |
|
141 public void flingSync(float startX, float startY, float endX, float endY, float velocity) { |
|
142 try { |
|
143 flingAsync(startX, startY, endX, endY, velocity).join(); |
|
144 mInstrumentation.waitForIdleSync(); |
|
145 } catch (InterruptedException ie) { |
|
146 ie.printStackTrace(); |
|
147 } |
|
148 } |
|
149 |
|
150 public void tap(float x, float y) { |
|
151 long downTime = down(x, y); |
|
152 downTime = up(downTime, x, y); |
|
153 } |
|
154 |
|
155 public void doubleTap(float x, float y) { |
|
156 tap(x, y); |
|
157 tap(x, y); |
|
158 } |
|
159 } |