package net.osmand.plus.views;
import java.lang.reflect.Method;
import net.osmand.LogUtil;
import org.apache.commons.logging.Log;
import android.content.Context;
import android.graphics.PointF;
import android.util.FloatMath;
import android.view.MotionEvent;
public class MultiTouchSupport {
private static final Log log = LogUtil.getLog(MultiTouchSupport.class);
public static final int ACTION_MASK = 255;
public static final int ACTION_POINTER_ID_SHIFT = 8;
public static final int ACTION_POINTER_DOWN = 5;
public static final int ACTION_POINTER_UP = 6;
public interface MultiTouchZoomListener {
public void onZoomStarted(float distance, PointF centerPoint);
public void onZooming(float distance, float relativeToStart);
public void onZoomEnded(float distance, float relativeToStart);
}
private boolean multiTouchAPISupported = false;
private final MultiTouchZoomListener listener;
protected final Context ctx;
protected Method getPointerCount;
protected Method getX;
protected Method getY;
protected Method getPointerId;
public MultiTouchSupport(Context ctx, MultiTouchZoomListener listener){
this.ctx = ctx;
this.listener = listener;
initMethods();
}
public boolean isMultiTouchSupported(){
return multiTouchAPISupported;
}
public boolean isInZoomMode(){
return inZoomMode;
}
private void initMethods(){
try {
getPointerCount = MotionEvent.class.getMethod("getPointerCount"); //$NON-NLS-1$
getPointerId = MotionEvent.class.getMethod("getPointerId", Integer.TYPE); //$NON-NLS-1$
getX = MotionEvent.class.getMethod("getX", Integer.TYPE); //$NON-NLS-1$
getY = MotionEvent.class.getMethod("getY", Integer.TYPE); //$NON-NLS-1$
multiTouchAPISupported = true;
} catch (Exception e) {
multiTouchAPISupported = false;
log.info("Multi touch not supported", e); //$NON-NLS-1$
}
}
private boolean inZoomMode = false;
private float zoomStartedDistance = 100;
private float previousZoom = 1;
private PointF centerPoint = new PointF();
public boolean onTouchEvent(MotionEvent event){
if(!isMultiTouchSupported()){
return false;
}
int actionCode = event.getAction() & ACTION_MASK;
try {
Integer pointCount = (Integer) getPointerCount.invoke(event);
if(pointCount < 2){
if(inZoomMode){
listener.onZoomEnded(zoomStartedDistance * previousZoom, previousZoom);
}
return false;
}
Float x1 = (Float) getX.invoke(event, 0);
Float x2 = (Float) getX.invoke(event, 1);
Float y1 = (Float) getY.invoke(event, 0);
Float y2 = (Float) getY.invoke(event, 1);
float distance = FloatMath.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
previousZoom = distance / zoomStartedDistance;
if (actionCode == ACTION_POINTER_DOWN) {
centerPoint = new PointF((x1 + x2) / 2, (y1 + y2) / 2);
listener.onZoomStarted(distance, centerPoint);
zoomStartedDistance = distance;
inZoomMode = true;
return true;
} else if(actionCode == ACTION_POINTER_UP){
if(inZoomMode){
listener.onZoomEnded(distance, previousZoom);
inZoomMode = false;
}
return true;
} else if(inZoomMode && actionCode == MotionEvent.ACTION_MOVE){
listener.onZooming(distance, previousZoom);
return true;
}
} catch (Exception e) {
log.debug("Multi touch exception" , e); //$NON-NLS-1$
}
return false;
}
}