Merge "Fix bug 4111271 and bug 4077526 - WebView touch event handling when WebCore is too slow" into honeycomb-mr1

This commit is contained in:
Adam Powell
2011-03-17 01:36:47 -07:00
committed by Android (Google) Code Review
2 changed files with 53 additions and 16 deletions

View File

@ -156,6 +156,7 @@ public class ScaleGestureDetector {
private float mRightSlopEdge; private float mRightSlopEdge;
private float mBottomSlopEdge; private float mBottomSlopEdge;
private boolean mSloppyGesture; private boolean mSloppyGesture;
private boolean mInvalidGesture;
// Pointer IDs currently responsible for the two fingers controlling the gesture // Pointer IDs currently responsible for the two fingers controlling the gesture
private int mActiveId0; private int mActiveId0;
@ -177,6 +178,8 @@ public class ScaleGestureDetector {
reset(); // Start fresh reset(); // Start fresh
} }
if (mInvalidGesture) return false;
if (!mGestureInProgress) { if (!mGestureInProgress) {
switch (action) { switch (action) {
case MotionEvent.ACTION_DOWN: { case MotionEvent.ACTION_DOWN: {
@ -518,6 +521,15 @@ public class ScaleGestureDetector {
final int currIndex0 = curr.findPointerIndex(mActiveId0); final int currIndex0 = curr.findPointerIndex(mActiveId0);
final int currIndex1 = curr.findPointerIndex(mActiveId1); final int currIndex1 = curr.findPointerIndex(mActiveId1);
if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) {
mInvalidGesture = true;
Log.e(TAG, "Invalid MotionEvent stream detected.", new Throwable());
if (mGestureInProgress) {
mListener.onScaleEnd(this);
}
return;
}
final float px0 = prev.getX(prevIndex0); final float px0 = prev.getX(prevIndex0);
final float py0 = prev.getY(prevIndex0); final float py0 = prev.getY(prevIndex0);
final float px1 = prev.getX(prevIndex1); final float px1 = prev.getX(prevIndex1);
@ -556,6 +568,7 @@ public class ScaleGestureDetector {
mGestureInProgress = false; mGestureInProgress = false;
mActiveId0 = -1; mActiveId0 = -1;
mActiveId1 = -1; mActiveId1 = -1;
mInvalidGesture = false;
} }
/** /**

View File

@ -7185,14 +7185,15 @@ public class WebView extends AbsoluteLayout
private class TouchEventQueue { private class TouchEventQueue {
private long mNextTouchSequence = Long.MIN_VALUE + 1; private long mNextTouchSequence = Long.MIN_VALUE + 1;
private long mLastHandledTouchSequence = Long.MIN_VALUE; private long mLastHandledTouchSequence = Long.MIN_VALUE;
private long mIgnoreUntilSequence = Long.MIN_VALUE; private long mIgnoreUntilSequence = Long.MIN_VALUE + 1;
private QueuedTouch mTouchEventQueue; private QueuedTouch mTouchEventQueue;
private QueuedTouch mQueuedTouchRecycleBin; private QueuedTouch mQueuedTouchRecycleBin;
private int mQueuedTouchRecycleCount; private int mQueuedTouchRecycleCount;
private long mLastEventTime = Long.MAX_VALUE;
private static final int MAX_RECYCLED_QUEUED_TOUCH = 15; private static final int MAX_RECYCLED_QUEUED_TOUCH = 15;
// milliseconds until we abandon hope of getting all of a previous gesture // milliseconds until we abandon hope of getting all of a previous gesture
private static final int QUEUED_GESTURE_TIMEOUT = 2000; private static final int QUEUED_GESTURE_TIMEOUT = 1000;
private QueuedTouch obtainQueuedTouch() { private QueuedTouch obtainQueuedTouch() {
if (mQueuedTouchRecycleBin != null) { if (mQueuedTouchRecycleBin != null) {
@ -7226,7 +7227,7 @@ public class WebView extends AbsoluteLayout
public void reset() { public void reset() {
mNextTouchSequence = Long.MIN_VALUE + 1; mNextTouchSequence = Long.MIN_VALUE + 1;
mLastHandledTouchSequence = Long.MIN_VALUE; mLastHandledTouchSequence = Long.MIN_VALUE;
mIgnoreUntilSequence = Long.MIN_VALUE; mIgnoreUntilSequence = Long.MIN_VALUE + 1;
while (mTouchEventQueue != null) { while (mTouchEventQueue != null) {
QueuedTouch recycleMe = mTouchEventQueue; QueuedTouch recycleMe = mTouchEventQueue;
mTouchEventQueue = mTouchEventQueue.mNext; mTouchEventQueue = mTouchEventQueue.mNext;
@ -7260,7 +7261,9 @@ public class WebView extends AbsoluteLayout
return; return;
} }
dropStaleGestures(ted.mMotionEvent, ted.mSequence); if (dropStaleGestures(ted.mMotionEvent, ted.mSequence)) {
return;
}
if (mLastHandledTouchSequence + 1 == ted.mSequence) { if (mLastHandledTouchSequence + 1 == ted.mSequence) {
handleQueuedTouchEventData(ted); handleQueuedTouchEventData(ted);
@ -7295,7 +7298,9 @@ public class WebView extends AbsoluteLayout
public void enqueueTouchEvent(MotionEvent ev) { public void enqueueTouchEvent(MotionEvent ev) {
final long sequence = nextTouchSequence(); final long sequence = nextTouchSequence();
dropStaleGestures(ev, sequence); if (dropStaleGestures(ev, sequence)) {
return;
}
if (mLastHandledTouchSequence + 1 == sequence) { if (mLastHandledTouchSequence + 1 == sequence) {
handleQueuedMotionEvent(ev); handleQueuedMotionEvent(ev);
@ -7318,16 +7323,30 @@ public class WebView extends AbsoluteLayout
} }
} }
private void dropStaleGestures(MotionEvent ev, long sequence) { private boolean dropStaleGestures(MotionEvent ev, long sequence) {
if (mTouchEventQueue == null) return; if (ev != null && ev.getAction() == MotionEvent.ACTION_MOVE && !mConfirmMove) {
// This is to make sure that we don't attempt to process a tap
// or long press when webkit takes too long to get back to us.
// The movement will be properly confirmed when we process the
// enqueued event later.
final int dx = Math.round(ev.getX()) - mLastTouchX;
final int dy = Math.round(ev.getY()) - mLastTouchY;
if (dx * dx + dy * dy > mTouchSlopSquare) {
mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS);
}
}
MotionEvent nextQueueEvent = mTouchEventQueue.mTed != null ? if (mTouchEventQueue == null) {
mTouchEventQueue.mTed.mMotionEvent : mTouchEventQueue.mEvent; return sequence <= mLastHandledTouchSequence;
}
if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN && nextQueueEvent != null) { // If we have a new down event and it's been a while since the last event
// we saw, just reset and keep going.
if (ev != null && ev.getAction() == MotionEvent.ACTION_DOWN) {
long eventTime = ev.getEventTime(); long eventTime = ev.getEventTime();
long nextQueueTime = nextQueueEvent.getEventTime(); long lastHandledEventTime = mLastEventTime;
if (eventTime > nextQueueTime + QUEUED_GESTURE_TIMEOUT) { if (eventTime > lastHandledEventTime + QUEUED_GESTURE_TIMEOUT) {
Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " + Log.w(LOGTAG, "Got ACTION_DOWN but still waiting on stale event. " +
"Ignoring previous queued events."); "Ignoring previous queued events.");
QueuedTouch qd = mTouchEventQueue; QueuedTouch qd = mTouchEventQueue;
@ -7341,17 +7360,18 @@ public class WebView extends AbsoluteLayout
} }
} }
if (mIgnoreUntilSequence > mLastHandledTouchSequence) { if (mIgnoreUntilSequence - 1 > mLastHandledTouchSequence) {
QueuedTouch qd = mTouchEventQueue; QueuedTouch qd = mTouchEventQueue;
while (qd != null && qd.mSequence < mIgnoreUntilSequence && while (qd != null && qd.mSequence < mIgnoreUntilSequence) {
qd.mSequence < sequence) {
mLastHandledTouchSequence = qd.mSequence;
QueuedTouch recycleMe = qd; QueuedTouch recycleMe = qd;
qd = qd.mNext; qd = qd.mNext;
recycleQueuedTouch(recycleMe); recycleQueuedTouch(recycleMe);
} }
mTouchEventQueue = qd; mTouchEventQueue = qd;
mLastHandledTouchSequence = mIgnoreUntilSequence - 1;
} }
return sequence <= mLastHandledTouchSequence;
} }
private void handleQueuedTouch(QueuedTouch qt) { private void handleQueuedTouch(QueuedTouch qt) {
@ -7364,6 +7384,7 @@ public class WebView extends AbsoluteLayout
} }
private void handleQueuedMotionEvent(MotionEvent ev) { private void handleQueuedMotionEvent(MotionEvent ev) {
mLastEventTime = ev.getEventTime();
int action = ev.getActionMasked(); int action = ev.getActionMasked();
if (ev.getPointerCount() > 1) { // Multi-touch if (ev.getPointerCount() > 1) { // Multi-touch
handleMultiTouchInWebView(ev); handleMultiTouchInWebView(ev);
@ -7381,6 +7402,9 @@ public class WebView extends AbsoluteLayout
} }
private void handleQueuedTouchEventData(TouchEventData ted) { private void handleQueuedTouchEventData(TouchEventData ted) {
if (ted.mMotionEvent != null) {
mLastEventTime = ted.mMotionEvent.getEventTime();
}
if (!ted.mReprocess) { if (!ted.mReprocess) {
if (ted.mAction == MotionEvent.ACTION_DOWN if (ted.mAction == MotionEvent.ACTION_DOWN
&& mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) { && mPreventDefault == PREVENT_DEFAULT_MAYBE_YES) {