diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index f2dab6e03b086..16ecab7566019 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -342,6 +342,7 @@ public class WebView extends AbsoluteLayout * choice. Maybe make this in the buildspec later. */ private static final int TOUCH_SENT_INTERVAL = 50; + private int mCurrentTouchInterval = TOUCH_SENT_INTERVAL; /** * Helper class to get velocity for fling @@ -4343,7 +4344,7 @@ public class WebView extends AbsoluteLayout // pass the touch events from UI thread to WebCore thread if (mForwardTouchEvents && (action != MotionEvent.ACTION_MOVE - || eventTime - mLastSentTouchTime > TOUCH_SENT_INTERVAL)) { + || eventTime - mLastSentTouchTime > mCurrentTouchInterval)) { WebViewCore.TouchEventData ted = new WebViewCore.TouchEventData(); ted.mAction = action; ted.mX = viewToContentX((int) x + mScrollX); @@ -6633,6 +6634,16 @@ public class WebView extends AbsoluteLayout mWebViewCore.drawContentPicture(canvas, 0, false, false); } + /** + * Set the time to wait between passing touches to WebCore. See also the + * TOUCH_SENT_INTERVAL member for further discussion. + * + * @hide This is only used by the DRT test application. + */ + public void setTouchInterval(int interval) { + mCurrentTouchInterval = interval; + } + /** * Update our cache with updatedText. * @param updatedText The new text to put in our cache. diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java index f33b01dd278fa..50451e75ae416 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java @@ -16,6 +16,7 @@ package com.android.dumprendertree; +import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.webkit.MockGeolocation; @@ -24,7 +25,7 @@ import android.webkit.WebStorage; import java.util.HashMap; public class CallbackProxy extends Handler implements EventSender, LayoutTestController { - + private EventSender mEventSender; private LayoutTestController mLayoutTestController; @@ -37,6 +38,15 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon private static final int EVENT_MOUSE_DOWN = 7; private static final int EVENT_MOUSE_MOVE = 8; private static final int EVENT_MOUSE_UP = 9; + private static final int EVENT_TOUCH_START = 10; + private static final int EVENT_TOUCH_MOVE = 11; + private static final int EVENT_TOUCH_END = 12; + private static final int EVENT_TOUCH_CANCEL = 13; + private static final int EVENT_ADD_TOUCH_POINT = 14; + private static final int EVENT_UPDATE_TOUCH_POINT = 15; + private static final int EVENT_RELEASE_TOUCH_POINT = 16; + private static final int EVENT_CLEAR_TOUCH_POINTS = 17; + private static final int EVENT_CANCEL_TOUCH_POINT = 18; private static final int LAYOUT_CLEAR_LIST = 20; private static final int LAYOUT_DISPLAY = 21; @@ -107,6 +117,46 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon mEventSender.mouseUp(); break; + case EVENT_TOUCH_START: + mEventSender.touchStart(); + break; + + case EVENT_TOUCH_MOVE: + mEventSender.touchMove(); + break; + + case EVENT_TOUCH_END: + mEventSender.touchEnd(); + break; + + case EVENT_TOUCH_CANCEL: + mEventSender.touchCancel(); + break; + + case EVENT_ADD_TOUCH_POINT: + mEventSender.addTouchPoint(msg.arg1, msg.arg2); + break; + + case EVENT_UPDATE_TOUCH_POINT: + Bundle args = (Bundle) msg.obj; + int x = args.getInt("x"); + int y = args.getInt("y"); + int id = args.getInt("id"); + mEventSender.updateTouchPoint(id, x, y); + break; + + case EVENT_RELEASE_TOUCH_POINT: + mEventSender.releaseTouchPoint(msg.arg1); + break; + + case EVENT_CLEAR_TOUCH_POINTS: + mEventSender.clearTouchPoints(); + break; + + case EVENT_CANCEL_TOUCH_POINT: + mEventSender.cancelTouchPoint(msg.arg1); + break; + case LAYOUT_CLEAR_LIST: mLayoutTestController.clearBackForwardList(); break; @@ -252,6 +302,51 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon public void mouseUp() { obtainMessage(EVENT_MOUSE_UP).sendToTarget(); } + + public void touchStart() { + obtainMessage(EVENT_TOUCH_START).sendToTarget(); + } + + public void addTouchPoint(int x, int y) { + obtainMessage(EVENT_ADD_TOUCH_POINT, x, y).sendToTarget(); + } + + public void updateTouchPoint(int id, int x, int y) { + Bundle map = new Bundle(); + map.putInt("x", x); + map.putInt("y", y); + map.putInt("id", id); + obtainMessage(EVENT_UPDATE_TOUCH_POINT, map).sendToTarget(); + } + + public void setTouchModifier(String modifier, boolean enabled) { + // TODO(benm): Android doesn't support key modifiers on touch events yet. + } + + public void touchMove() { + obtainMessage(EVENT_TOUCH_MOVE).sendToTarget(); + } + + public void releaseTouchPoint(int id) { + obtainMessage(EVENT_RELEASE_TOUCH_POINT, id, 0).sendToTarget(); + } + + public void touchEnd() { + obtainMessage(EVENT_TOUCH_END).sendToTarget(); + } + + public void touchCancel() { + obtainMessage(EVENT_TOUCH_CANCEL).sendToTarget(); + } + + + public void clearTouchPoints() { + obtainMessage(EVENT_CLEAR_TOUCH_POINTS).sendToTarget(); + } + + public void cancelTouchPoint(int id) { + obtainMessage(EVENT_CANCEL_TOUCH_POINT, id, 0).sendToTarget(); + } // LayoutTestController Methods diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java index 82fd8d8d61de0..23cc8f531bb00 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java @@ -26,4 +26,14 @@ public interface EventSender { public void keyDown (String character); public void enableDOMUIEventLogging(int DOMNode); public void fireKeyboardEventsToElement(int DOMNode); + public void touchStart(); + public void touchMove(); + public void touchEnd(); + public void touchCancel(); + public void addTouchPoint(int x, int y); + public void updateTouchPoint(int id, int x, int y); + public void setTouchModifier(String modifier, boolean enabled); + public void releaseTouchPoint(int id); + public void clearTouchPoints(); + public void cancelTouchPoint(int id); } diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java index 32219fad63975..452368eb309a0 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java @@ -96,6 +96,8 @@ public class FileFilter { // tests expect "LayoutTests" in their output. "storage/domstorage/localstorage/iframe-events.html", "storage/domstorage/sessionstorage/iframe-events.html", + // We do not support multi touch events. + "fast/events/touch/basic-multi-touch-events.html", // below tests (failed or crashes) are filtered out temporarily due to prioritizing "editing/selection/move-left-right.html", }; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 5763b85e04b3b..e8a66c19b6089 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -705,6 +705,7 @@ public class TestShellActivity extends Activity implements LayoutTestController mDumpDatabaseCallbacks = false; mCanOpenWindows = false; mEventSender.resetMouse(); + mEventSender.clearTouchPoints(); mPageFinished = false; mOneHundredPercentComplete = false; mDumpWebKitData = false; @@ -769,6 +770,12 @@ public class TestShellActivity extends Activity implements LayoutTestController webview.setWebChromeClient(mChromeClient); webview.setWebViewClient(mViewClient); + // Setting a touch interval of -1 effectively disables the optimisation in WebView + // that stops repeated touch events flooding WebCore. The Event Sender only sends a + // single event rather than a stream of events (like what would generally happen in + // a real use of touch events in a WebView) and so if the WebView drops the event, + // the test will fail as the test expects one callback for every touch it synthesizes. + webview.setTouchInterval(-1); } private WebView mWebView; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java index eea6346369783..996eaba0b73ee 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java @@ -16,17 +16,25 @@ package com.android.dumprendertree; -import android.webkit.WebView; -import android.view.KeyEvent; +import android.os.Handler; +import android.os.SystemClock; import android.util.*; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.webkit.WebView; +import java.lang.InterruptedException; import java.util.Arrays; +import java.util.Vector; public class WebViewEventSender implements EventSender { + + private static final String LOGTAG = "WebViewEventSender"; - WebViewEventSender(WebView webView) { - mWebView = webView; - } + WebViewEventSender(WebView webView) { + mWebView = webView; + mTouchPoints = new Vector(); + } public void resetMouse() { mouseX = mouseY = 0; @@ -186,9 +194,162 @@ public class WebViewEventSender implements EventSender { } return KeyEvent.KEYCODE_UNKNOWN; } - + + public void touchStart() { + // We only support single touch so examine the first touch point only. + // If multi touch is enabled in the future, we need to re-examine this to send + // all the touch points with the event. + TouchPoint tp = mTouchPoints.get(0); + + if (tp == null) { + return; + } + + tp.setDownTime(SystemClock.uptimeMillis()); + MotionEvent event = MotionEvent.obtain(tp.downTime(), tp.downTime(), + MotionEvent.ACTION_DOWN, tp.getX(), tp.getY(), 0); + mWebView.onTouchEvent(event); + } + + public void touchMove() { + TouchPoint tp = mTouchPoints.get(0); + + if (tp == null) { + return; + } + + if (!tp.hasMoved()) { + return; + } + + MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), + MotionEvent.ACTION_MOVE, tp.getX(), tp.getY(), 0); + mWebView.onTouchEvent(event); + + tp.setMoved(false); + } + + public void touchEnd() { + TouchPoint tp = mTouchPoints.get(0); + + if (tp == null) { + return; + } + + MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), + MotionEvent.ACTION_UP, tp.getX(), tp.getY(), 0); + mWebView.onTouchEvent(event); + + if (tp.isReleased()) { + mTouchPoints.remove(0); + } + } + + public void touchCancel() { + TouchPoint tp = mTouchPoints.get(0); + if (tp == null) { + return; + } + + if (tp.cancelled()) { + MotionEvent event = MotionEvent.obtain(tp.downTime(), SystemClock.uptimeMillis(), + MotionEvent.ACTION_CANCEL, tp.getX(), tp.getY(), 0); + mWebView.onTouchEvent(event); + } + } + + public void cancelTouchPoint(int id) { + TouchPoint tp = mTouchPoints.get(0); + if (tp == null) { + return; + } + + tp.cancel(); + } + + public void addTouchPoint(int x, int y) { + mTouchPoints.add(new TouchPoint(contentsToWindowX(x), contentsToWindowY(y))); + if (mTouchPoints.size() > 1) { + Log.w(LOGTAG, "Adding more than one touch point, but multi touch is not supported!"); + } + } + + public void updateTouchPoint(int id, int x, int y) { + TouchPoint tp = mTouchPoints.get(0); + if (tp == null) { + return; + } + + tp.update(contentsToWindowX(x), contentsToWindowY(y)); + tp.setMoved(true); + } + + public void setTouchModifier(String modifier, boolean enabled) { + // TODO(benm): This needs implementing when Android supports sending key modifiers + // in touch events. + } + + public void releaseTouchPoint(int id) { + TouchPoint tp = mTouchPoints.get(0); + if (tp == null) { + return; + } + + tp.release(); + } + + public void clearTouchPoints() { + mTouchPoints.clear(); + } + + private int contentsToWindowX(int x) { + return (int) (x * mWebView.getScale()) - mWebView.getScrollX(); + } + + private int contentsToWindowY(int y) { + return (int) (y * mWebView.getScale()) - mWebView.getScrollY(); + } + private WebView mWebView = null; private int mouseX; private int mouseY; + private class TouchPoint { + private int mX; + private int mY; + private long mDownTime; + private boolean mReleased; + private boolean mMoved; + private boolean mCancelled; + + public TouchPoint(int x, int y) { + mX = x; + mY = y; + mReleased = false; + mMoved = false; + mCancelled = false; + } + + public void setDownTime(long downTime) { mDownTime = downTime; } + public long downTime() { return mDownTime; } + public void cancel() { mCancelled = true; } + + public boolean cancelled() { return mCancelled; } + + public void release() { mReleased = true; } + public boolean isReleased() { return mReleased; } + + public void setMoved(boolean moved) { mMoved = moved; } + public boolean hasMoved() { return mMoved; } + + public int getX() { return mX; } + public int getY() { return mY; } + + public void update(int x, int y) { + mX = x; + mY = y; + } + }; + + private Vector mTouchPoints; }