19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.dumprendertree;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdochimport android.os.SystemClock;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.*;
21ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdochimport android.view.KeyEvent;
22ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdochimport android.view.MotionEvent;
23ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdochimport android.webkit.WebView;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Arrays;
26ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdochimport java.util.Vector;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class WebViewEventSender implements EventSender {
29ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
30ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    private static final String LOGTAG = "WebViewEventSender";
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    WebViewEventSender(WebView webView) {
33ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        mWebView = webView;
3441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        mWebView.getSettings().setBuiltInZoomControls(true);
35b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        mTouchPoints = new Vector<TouchPoint>();
36ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void resetMouse() {
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		mouseX = mouseY = 0;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void enableDOMUIEventLogging(int DOMNode) {
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// TODO Auto-generated method stub
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void fireKeyboardEventsToElement(int DOMNode) {
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// TODO Auto-generated method stub
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void keyDown(String character, String[] withModifiers) {
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.e("EventSender", "KeyDown: " + character + "("
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + character.getBytes()[0] + ") Modifiers: "
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Arrays.toString(withModifiers));
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KeyEvent modifier = null;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (withModifiers != null && withModifiers.length > 0) {
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < withModifiers.length; i++) {
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int keyCode = modifierMapper(withModifiers[i]);
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mWebView.onKeyDown(modifier.getKeyCode(), modifier);
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWebView.onKeyDown(event.getKeyCode(), event);
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void keyDown(String character) {
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        keyDown(character, null);
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void leapForward(int milliseconds) {
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// TODO Auto-generated method stub
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	public void mouseClick() {
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		mouseDown();
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		mouseUp();
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    public void mouseDown() {
85b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        long ts = SystemClock.uptimeMillis();
86b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        MotionEvent event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mouseX, mouseY, 0);
87b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        mWebView.onTouchEvent(event);
88b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    }
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
90b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    public void mouseMoveTo(int X, int Y) {
91b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        mouseX= X;
92b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        mouseY= Y;
93b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu     public void mouseUp() {
96b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        long ts = SystemClock.uptimeMillis();
97b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        MotionEvent event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mouseX, mouseY, 0);
98b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu        mWebView.onTouchEvent(event);
99b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    }
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	// Assumes lowercase chars, case needs to be
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	// handled by calling function.
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	static int keyMapper(char c) {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// handle numbers
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (c >= '0' && c<= '9') {
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			int offset = c - '0';
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_0 + offset;
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// handle characters
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (c >= 'a' && c <= 'z') {
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			int offset = c - 'a';
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_A + offset;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		// handle all others
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		switch (c) {
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '*':
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_STAR;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '#':
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_POUND;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case ',':
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_COMMA;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '.':
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_PERIOD;
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '\t':
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_TAB;
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case ' ':
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_SPACE;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '\n':
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_ENTER;
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '\b':
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case 0x7F:
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_DEL;
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '~':
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_GRAVE;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '-':
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_MINUS;
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '=':
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_EQUALS;
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '(':
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_LEFT_BRACKET;
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case ')':
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_RIGHT_BRACKET;
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '\\':
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_BACKSLASH;
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case ';':
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_SEMICOLON;
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '\'':
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_APOSTROPHE;
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		case '/':
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_SLASH;
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		default:
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			break;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		return c;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	static int modifierMapper(String modifier) {
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		if (modifier.equals("ctrlKey")) {
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_ALT_LEFT;
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		} else if (modifier.equals("shiftKey")) {
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_SHIFT_LEFT;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		} else if (modifier.equals("altKey")) {
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_SYM;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		} else if (modifier.equals("metaKey")) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project			return KeyEvent.KEYCODE_UNKNOWN;
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		}
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project		return KeyEvent.KEYCODE_UNKNOWN;
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project	}
172ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
173ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void touchStart() {
17441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        final int numPoints = mTouchPoints.size();
17541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numPoints == 0) {
176ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
177ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
178ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
17941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int[] pointerIds = new int[numPoints];
18041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
18141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        long downTime = SystemClock.uptimeMillis();
18241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
18341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        for (int i = 0; i < numPoints; ++i) {
18441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerIds[i] = mTouchPoints.get(i).getId();
18541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i] = new MotionEvent.PointerCoords();
18641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i].x = mTouchPoints.get(i).getX();
18741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i].y = mTouchPoints.get(i).getY();
18841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            mTouchPoints.get(i).setDownTime(downTime);
18941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        }
19041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
19141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent event = MotionEvent.obtain(downTime, downTime,
19241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            MotionEvent.ACTION_DOWN, numPoints, pointerIds, pointerCoords,
19341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
19441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
195ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        mWebView.onTouchEvent(event);
196ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
197ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
198ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void touchMove() {
19941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        final int numPoints = mTouchPoints.size();
20041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numPoints == 0) {
201ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
202ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
203ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
20441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int[] pointerIds = new int[numPoints];
20541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
20641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int numMovedPoints = 0;
20741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        for (int i = 0; i < numPoints; ++i) {
20841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            TouchPoint tp = mTouchPoints.get(i);
20941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            if (tp.hasMoved()) {
21041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerIds[numMovedPoints] = mTouchPoints.get(i).getId();
21141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[i] = new MotionEvent.PointerCoords();
21241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[numMovedPoints].x = mTouchPoints.get(i).getX();
21341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[numMovedPoints].y = mTouchPoints.get(i).getY();
21441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                ++numMovedPoints;
21541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                tp.setMoved(false);
21641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            }
21741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        }
21841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
21941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numMovedPoints == 0) {
220ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
221ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
222ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
22341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
22441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                SystemClock.uptimeMillis(), MotionEvent.ACTION_MOVE,
22541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                numMovedPoints, pointerIds, pointerCoords,
22641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
227ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        mWebView.onTouchEvent(event);
228ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
229ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
230ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void touchEnd() {
23141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        final int numPoints = mTouchPoints.size();
23241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numPoints == 0) {
233ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
234ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
235ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
23641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int[] pointerIds = new int[numPoints];
23741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
23841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
23941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        for (int i = 0; i < numPoints; ++i) {
24041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerIds[i] = mTouchPoints.get(i).getId();
24141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i] = new MotionEvent.PointerCoords();
24241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i].x = mTouchPoints.get(i).getX();
24341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            pointerCoords[i].y = mTouchPoints.get(i).getY();
24441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        }
24541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
24641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
24741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                SystemClock.uptimeMillis(), MotionEvent.ACTION_UP,
24841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                numPoints, pointerIds, pointerCoords,
24941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
250ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        mWebView.onTouchEvent(event);
251ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
25241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        for (int i = numPoints - 1; i >= 0; --i) {  // remove released points.
25341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            TouchPoint tp = mTouchPoints.get(i);
25441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            if (tp.isReleased()) {
25541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu              mTouchPoints.remove(i);
25641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            }
257ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
258ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
259ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
260ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void touchCancel() {
26141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        final int numPoints = mTouchPoints.size();
26241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numPoints == 0) {
263ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
264ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
265ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
26641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int[] pointerIds = new int[numPoints];
26741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
26841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        long cancelTime = SystemClock.uptimeMillis();
26941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int numCanceledPoints = 0;
27041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
27141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        for (int i = 0; i < numPoints; ++i) {
27241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            TouchPoint tp = mTouchPoints.get(i);
27341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            if (tp.cancelled()) {
27441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerIds[numCanceledPoints] = mTouchPoints.get(i).getId();
27541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[numCanceledPoints] = new MotionEvent.PointerCoords();
27641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[numCanceledPoints].x = mTouchPoints.get(i).getX();
27741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                pointerCoords[numCanceledPoints].y = mTouchPoints.get(i).getY();
27841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu                ++numCanceledPoints;
27941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            }
28041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        }
28141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
28241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numCanceledPoints == 0) {
28341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            return;
284ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
28541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
28641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).downTime(),
28741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            SystemClock.uptimeMillis(), MotionEvent.ACTION_CANCEL,
28841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            numCanceledPoints, pointerIds, pointerCoords,
28941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
29041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
29141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        mWebView.onTouchEvent(event);
292ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
293ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
294ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void cancelTouchPoint(int id) {
29541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        TouchPoint tp = mTouchPoints.get(id);
296ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        if (tp == null) {
297ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
298ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
299ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
300ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        tp.cancel();
301ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
302ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
303ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void addTouchPoint(int x, int y) {
30441865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        final int numPoints = mTouchPoints.size();
30541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        int id;
30641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        if (numPoints == 0) {
30741865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu          id = 0;
30841865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        } else {
30941865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu          id = mTouchPoints.get(numPoints - 1).getId() + 1;
310ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
31141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu
31241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        mTouchPoints.add(new TouchPoint(id, contentsToWindowX(x), contentsToWindowY(y)));
313ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
314ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
31541865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu    public void updateTouchPoint(int i, int x, int y) {
31641865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        TouchPoint tp = mTouchPoints.get(i);
317ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        if (tp == null) {
318ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
319ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
320ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
321ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        tp.update(contentsToWindowX(x), contentsToWindowY(y));
322ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        tp.setMoved(true);
323ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
324ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
325ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void setTouchModifier(String modifier, boolean enabled) {
3268a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        int mask = 0;
3278a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        if ("alt".equals(modifier.toLowerCase())) {
3288a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch            mask = KeyEvent.META_ALT_ON;
3298a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        } else if ("shift".equals(modifier.toLowerCase())) {
3308a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch            mask = KeyEvent.META_SHIFT_ON;
3318a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        } else if ("ctrl".equals(modifier.toLowerCase())) {
3328a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch            mask = KeyEvent.META_SYM_ON;
3338a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        }
3348a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch
3358a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        if (enabled) {
3368a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch            mTouchMetaState |= mask;
3378a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        } else {
3388a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch            mTouchMetaState &= ~mask;
3398a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        }
340ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
341ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
342ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void releaseTouchPoint(int id) {
34341865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        TouchPoint tp = mTouchPoints.get(id);
344ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        if (tp == null) {
345ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            return;
346ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
347ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
348ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        tp.release();
349ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
350ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
351ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    public void clearTouchPoints() {
352ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        mTouchPoints.clear();
353ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
354ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
3558a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch    public void clearTouchMetaState() {
3568a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch        mTouchMetaState = 0;
3578a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch    }
3588a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch
359ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    private int contentsToWindowX(int x) {
360a586b7baaf71eef621a826675346b95947fd1df0Huahui Wu        return Math.round(x * mWebView.getScale()) - mWebView.getScrollX();
361ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
362ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
363ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    private int contentsToWindowY(int y) {
364a586b7baaf71eef621a826675346b95947fd1df0Huahui Wu        return Math.round(y * mWebView.getScale()) - mWebView.getScrollY();
365ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    }
366ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private WebView mWebView = null;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mouseX;
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mouseY;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
371ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    private class TouchPoint {
37241865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        private int mId;
373ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private int mX;
374ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private int mY;
375ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private long mDownTime;
376ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private boolean mReleased;
377ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private boolean mMoved;
378ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        private boolean mCancelled;
379ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
38041865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        public TouchPoint(int id, int x, int y) {
38141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu            mId = id;
382ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mX = x;
383ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mY = y;
384ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mReleased = false;
385ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mMoved = false;
386ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mCancelled = false;
387ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
388ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
389ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public void setDownTime(long downTime) { mDownTime = downTime; }
390ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public long downTime() { return mDownTime; }
391ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public void cancel() { mCancelled = true; }
392ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
393ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public boolean cancelled() { return mCancelled; }
394ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
395ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public void release() { mReleased = true; }
396ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public boolean isReleased() { return mReleased; }
397ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
398ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public void setMoved(boolean moved) { mMoved = moved; }
399ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public boolean hasMoved() { return mMoved; }
400ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
40141865f4b0c5670369bf957ad72a867757fc6b356Huahui Wu        public int getId() { return mId; }
402ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public int getX() { return mX; }
403ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public int getY() { return mY; }
404ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
405ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        public void update(int x, int y) {
406ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mX = x;
407ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch            mY = y;
408ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch        }
409b5c4caa07819e59f909cf9d71e7e45ae2c88d715Guang Zhu    }
410ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch
411ecbc65cf8f2ea3bdd311f954e3927b46fca068ffBen Murdoch    private Vector<TouchPoint> mTouchPoints;
4128a032a3b29e7708e468e2078ff88a39e083db1daBen Murdoch    private int mTouchMetaState;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
414