summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2011-02-24 17:19:20 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-02-24 17:19:20 -0800
commit78b1dc594e53120ba7817d9ceb6a340278186891 (patch)
tree5d5520316bbd4ebb7271d3c9e04597cb8cc59e69 /core/java
parent30b1fe07a73d522e97b7140cc227232a0c8c1a1e (diff)
parente33cef8037cb87386e17bcf8701a47452d262fa6 (diff)
downloadframeworks_base-78b1dc594e53120ba7817d9ceb6a340278186891.zip
frameworks_base-78b1dc594e53120ba7817d9ceb6a340278186891.tar.gz
frameworks_base-78b1dc594e53120ba7817d9ceb6a340278186891.tar.bz2
Merge "Ensure WebView passes a complete/in-order event stream to ScaleGestureDetector. Prerequisite for several ScaleGestureDetector bugfixes."
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/view/ScaleGestureDetector.java254
-rw-r--r--core/java/android/webkit/WebView.java27
2 files changed, 209 insertions, 72 deletions
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index 17b5dd7..218ee4f 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -154,6 +154,11 @@ public class ScaleGestureDetector {
private float mBottomSlopEdge;
private boolean mSloppyGesture;
+ // Pointer IDs currently responsible for the two fingers controlling the gesture
+ private int mActiveId0;
+ private int mActiveId1;
+ private boolean mActive0MostRecent;
+
public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
ViewConfiguration config = ViewConfiguration.get(context);
mContext = context;
@@ -162,11 +167,21 @@ public class ScaleGestureDetector {
}
public boolean onTouchEvent(MotionEvent event) {
- final int action = event.getAction();
+ final int action = event.getActionMasked();
boolean handled = true;
if (!mGestureInProgress) {
- switch (action & MotionEvent.ACTION_MASK) {
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ mActiveId0 = event.getPointerId(0);
+ mActive0MostRecent = true;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ reset();
+ break;
+
case MotionEvent.ACTION_POINTER_DOWN: {
// We have a new multi-finger gesture
@@ -175,12 +190,15 @@ public class ScaleGestureDetector {
mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
- // Be paranoid in case we missed an event
- reset();
-
+ if (mPrevEvent != null) mPrevEvent.recycle();
mPrevEvent = MotionEvent.obtain(event);
mTimeDelta = 0;
+ int index1 = event.getActionIndex();
+ int index0 = event.findPointerIndex(mActiveId0);
+ mActiveId1 = event.getPointerId(index1);
+ mActive0MostRecent = false;
+
setContext(event);
// Check if we have a sloppy gesture. If so, delay
@@ -190,10 +208,10 @@ public class ScaleGestureDetector {
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);
+ float x0 = getRawX(event, index0);
+ float y0 = getRawY(event, index0);
+ float x1 = getRawX(event, index1);
+ float y1 = getRawY(event, index1);
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
|| x0 > rightSlop || y0 > bottomSlop;
@@ -205,14 +223,15 @@ public class ScaleGestureDetector {
mFocusY = -1;
mSloppyGesture = true;
} else if (p0sloppy) {
- mFocusX = event.getX(1);
- mFocusY = event.getY(1);
+ mFocusX = event.getX(index1);
+ mFocusY = event.getY(index1);
mSloppyGesture = true;
} else if (p1sloppy) {
- mFocusX = event.getX(0);
- mFocusY = event.getY(0);
+ mFocusX = event.getX(index0);
+ mFocusY = event.getY(index0);
mSloppyGesture = true;
} else {
+ mSloppyGesture = false;
mGestureInProgress = mListener.onScaleBegin(this);
}
}
@@ -224,25 +243,51 @@ public class ScaleGestureDetector {
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);
+ int index0 = event.findPointerIndex(mActiveId0);
+ int index1 = event.findPointerIndex(mActiveId1);
+ float x0 = getRawX(event, index0);
+ float y0 = getRawY(event, index0);
+ float x1 = getRawX(event, index1);
+ float y1 = getRawY(event, index1);
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
- || x0 > rightSlop || y0 > bottomSlop;
+ || x0 > rightSlop || y0 > bottomSlop;
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
- || x1 > rightSlop || y1 > bottomSlop;
+ || x1 > rightSlop || y1 > bottomSlop;
+
+ if (p0sloppy) {
+ // Do we have a different pointer that isn't sloppy?
+ int index = findNewActiveIndex(event, mActiveId1, index0);
+ if (index >= 0) {
+ index0 = index;
+ mActiveId0 = event.getPointerId(index);
+ x0 = getRawX(event, index);
+ y0 = getRawY(event, index);
+ p0sloppy = false;
+ }
+ }
+
+ if (p1sloppy) {
+ // Do we have a different pointer that isn't sloppy?
+ int index = findNewActiveIndex(event, mActiveId0, index1);
+ if (index >= 0) {
+ index1 = index;
+ mActiveId1 = event.getPointerId(index);
+ x1 = getRawX(event, index);
+ y1 = getRawY(event, index);
+ p1sloppy = false;
+ }
+ }
if(p0sloppy && p1sloppy) {
mFocusX = -1;
mFocusY = -1;
} else if (p0sloppy) {
- mFocusX = event.getX(1);
- mFocusY = event.getY(1);
+ mFocusX = event.getX(index1);
+ mFocusY = event.getY(index1);
} else if (p1sloppy) {
- mFocusX = event.getX(0);
- mFocusY = event.getY(0);
+ mFocusX = event.getX(index0);
+ mFocusY = event.getY(index0);
} else {
mSloppyGesture = false;
mGestureInProgress = mListener.onScaleBegin(this);
@@ -252,43 +297,109 @@ public class ScaleGestureDetector {
case MotionEvent.ACTION_POINTER_UP:
if (mSloppyGesture) {
- // Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
- mFocusX = event.getX(id);
- mFocusY = event.getY(id);
+ final int pointerCount = event.getPointerCount();
+ final int actionIndex = event.getActionIndex();
+ final int actionId = event.getPointerId(actionIndex);
+
+ if (pointerCount > 2) {
+ if (actionId == mActiveId0) {
+ final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
+ if (newIndex >= 0) mActiveId0 = event.getPointerId(newIndex);
+ } else if (actionId == mActiveId1) {
+ final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
+ if (newIndex >= 0) mActiveId1 = event.getPointerId(newIndex);
+ }
+ } else {
+ // Set focus point to the remaining finger
+ final int index = event.findPointerIndex(actionId == mActiveId0 ?
+ mActiveId1 : mActiveId0);
+ mActiveId0 = event.getPointerId(index);
+ mActive0MostRecent = true;
+ mActiveId1 = -1;
+ mFocusX = event.getX(index);
+ mFocusY = event.getY(index);
+ }
}
break;
}
} else {
// Transform gesture in progress - attempt to handle it
- switch (action & MotionEvent.ACTION_MASK) {
- case MotionEvent.ACTION_POINTER_UP:
- // Gesture ended
+ switch (action) {
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ // End the old gesture and begin a new one with the most recent two fingers.
+ mListener.onScaleEnd(this);
+ final int oldActive0 = mActiveId0;
+ final int oldActive1 = mActiveId1;
+ reset();
+
+ mPrevEvent = MotionEvent.obtain(event);
+ mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1;
+ mActiveId1 = event.getPointerId(event.getActionIndex());
+ mActive0MostRecent = false;
+
setContext(event);
- // Set focus point to the remaining finger
- int id = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
- >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
- mFocusX = event.getX(id);
- mFocusY = event.getY(id);
+ mGestureInProgress = mListener.onScaleBegin(this);
+ }
+ break;
- if (!mSloppyGesture) {
- mListener.onScaleEnd(this);
+ case MotionEvent.ACTION_POINTER_UP: {
+ final int pointerCount = event.getPointerCount();
+ final int actionIndex = event.getActionIndex();
+ final int actionId = event.getPointerId(actionIndex);
+
+ boolean gestureEnded = false;
+ if (pointerCount > 2) {
+ if (actionId == mActiveId0) {
+ final int newIndex = findNewActiveIndex(event, mActiveId1, actionIndex);
+ if (newIndex >= 0) {
+ mActiveId0 = event.getPointerId(newIndex);
+ } else {
+ gestureEnded = true;
+ }
+ } else if (actionId == mActiveId1) {
+ final int newIndex = findNewActiveIndex(event, mActiveId0, actionIndex);
+ if (newIndex >= 0) {
+ mActiveId1 = event.getPointerId(newIndex);
+ } else {
+ gestureEnded = true;
+ }
+ }
+ mPrevEvent.recycle();
+ mPrevEvent = MotionEvent.obtain(event);
+ setContext(event);
+ } else {
+ gestureEnded = true;
}
- reset();
- break;
+ if (gestureEnded) {
+ // Gesture ended
+ setContext(event);
+
+ // Set focus point to the remaining finger
+ final int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0;
+ final int index = event.findPointerIndex(activeId);
+ mFocusX = event.getX(index);
+ mFocusY = event.getY(index);
- case MotionEvent.ACTION_CANCEL:
- if (!mSloppyGesture) {
mListener.onScaleEnd(this);
+ reset();
+ mActiveId0 = activeId;
+ mActive0MostRecent = true;
}
+ }
+ break;
+ case MotionEvent.ACTION_CANCEL:
+ mListener.onScaleEnd(this);
reset();
break;
- case MotionEvent.ACTION_MOVE:
+ case MotionEvent.ACTION_UP:
+ reset();
+ break;
+
+ case MotionEvent.ACTION_MOVE: {
setContext(event);
// Only accept the event if our relative pressure is within
@@ -302,16 +413,43 @@ public class ScaleGestureDetector {
mPrevEvent = MotionEvent.obtain(event);
}
}
- break;
+ }
+ break;
}
}
return handled;
}
+ private int findNewActiveIndex(MotionEvent ev, int otherActiveId, int oldIndex) {
+ final int pointerCount = ev.getPointerCount();
+
+ // It's ok if this isn't found and returns -1, it simply won't match.
+ final int otherActiveIndex = ev.findPointerIndex(otherActiveId);
+ int newActiveIndex = -1;
+
+ // Pick a new id and update tracking state. Only pick pointers not on the slop edges.
+ for (int i = 0; i < pointerCount; i++) {
+ if (i != oldIndex && i != otherActiveIndex) {
+ final float edgeSlop = mEdgeSlop;
+ final float rightSlop = mRightSlopEdge;
+ final float bottomSlop = mBottomSlopEdge;
+ float x = getRawX(ev, i);
+ float y = getRawY(ev, i);
+ if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) {
+ newActiveIndex = i;
+ break;
+ }
+ }
+ }
+
+ return newActiveIndex;
+ }
+
/**
* MotionEvent has no getRawX(int) method; simulate it pending future API approval.
*/
private static float getRawX(MotionEvent event, int pointerIndex) {
+ if (pointerIndex == 0) return event.getRawX();
float offset = event.getRawX() - event.getX();
return event.getX(pointerIndex) + offset;
}
@@ -320,6 +458,7 @@ public class ScaleGestureDetector {
* MotionEvent has no getRawY(int) method; simulate it pending future API approval.
*/
private static float getRawY(MotionEvent event, int pointerIndex) {
+ if (pointerIndex == 0) return event.getRawY();
float offset = event.getRawY() - event.getY();
return event.getY(pointerIndex) + offset;
}
@@ -336,14 +475,19 @@ public class ScaleGestureDetector {
final MotionEvent prev = mPrevEvent;
- final float px0 = prev.getX(0);
- final float py0 = prev.getY(0);
- final float px1 = prev.getX(1);
- final float py1 = prev.getY(1);
- final float cx0 = curr.getX(0);
- final float cy0 = curr.getY(0);
- final float cx1 = curr.getX(1);
- final float cy1 = curr.getY(1);
+ final int prevIndex0 = prev.findPointerIndex(mActiveId0);
+ final int prevIndex1 = prev.findPointerIndex(mActiveId1);
+ final int currIndex0 = curr.findPointerIndex(mActiveId0);
+ final int currIndex1 = curr.findPointerIndex(mActiveId1);
+
+ final float px0 = prev.getX(prevIndex0);
+ final float py0 = prev.getY(prevIndex0);
+ final float px1 = prev.getX(prevIndex1);
+ final float py1 = prev.getY(prevIndex1);
+ final float cx0 = curr.getX(currIndex0);
+ final float cy0 = curr.getY(currIndex0);
+ final float cx1 = curr.getX(currIndex1);
+ final float cy1 = curr.getY(currIndex1);
final float pvx = px1 - px0;
final float pvy = py1 - py0;
@@ -357,8 +501,8 @@ public class ScaleGestureDetector {
mFocusX = cx0 + cvx * 0.5f;
mFocusY = cy0 + cvy * 0.5f;
mTimeDelta = curr.getEventTime() - prev.getEventTime();
- mCurrPressure = curr.getPressure(0) + curr.getPressure(1);
- mPrevPressure = prev.getPressure(0) + prev.getPressure(1);
+ mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1);
+ mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1);
}
private void reset() {
@@ -372,6 +516,8 @@ public class ScaleGestureDetector {
}
mSloppyGesture = false;
mGestureInProgress = false;
+ mActiveId0 = -1;
+ mActiveId1 = -1;
}
/**
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f8ece6b..06cb64e 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -5414,12 +5414,20 @@ public class WebView extends AbsoluteLayout
// If WebKit already showed no interests in this sequence of events,
// WebView handles them directly.
- if (mPreventDefault == PREVENT_DEFAULT_NO && action == MotionEvent.ACTION_MOVE) {
+ if (mPreventDefault == PREVENT_DEFAULT_NO) {
handleMultiTouchInWebView(ev);
} else {
passMultiTouchToWebKit(ev);
}
return true;
+ } else {
+ final ScaleGestureDetector detector = mZoomManager.getMultiTouchGestureDetector();
+ if (detector != null) {
+ // ScaleGestureDetector needs a consistent event stream to operate properly.
+ // It won't take any action with fewer than two pointers, but it needs to
+ // update internal bookkeeping state.
+ detector.onTouchEvent(ev);
+ }
}
// Skip ACTION_MOVE for single touch if it's still handling multi-touch.
@@ -5959,23 +5967,6 @@ public class WebView extends AbsoluteLayout
float x = ev.getX();
float y = ev.getY();
- if (!detector.isInProgress() &&
- ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
- // Insert a fake pointer down event in order to start
- // the zoom scale detector.
- MotionEvent temp = MotionEvent.obtain(ev);
- // Clear the original event and set it to
- // ACTION_POINTER_DOWN.
- try {
- temp.setAction(temp.getAction() &
- ~MotionEvent.ACTION_MASK |
- MotionEvent.ACTION_POINTER_DOWN);
- detector.onTouchEvent(temp);
- } finally {
- temp.recycle();
- }
- }
-
detector.onTouchEvent(ev);
if (detector.isInProgress()) {