diff options
-rw-r--r-- | core/java/android/view/ScaleGestureDetector.java | 105 |
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; } /** |