summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ScaleGestureDetector.java105
1 files changed, 95 insertions, 10 deletions
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 2da8f14..50bfefc 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -17,6 +17,8 @@
package android.view;
import android.content.Context;
+import android.util.DisplayMetrics;
+import android.util.Log;
/**
* Detects transformation gestures involving more than one pointer ("multitouch")
@@ -137,10 +139,20 @@ public class ScaleGestureDetector {
private float mCurrPressure;
private float mPrevPressure;
private long mTimeDelta;
+
+ private float mEdgeSlop;
+ private float mRightSlopEdge;
+ private float mBottomSlopEdge;
+ private boolean mSloppyGesture;
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
+ ViewConfiguration config = ViewConfiguration.get(context);
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
mContext = context;
mListener = listener;
+ mEdgeSlop = config.getScaledEdgeSlop();
+ mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
+ mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
}
public boolean onTouchEvent(MotionEvent event) {
@@ -152,15 +164,68 @@ public class ScaleGestureDetector {
action == MotionEvent.ACTION_POINTER_2_DOWN) &&
event.getPointerCount() >= 2) {
// We have a new multi-finger gesture
-
+
// Be paranoid in case we missed an event
reset();
-
+
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
-
+
setContext(event);
- mGestureInProgress = mListener.onScaleBegin(this);
+
+ // Check if we have a sloppy gesture. If so, delay
+ // the beginning of the gesture until we're sure that's
+ // what the user wanted. Sloppy gestures can happen if the
+ // edge of the user's hand is touching the screen, for example.
+ final float edgeSlop = mEdgeSlop;
+ final float rightSlop = mRightSlopEdge;
+ final float bottomSlop = mBottomSlopEdge;
+ final float x0 = event.getRawX();
+ final float y0 = event.getRawY();
+ final float x1 = getRawX(event, 1);
+ final float y1 = getRawY(event, 1);
+
+ boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop ||
+ x1 < edgeSlop || y1 < edgeSlop;
+ boolean p1sloppy = x0 > rightSlop || y0 > bottomSlop ||
+ x1 > rightSlop || y1 > bottomSlop;
+
+ if (p0sloppy) {
+ mFocusX = event.getX(1);
+ mFocusY = event.getY(1);
+ mSloppyGesture = true;
+ } else if (p1sloppy) {
+ mFocusX = event.getX(0);
+ mFocusY = event.getY(0);
+ mSloppyGesture = true;
+ } else {
+ mGestureInProgress = mListener.onScaleBegin(this);
+ }
+ } else if (action == MotionEvent.ACTION_MOVE && mSloppyGesture) {
+ // Initiate sloppy gestures if we've moved outside of the slop area.
+ final float edgeSlop = mEdgeSlop;
+ final float rightSlop = mRightSlopEdge;
+ final float bottomSlop = mBottomSlopEdge;
+ final float x0 = event.getRawX();
+ final float y0 = event.getRawY();
+ final float x1 = getRawX(event, 1);
+ final float y1 = getRawY(event, 1);
+
+ boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop ||
+ x1 < edgeSlop || y1 < edgeSlop;
+ boolean p1sloppy = x0 > rightSlop || y0 > bottomSlop ||
+ x1 > rightSlop || y1 > bottomSlop;
+
+ if (p0sloppy) {
+ mFocusX = event.getX(1);
+ mFocusY = event.getY(1);
+ } else if (p1sloppy) {
+ mFocusX = event.getX(0);
+ mFocusY = event.getY(0);
+ } else {
+ mSloppyGesture = false;
+ mGestureInProgress = mListener.onScaleBegin(this);
+ }
}
} else {
// Transform gesture in progress - attempt to handle it
@@ -169,22 +234,24 @@ public class ScaleGestureDetector {
case MotionEvent.ACTION_POINTER_2_UP:
// Gesture ended
setContext(event);
-
+
// Set focus point to the remaining finger
int id = (((action & MotionEvent.ACTION_POINTER_ID_MASK)
>> MotionEvent.ACTION_POINTER_ID_SHIFT) == 0) ? 1 : 0;
mFocusX = event.getX(id);
mFocusY = event.getY(id);
-
- mListener.onScaleEnd(this);
- mGestureInProgress = false;
+
+ if (!mSloppyGesture) {
+ mListener.onScaleEnd(this);
+ }
reset();
break;
case MotionEvent.ACTION_CANCEL:
- mListener.onScaleEnd(this);
- mGestureInProgress = false;
+ if (!mSloppyGesture) {
+ mListener.onScaleEnd(this);
+ }
reset();
break;
@@ -208,6 +275,22 @@ public class ScaleGestureDetector {
}
return handled;
}
+
+ /**
+ * MotionEvent has no getRawX(int) method; simulate it pending future API approval.
+ */
+ private static float getRawX(MotionEvent event, int pointerIndex) {
+ float offset = event.getX() - event.getRawX();
+ return event.getX(pointerIndex) + offset;
+ }
+
+ /**
+ * MotionEvent has no getRawY(int) method; simulate it pending future API approval.
+ */
+ private static float getRawY(MotionEvent event, int pointerIndex) {
+ float offset = event.getY() - event.getRawY();
+ return event.getY(pointerIndex) + offset;
+ }
private void setContext(MotionEvent curr) {
if (mCurrEvent != null) {
@@ -255,6 +338,8 @@ public class ScaleGestureDetector {
mCurrEvent.recycle();
mCurrEvent = null;
}
+ mSloppyGesture = false;
+ mGestureInProgress = false;
}
/**