1
2
3
4
5
6
7
8
9
10
11
12
13
14 package com.googlecode.mgwt.dom.client.recognizer.longtap;
15
16 import com.google.gwt.core.client.GWT;
17 import com.google.gwt.event.shared.HasHandlers;
18 import com.googlecode.mgwt.collection.shared.CollectionFactory;
19 import com.googlecode.mgwt.collection.shared.LightArray;
20 import com.googlecode.mgwt.dom.client.event.touch.Touch;
21 import com.googlecode.mgwt.dom.client.event.touch.TouchCancelEvent;
22 import com.googlecode.mgwt.dom.client.event.touch.TouchEndEvent;
23 import com.googlecode.mgwt.dom.client.event.touch.TouchHandler;
24 import com.googlecode.mgwt.dom.client.event.touch.TouchMoveEvent;
25 import com.googlecode.mgwt.dom.client.event.touch.TouchStartEvent;
26 import com.googlecode.mgwt.dom.client.event.touch.TouchUtil;
27 import com.googlecode.mgwt.dom.client.recognizer.EventPropagator;
28 import com.googlecode.mgwt.dom.client.recognizer.TimerExecturGwtTimerImpl;
29 import com.googlecode.mgwt.dom.client.recognizer.TimerExecutor;
30 import com.googlecode.mgwt.dom.client.recognizer.TimerExecutor.CodeToRun;
31
32
33
34
35
36
37
38 public class LongTapRecognizer implements TouchHandler {
39
40 public static final int DEFAULT_WAIT_TIME_IN_MS = 1500;
41 public static final int DEFAULT_MAX_DISTANCE = 15;
42
43 protected enum State {
44 INVALID, READY, FINGERS_DOWN, FINGERS_UP, WAITING
45 };
46
47 protected State state;
48 private final HasHandlers source;
49 private final int numberOfFingers;
50 private final int time;
51
52 private LightArray<Touch> startPositions;
53 private int touchCount;
54 private final int distance;
55
56 private TimerExecutor timerExecutor;
57
58 private EventPropagator eventPropagator;
59
60 private static EventPropagator DEFAULT_EVENT_PROPAGATOR;
61
62
63
64
65
66
67 public LongTapRecognizer(HasHandlers source) {
68 this(source, 1);
69 }
70
71
72
73
74
75
76
77
78 public LongTapRecognizer(HasHandlers source, int numberOfFingers) {
79 this(source, numberOfFingers, DEFAULT_WAIT_TIME_IN_MS);
80 }
81
82
83
84
85
86
87
88
89 public LongTapRecognizer(HasHandlers source, int numberOfFingers, int time) {
90 this(source, numberOfFingers, time, DEFAULT_MAX_DISTANCE);
91 }
92
93
94
95
96
97
98
99
100
101 public LongTapRecognizer(HasHandlers source, int numberOfFingers, int time, int maxDistance) {
102
103 if (source == null) {
104 throw new IllegalArgumentException("source can not be null");
105 }
106 if (numberOfFingers < 1) {
107 throw new IllegalArgumentException("numberOfFingers > 0");
108 }
109
110 if (time < 200) {
111 throw new IllegalArgumentException("time > 200");
112 }
113
114 if (maxDistance < 0) {
115 throw new IllegalArgumentException("maxDistance > 0");
116 }
117
118 this.source = source;
119 this.numberOfFingers = numberOfFingers;
120 this.time = time;
121 this.distance = maxDistance;
122
123 state = State.READY;
124 startPositions = CollectionFactory.constructArray();
125 touchCount = 0;
126
127 }
128
129
130
131
132
133
134
135
136 @Override
137 public void onTouchStart(TouchStartEvent event) {
138
139 LightArray<Touch> touches = event.getTouches();
140 touchCount++;
141
142 switch (state) {
143 case INVALID:
144 break;
145 case READY:
146 startPositions.push(TouchUtil.cloneTouch(touches.get(touchCount - 1)));
147 state = State.FINGERS_DOWN;
148 break;
149 case FINGERS_DOWN:
150 startPositions.push(TouchUtil.cloneTouch(touches.get(touchCount - 1)));
151 break;
152 case FINGERS_UP:
153 default:
154 state = State.INVALID;
155 break;
156 }
157
158 if (touchCount == numberOfFingers) {
159 state = State.WAITING;
160 getTimerExecutor().execute(new CodeToRun() {
161
162 @Override
163 public void onExecution() {
164 if (state != State.WAITING) {
165
166 return;
167 }
168
169 getEventPropagator().fireEvent(source, new LongTapEvent(source, numberOfFingers, time, startPositions));
170 reset();
171
172 }
173 }, time);
174 }
175
176 if (touchCount > numberOfFingers) {
177 state = State.INVALID;
178 }
179
180 }
181
182
183
184
185
186
187
188
189 @Override
190 public void onTouchMove(TouchMoveEvent event) {
191 switch (state) {
192 case WAITING:
193 case FINGERS_DOWN:
194 case FINGERS_UP:
195
196 LightArray<Touch> currentTouches = event.getTouches();
197 for (int i = 0; i < currentTouches.length(); i++) {
198 Touch currentTouch = currentTouches.get(i);
199 for (int j = 0; j < startPositions.length(); j++) {
200 Touch startTouch = startPositions.get(j);
201 if (currentTouch.getIdentifier() == startTouch.getIdentifier()) {
202 if (Math.abs(currentTouch.getPageX() - startTouch.getPageX()) > distance || Math.abs(currentTouch.getPageY() - startTouch.getPageY()) > distance) {
203 state = State.INVALID;
204 break;
205 }
206 }
207 if (state == State.INVALID) {
208 break;
209 }
210 }
211 }
212
213 break;
214
215 default:
216 state = State.INVALID;
217 break;
218 }
219
220 }
221
222
223
224
225
226
227
228
229 @Override
230 public void onTouchEnd(TouchEndEvent event) {
231 int currentTouches = event.getTouches().length();
232 switch (state) {
233 case WAITING:
234 state = State.INVALID;
235 break;
236
237 case FINGERS_DOWN:
238 state = State.FINGERS_UP;
239 break;
240 case FINGERS_UP:
241
242 if (currentTouches == 0 && touchCount == numberOfFingers) {
243
244
245 reset();
246 }
247 break;
248
249 case INVALID:
250 default:
251 if (currentTouches == 0)
252 reset();
253 break;
254 }
255
256 }
257
258
259
260
261
262
263
264
265 @Override
266 public void onTouchCanceled(TouchCancelEvent event) {
267 state = State.INVALID;
268 int currentTouches = event.getTouches().length();
269 if (currentTouches == 0)
270 reset();
271 }
272
273
274
275
276
277
278 protected void setTimerExecutor(TimerExecutor timerExecutor) {
279 this.timerExecutor = timerExecutor;
280 }
281
282
283
284
285
286
287 protected void setEventPropagator(EventPropagator eventPropagator) {
288 this.eventPropagator = eventPropagator;
289
290 }
291
292 protected TimerExecutor getTimerExecutor() {
293 if (timerExecutor == null) {
294 timerExecutor = new TimerExecturGwtTimerImpl();
295 }
296 return timerExecutor;
297 }
298
299 protected void reset() {
300 state = State.READY;
301 touchCount = 0;
302 }
303
304 protected EventPropagator getEventPropagator() {
305 if (eventPropagator == null) {
306 if (DEFAULT_EVENT_PROPAGATOR == null) {
307 DEFAULT_EVENT_PROPAGATOR = GWT.create(EventPropagator.class);
308 }
309 eventPropagator = DEFAULT_EVENT_PROPAGATOR;
310 }
311 return eventPropagator;
312 }
313
314 }