Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 package org.mozilla.gecko.tests;
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;
9 class MotionEventHelper {
10 private static final String LOGTAG = "RobocopMotionEventHelper";
12 private static final long DRAG_EVENTS_PER_SECOND = 20; // 20 move events per second when doing a drag
14 private final Instrumentation mInstrumentation;
15 private final int mSurfaceOffsetX;
16 private final int mSurfaceOffsetY;
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 }
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 }
38 public long move(long downTime, float x, float y) {
39 return move(downTime, SystemClock.uptimeMillis(), x, y);
40 }
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 }
54 public long up(long downTime, float x, float y) {
55 return up(downTime, SystemClock.uptimeMillis(), x, y);
56 }
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 }
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 }
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 }
111 public void dragSync(float startX, float startY, float endX, float endY) {
112 dragSync(startX, startY, endX, endY, 1000);
113 }
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 }
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 }
150 public void tap(float x, float y) {
151 long downTime = down(x, y);
152 downTime = up(downTime, x, y);
153 }
155 public void doubleTap(float x, float y) {
156 tap(x, y);
157 tap(x, y);
158 }
159 }