package org.ebookdroid.common.touch;
import android.annotation.TargetApi;
import android.graphics.PointF;
import android.util.FloatMath;
import android.view.MotionEvent;
import org.emdev.common.log.LogContext;
import org.emdev.common.log.LogManager;
@TargetApi(5)
public class MultiTouchGestureDetector implements IGestureDetector {
protected static final LogContext LCTX = LogManager.root().lctx("Gesture", false);
private final IMultiTouchListener listener;
private float twoFingerDistance;
private boolean multiEventCatched;
private PointF multiCenter;
private boolean twoFingerPress = false;
private boolean twoFingerMove = false;
public MultiTouchGestureDetector(final IMultiTouchListener listener) {
this.listener = listener;
}
@Override
public boolean enabled() {
return true;
}
@Override
public boolean onTouchEvent(final MotionEvent ev) {
if ((ev.getAction() & MotionEvent.ACTION_POINTER_DOWN) == MotionEvent.ACTION_POINTER_DOWN) {
if (LCTX.isDebugEnabled()) {
LCTX.d("onTouchEvent(pointer down, " + ev.getPointerCount() + "): " + twoFingerPress + ", "
+ twoFingerMove);
}
switch (ev.getPointerCount()) {
case 2:
if (getTwoFingerDistance(ev) > 25){
twoFingerDistance = getTwoFingerDistance(ev);
twoFingerPress = true;
twoFingerMove = false;
}
break;
default:
twoFingerPress = false;
twoFingerMove = false;
twoFingerDistance = 0;
}
multiCenter = calculateCenter(ev);
multiEventCatched = true;
return true;
}
if (ev.getAction() == MotionEvent.ACTION_MOVE) {
if (LCTX.isDebugEnabled()) {
LCTX.d("onTouchEvent(move, " + ev.getPointerCount() + "): " + twoFingerPress + ", "
+ twoFingerMove);
}
if (twoFingerPress && ev.getPointerCount() == 2) {
final PointF newCenter = calculateCenter(ev);
// First time movement distance should be more than 10, next - without limitation
if (distance(newCenter, multiCenter) > 10.0f || twoFingerMove) {
final float zoomDistance = getTwoFingerDistance(ev);
listener.onTwoFingerPinch(calculateCenterEvent(ev), twoFingerDistance, zoomDistance);
twoFingerDistance = zoomDistance;
twoFingerMove = true;
}
multiEventCatched = true;
}
return multiEventCatched;
}
if ((ev.getAction() & MotionEvent.ACTION_POINTER_UP) == MotionEvent.ACTION_POINTER_UP) {
if (LCTX.isDebugEnabled()) {
LCTX.d("onTouchEvent(pointer up, " + ev.getPointerCount() + "): " + twoFingerPress + ", "
+ twoFingerMove);
}
if (twoFingerPress && ev.getPointerCount() == 2) {
if (twoFingerMove) {
listener.onTwoFingerPinchEnd(calculateCenterEvent(ev));
twoFingerDistance = 0;
twoFingerMove = false;
} else {
listener.onTwoFingerTap(calculateCenterEvent(ev));
}
twoFingerPress = false;
multiEventCatched = true;
}
twoFingerPress = false;
twoFingerMove = false;
twoFingerDistance = 0;
return true;
}
if (ev.getAction() == MotionEvent.ACTION_UP && multiEventCatched) {
if (LCTX.isDebugEnabled()) {
LCTX.d("onTouchEvent(up, " + ev.getPointerCount() + "): " + twoFingerPress + ", "
+ twoFingerMove);
}
if (twoFingerPress && ev.getPointerCount() < 2) {
// System.out.println("MultiTouchGestureDetector.onTouchEvent(): up pointer");
if (twoFingerMove) {
listener.onTwoFingerPinchEnd(calculateCenterEvent(ev));
} else {
listener.onTwoFingerTap(calculateCenterEvent(ev));
}
}
multiEventCatched = false;
twoFingerPress = false;
twoFingerMove = false;
twoFingerDistance = 0;
return true;
}
return false;
}
private float distance(final PointF p0, final PointF p1) {
return (float) Math.sqrt(((p0.x - p1.x) * (p0.x - p1.x) + (p0.y - p1.y) * (p0.y - p1.y)));
}
private PointF calculateCenter(final MotionEvent ev) {
float x = 0, y = 0;
for (int i = 0; i < ev.getPointerCount(); i++) {
x += ev.getX(i);
y += ev.getY(i);
}
return new PointF(x / ev.getPointerCount(), y / ev.getPointerCount());
}
private MotionEvent calculateCenterEvent(final MotionEvent ev) {
final PointF center = calculateCenter(ev);
final MotionEvent newEvent = MotionEvent.obtain(ev);
newEvent.setLocation(center.x, center.y);
return newEvent;
}
private float getTwoFingerDistance(final MotionEvent ev) {
final float x0 = ev.getX(0);
final float x1 = ev.getX(1);
final float y0 = ev.getY(0);
final float y1 = ev.getY(1);
return (float) Math.sqrt(((x0 - x1) * (x0 - x1) + (y0 - y1) * (y0 - y1)));
}
}