11 package com.freerdp.freerdpcore.utils;
13 import android.content.Context;
14 import android.os.Handler;
15 import android.view.MotionEvent;
16 import android.view.ScaleGestureDetector;
18 import com.freerdp.freerdpcore.utils.GestureDetector.OnGestureListener;
24 private static final long DOUBLE_TOUCH_TIMEOUT = 100;
26 private static final long SINGLE_DOUBLE_TOUCH_TIMEOUT = 1000;
28 private static final int TAP = 1;
30 private static final int MODE_UNKNOWN = 0;
31 private static final int MODE_PINCH_ZOOM = 1;
32 private static final int MODE_SCROLL = 2;
33 private static final int SCROLL_SCORE_TO_REACH = 20;
35 private int mPointerDistanceSquare;
36 private int mCurrentMode;
37 private int mScrollDetectionScore;
38 private ScaleGestureDetector scaleGestureDetector;
39 private boolean mCancelDetection;
40 private boolean mDoubleInProgress;
41 private GestureHandler mHandler;
42 private MotionEvent mCurrentDownEvent;
43 private MotionEvent mCurrentDoubleDownEvent;
44 private MotionEvent mPreviousUpEvent;
45 private MotionEvent mPreviousPointerUpEvent;
59 init(context, handler);
62 private void init(Context context, Handler handler)
64 if (mListener ==
null)
66 throw new NullPointerException(
"OnGestureListener must not be null");
70 mHandler =
new GestureHandler(handler);
72 mHandler =
new GestureHandler();
77 float distInches = 0.5f / 2.54f;
78 float distPixelsX = distInches * context.getResources().getDisplayMetrics().xdpi;
79 float distPixelsY = distInches * context.getResources().getDisplayMetrics().ydpi;
81 mPointerDistanceSquare = (int)(distPixelsX * distPixelsX + distPixelsY * distPixelsY);
91 this.scaleGestureDetector = scaleGestureDetector;
104 boolean handled =
false;
105 final int action = ev.getAction();
108 switch (action & MotionEvent.ACTION_MASK)
110 case MotionEvent.ACTION_DOWN:
111 if (mCurrentDownEvent !=
null)
112 mCurrentDownEvent.recycle();
114 mCurrentMode = MODE_UNKNOWN;
115 mCurrentDownEvent = MotionEvent.obtain(ev);
116 mCancelDetection =
false;
117 mDoubleInProgress =
false;
118 mScrollDetectionScore = 0;
122 case MotionEvent.ACTION_POINTER_UP:
123 if (mPreviousPointerUpEvent !=
null)
124 mPreviousPointerUpEvent.recycle();
125 mPreviousPointerUpEvent = MotionEvent.obtain(ev);
128 case MotionEvent.ACTION_POINTER_DOWN:
131 if (ev.getPointerCount() > 2 ||
132 (ev.getEventTime() - mCurrentDownEvent.getEventTime()) > DOUBLE_TOUCH_TIMEOUT)
139 if (mCancelDetection)
143 mDoubleInProgress =
true;
144 if (mCurrentDoubleDownEvent !=
null)
145 mCurrentDoubleDownEvent.recycle();
146 mCurrentDoubleDownEvent = MotionEvent.obtain(ev);
150 mCurrentMode = MODE_UNKNOWN;
151 mHandler.sendEmptyMessageDelayed(TAP, SINGLE_DOUBLE_TOUCH_TIMEOUT);
156 case MotionEvent.ACTION_MOVE:
159 if (mCancelDetection || !mDoubleInProgress || ev.getPointerCount() != 2)
163 if (mCurrentMode == MODE_UNKNOWN)
166 if (pointerDistanceChanged(mCurrentDoubleDownEvent, ev))
168 handled |= scaleGestureDetector.onTouchEvent(mCurrentDownEvent);
169 MotionEvent e = MotionEvent.obtain(ev);
170 e.setAction(mCurrentDoubleDownEvent.getAction());
171 handled |= scaleGestureDetector.onTouchEvent(e);
172 mCurrentMode = MODE_PINCH_ZOOM;
177 mScrollDetectionScore++;
178 if (mScrollDetectionScore >= SCROLL_SCORE_TO_REACH)
179 mCurrentMode = MODE_SCROLL;
183 switch (mCurrentMode)
185 case MODE_PINCH_ZOOM:
186 if (scaleGestureDetector !=
null)
187 handled |= scaleGestureDetector.onTouchEvent(ev);
201 case MotionEvent.ACTION_UP:
203 if (mPreviousPointerUpEvent !=
null &&
204 (ev.getEventTime() - mPreviousPointerUpEvent.getEventTime()) >
205 DOUBLE_TOUCH_TIMEOUT)
207 mPreviousPointerUpEvent.recycle();
208 mPreviousPointerUpEvent =
null;
214 if (mCancelDetection || !mDoubleInProgress)
217 boolean hasTapEvent = mHandler.hasMessages(TAP);
218 MotionEvent currentUpEvent = MotionEvent.obtain(ev);
219 if (mCurrentMode == MODE_UNKNOWN && hasTapEvent)
221 else if (mCurrentMode == MODE_PINCH_ZOOM)
222 handled = scaleGestureDetector.onTouchEvent(ev);
224 if (mPreviousUpEvent !=
null)
225 mPreviousUpEvent.recycle();
228 mPreviousUpEvent = currentUpEvent;
232 case MotionEvent.ACTION_CANCEL:
237 if ((action == MotionEvent.ACTION_MOVE) && handled ==
false)
243 private void cancel()
245 mHandler.removeMessages(TAP);
246 mCurrentMode = MODE_UNKNOWN;
247 mCancelDetection =
true;
248 mDoubleInProgress =
false;
252 private boolean pointerDistanceChanged(MotionEvent oldEvent, MotionEvent newEvent)
254 int deltaX1 = Math.abs((
int)oldEvent.getX(0) - (
int)oldEvent.getX(1));
255 int deltaX2 = Math.abs((
int)newEvent.getX(0) - (
int)newEvent.getX(1));
256 int distXSquare = (deltaX2 - deltaX1) * (deltaX2 - deltaX1);
258 int deltaY1 = Math.abs((
int)oldEvent.getY(0) - (int)oldEvent.getY(1));
259 int deltaY2 = Math.abs((
int)newEvent.getY(0) - (int)newEvent.getY(1));
260 int distYSquare = (deltaY2 - deltaY1) * (deltaY2 - deltaY1);
262 return (distXSquare + distYSquare) > mPointerDistanceSquare;
338 private class GestureHandler
extends Handler
345 GestureHandler(Handler handler)
347 super(handler.getLooper());
void setScaleGestureDetector(ScaleGestureDetector scaleGestureDetector)
boolean onTouchEvent(MotionEvent ev)
DoubleGestureDetector(Context context, Handler handler, OnDoubleGestureListener listener)
boolean onDoubleTouchScroll(MotionEvent e1, MotionEvent e2)
boolean onDoubleTouchUp(MotionEvent e)
boolean onDoubleTouchDown(MotionEvent e)
boolean onDoubleTouchSingleTap(MotionEvent e)