package carbon;
import android.os.Handler;
import android.view.MotionEvent;
public class GestureDetector {
private static final int DEFAULT_PRESS_TIMEOUT = 100;
private static final int DEFAULT_TAP_TIMEOUT = 300;
private static final int DEFAULT_MOVE_EPSILON = 4;
private int pressTimeout = DEFAULT_PRESS_TIMEOUT;
private int tapTimeout = DEFAULT_TAP_TIMEOUT;
private int moveEpsilon = DEFAULT_MOVE_EPSILON;
private Handler handler;
private Runnable tapHandler;
private Runnable pressHandler;
private final OnGestureListener listener;
private long prevTouchTime;
private float prevTouchY;
private float prevTouchX;
boolean verticalMoveCancel = true;
boolean horizontalMoveCancel = true;
private boolean dragging;
private boolean moving;
private Runnable longPressHandler;
private long longPressTimeout = 200;
private int clicks = 0;
private boolean pressed;
public GestureDetector(OnGestureListener listener) {
if (listener == null)
throw new NullPointerException("Listener cannot be null");
this.listener = listener;
handler = new Handler();
}
public void onTouchEvent(final MotionEvent motionEvent) {
final MotionEvent event = MotionEvent.obtain(motionEvent);
float dx = motionEvent.getX() - prevTouchX;
float dy = motionEvent.getY() - prevTouchY;
long time = System.currentTimeMillis();
long dt = System.currentTimeMillis() - prevTouchTime;
handler.removeCallbacks(longPressHandler);
longPressHandler = null;
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_DOWN:
dragging = false;
moving = false;
pressed = true;
if (tapHandler != null) {
clicks++;
handler.removeCallbacks(tapHandler);
tapHandler = null;
}
handler.removeCallbacks(pressHandler);
pressHandler = () -> {
// handler.removeCallbacks(tapHandler);
// tapHandler = null;
onPress(event);
};
handler.postDelayed(pressHandler, pressTimeout);
longPressHandler = () -> onLongPress(event);
handler.removeCallbacks(longPressHandler);
handler.postDelayed(longPressHandler, longPressTimeout);
prevTouchTime = time;
break;
case MotionEvent.ACTION_UP:
if (pressed || moving || dragging) {
if (pressHandler != null) {
handler.removeCallbacks(pressHandler);
pressHandler.run();
}
onRelease(event);
//break;
}
//TODO: tapping is broken
/*tapHandler = new Runnable() {
@Override
public void run() {
handler.removeCallbacks(longPressHandler);
longPressHandler = null;
onTap(motionEvent, clicks);
}
};
handler.postDelayed(tapHandler, tapTimeout - dt);*/
pressed = false;
prevTouchTime = time;
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(dx) > moveEpsilon || Math.abs(dy) > moveEpsilon || dragging || moving) {
if (pressHandler == null && !moving) {
dragging = true;
}
handler.removeCallbacks(tapHandler);
tapHandler = null;
handler.removeCallbacks(pressHandler);
pressHandler = null;
handler.removeCallbacks(longPressHandler);
longPressHandler = null;
moving = true;
if (dragging) {
onDrag(event);
} else {
onMove(event);
}
}
break;
case MotionEvent.ACTION_CANCEL:
pressed = false;
handler.removeCallbacks(pressHandler);
pressHandler = null;
handler.removeCallbacks(tapHandler);
tapHandler = null;
handler.removeCallbacks(longPressHandler);
longPressHandler = null;
onCancel(event);
}
prevTouchX = motionEvent.getX();
prevTouchY = motionEvent.getY();
}
private void onCancel(MotionEvent motionEvent) {
clicks = 0;
listener.onCancel(motionEvent);
}
private void onRelease(MotionEvent motionEvent) {
clicks = 0;
listener.onRelease(motionEvent);
}
private void onDrag(MotionEvent motionEvent) {
clicks = 0;
listener.onDrag(motionEvent);
}
private void onMove(MotionEvent motionEvent) {
clicks = 0;
listener.onMove(motionEvent);
}
protected void onTap(MotionEvent motionEvent, int clicks) {
tapHandler = null;
if (clicks == 0) {
listener.onTap(motionEvent);
} else {
listener.onMultiTap(motionEvent, clicks + 1);
}
this.clicks = 0;
}
protected void onLongPress(MotionEvent motionEvent) {
clicks = 0;
longPressHandler = null;
listener.onLongPress(motionEvent);
}
protected void onPress(MotionEvent motionEvent) {
pressHandler = null;
listener.onPress(motionEvent);
}
public int getPressTimeout() {
return pressTimeout;
}
public void setPressTimeout(int pressTimeout) {
this.pressTimeout = pressTimeout;
}
public int getTapTimeout() {
return tapTimeout;
}
public void setTapTimeout(int tapTimeout) {
this.tapTimeout = tapTimeout;
}
public int getMoveEpsilon() {
return moveEpsilon;
}
public void setMoveEpsilon(int moveEpsilon) {
this.moveEpsilon = moveEpsilon;
}
public long getLongPressTimeout() {
return longPressTimeout;
}
public void setLongPressTimeout(long longPressTimeout) {
this.longPressTimeout = longPressTimeout;
}
}