1694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/*
2694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Copyright (C) 2010 The Android Open Source Project
3694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
4694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * you may not use this file except in compliance with the License.
6694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * You may obtain a copy of the License at
7694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
8694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy *
10694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * Unless required by applicable law or agreed to in writing, software
11694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * See the License for the specific language governing permissions and
14694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy * limitations under the License.
15694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy */
16694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
17694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guypackage com.android.dumprendertree2;
18694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
19694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyimport android.os.Bundle;
20694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyimport android.os.Handler;
2151769a68a5cb34e9564740c6a854fcb93018789dRomain Guyimport android.os.Message;
22e2d345ea67e2960b37bfdc0fc8626d1bfa747404Romain Guyimport android.os.SystemClock;
2351769a68a5cb34e9564740c6a854fcb93018789dRomain Guyimport android.util.Log;
2451769a68a5cb34e9564740c6a854fcb93018789dRomain Guyimport android.view.KeyEvent;
25c9855a53edfac818dc68714557185977556f849dRomain Guyimport android.view.MotionEvent;
2651769a68a5cb34e9564740c6a854fcb93018789dRomain Guyimport android.webkit.WebView;
2751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
28694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyimport java.util.LinkedList;
29694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guyimport java.util.List;
30694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
31694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy/**
3251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy * An implementation of EventSender
3351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy */
3451769a68a5cb34e9564740c6a854fcb93018789dRomain Guypublic class EventSenderImpl {
3551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    private static final String LOG_TAG = "EventSenderImpl";
3651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
3751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    private static final int MSG_ENABLE_DOM_UI_EVENT_LOGGING = 0;
38726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    private static final int MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT = 1;
3944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    private static final int MSG_LEAP_FORWARD = 2;
4044984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
4144984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    private static final int MSG_KEY_DOWN = 3;
4251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
43694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_MOUSE_DOWN = 4;
44694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_MOUSE_UP = 5;
45694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_MOUSE_CLICK = 6;
462577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    private static final int MSG_MOUSE_MOVE_TO = 7;
478668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase
482577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy    private static final int MSG_ADD_TOUCH_POINT = 8;
498668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase    private static final int MSG_TOUCH_START = 9;
50694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_UPDATE_TOUCH_POINT = 10;
51694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_TOUCH_MOVE = 11;
52694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_CLEAR_TOUCH_POINTS = 12;
53694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_TOUCH_CANCEL = 13;
54694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_RELEASE_TOUCH_POINT = 14;
55694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_TOUCH_END = 15;
56694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_SET_TOUCH_MODIFIER = 16;
57694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static final int MSG_CANCEL_TOUCH_POINT = 17;
58694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
59694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private static class Point {
60694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        private int mX;
61694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        private int mY;
62726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
63694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        public Point(int x, int y) {
64694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mX = x;
65694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mY = y;
66694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
67694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        public int x() {
68694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return mX;
69694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
70694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        public int y() {
71694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return mY;
72f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        }
73f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
74f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
75f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    private Point createViewPointFromContentCoordinates(int x, int y) {
76f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        return new Point(Math.round(x * mWebView.getScale()) - mWebView.getScrollX(),
77f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                         Math.round(y * mWebView.getScale()) - mWebView.getScrollY());
78f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    }
7961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
80f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk    public static class TouchPoint {
81f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        private int mId;
8261c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        private Point mPoint;
83f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        private long mDownTime;
84f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        private boolean mReleased = false;
8561c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        private boolean mMoved = false;
86f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        private boolean mCancelled = false;
87f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
8861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy        public TouchPoint(int id, Point point) {
89f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            mId = id;
90f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            mPoint = point;
91f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        }
92f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
93694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        public int getId() {
94694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy          return mId;
95694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
96694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
9751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        public int getX() {
9851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return mPoint.x();
9951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        }
10051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
10151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        public int getY() {
10251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return mPoint.y();
10351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        }
10451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
10551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        public boolean hasMoved() {
10651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy            return mMoved;
10751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        }
10851769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
109694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        public void move(Point point) {
110694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mPoint = point;
111b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy            mMoved = true;
112b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy        }
11389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
11489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        public void resetHasMoved() {
11589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            mMoved = false;
11689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
11789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
11889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        public long getDownTime() {
11989a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            return mDownTime;
12089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
12189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
122f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        public void setDownTime(long downTime) {
123f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            mDownTime = downTime;
12489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
12589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
126b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy        public boolean isReleased() {
127f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk            return mReleased;
128f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk        }
129f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
13089a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        public void release() {
13189a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            mReleased = true;
13289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
13389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
13489a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        public boolean isCancelled() {
13589a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk            return mCancelled;
13689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        }
137726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
1381e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        public void cancel() {
139726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy            mCancelled = true;
1401e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
1411e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy    }
1421e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy
143726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy    private List<TouchPoint> mTouchPoints;
14465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    private int mTouchMetaState;
14565ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    private Point mMousePoint;
14665ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
14765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    private WebView mWebView;
148726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
14965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    private Handler mEventSenderHandler = new Handler() {
15065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        @Override
15165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk        public void handleMessage(Message msg) {
15265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk            Bundle bundle;
15365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk            MotionEvent event;
15465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk            long ts;
155726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
15661c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy            switch (msg.what) {
15761c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                case MSG_ENABLE_DOM_UI_EVENT_LOGGING:
158726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    /** TODO: implement */
15961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    break;
16061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
161726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                case MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT:
162726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    /** TODO: implement */
163f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    break;
164f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
165f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                case MSG_LEAP_FORWARD:
166f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    /** TODO: implement */
167726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    break;
16861c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
16961c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                case MSG_KEY_DOWN:
170f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    bundle = (Bundle)msg.obj;
171f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    String character = bundle.getString("character");
172f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    String[] withModifiers = bundle.getStringArray("withModifiers");
173f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
174726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    if (withModifiers != null && withModifiers.length > 0) {
175f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                        for (int i = 0; i < withModifiers.length; i++) {
176f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                            executeKeyEvent(KeyEvent.ACTION_DOWN,
17758ef7fbf16864164efe98bf613b15c64deb1afc0Romain Guy                                    modifierToKeyCode(withModifiers[i]));
1782bffd268f135df8308c9e67af110525a5c463424Romain Guy                        }
179726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    }
18061c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                    executeKeyEvent(KeyEvent.ACTION_DOWN,
18161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                            charToKeyCode(character.toLowerCase().toCharArray()[0]));
182694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
183694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
184694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                /** MOUSE */
185694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
1862bffd268f135df8308c9e67af110525a5c463424Romain Guy                case MSG_MOUSE_DOWN:
1872bffd268f135df8308c9e67af110525a5c463424Romain Guy                    if (mMousePoint != null) {
188694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        ts = SystemClock.uptimeMillis();
189694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_DOWN, mMousePoint.x(), mMousePoint.y(), 0);
190694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        mWebView.onTouchEvent(event);
191694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
192694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
1932bffd268f135df8308c9e67af110525a5c463424Romain Guy
1942bffd268f135df8308c9e67af110525a5c463424Romain Guy                case MSG_MOUSE_UP:
1952bffd268f135df8308c9e67af110525a5c463424Romain Guy                    if (mMousePoint != null) {
196694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        ts = SystemClock.uptimeMillis();
197694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        event = MotionEvent.obtain(ts, ts, MotionEvent.ACTION_UP, mMousePoint.x(), mMousePoint.y(), 0);
198694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        mWebView.onTouchEvent(event);
199726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                    }
200694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
20161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy
202726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                case MSG_MOUSE_CLICK:
203694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    mouseDown();
204694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    mouseUp();
205694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
206726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
2072bffd268f135df8308c9e67af110525a5c463424Romain Guy                case MSG_MOUSE_MOVE_TO:
2082bffd268f135df8308c9e67af110525a5c463424Romain Guy                    mMousePoint = createViewPointFromContentCoordinates(msg.arg1, msg.arg2);
209694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
210694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
211694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                /** TOUCH */
212f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk
213f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                case MSG_ADD_TOUCH_POINT:
2142bffd268f135df8308c9e67af110525a5c463424Romain Guy                    int numPoints = getTouchPoints().size();
215f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    int id;
216f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    if (numPoints == 0) {
2172bffd268f135df8308c9e67af110525a5c463424Romain Guy                        id = 0;
218f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    } else {
219f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                        id = getTouchPoints().get(numPoints - 1).getId() + 1;
2202bffd268f135df8308c9e67af110525a5c463424Romain Guy                    }
221f18136cb3c881a9d16c1a4f0f341732c276936bfAlex Sakhartchouk                    getTouchPoints().add(
22289a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                            new TouchPoint(id, createViewPointFromContentCoordinates(msg.arg1, msg.arg2)));
223694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
224694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
2252bffd268f135df8308c9e67af110525a5c463424Romain Guy                case MSG_TOUCH_START:
226694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if (getTouchPoints().isEmpty()) {
227694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        return;
228694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
229694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    for (int i = 0; i < getTouchPoints().size(); ++i) {
230694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        getTouchPoints().get(i).setDownTime(SystemClock.uptimeMillis());
231694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
232694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    executeTouchEvent(MotionEvent.ACTION_DOWN);
233694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
23451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
235694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                case MSG_UPDATE_TOUCH_POINT:
236694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    bundle = (Bundle)msg.obj;
237694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
238694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    int index = bundle.getInt("id");
2392bffd268f135df8308c9e67af110525a5c463424Romain Guy                    if (index >= getTouchPoints().size()) {
2402bffd268f135df8308c9e67af110525a5c463424Romain Guy                        Log.w(LOG_TAG + "::MSG_UPDATE_TOUCH_POINT", "TouchPoint out of bounds: "
241694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                                + index);
242694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        break;
243694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
244694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
245694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    getTouchPoints().get(index).move(
246694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                            createViewPointFromContentCoordinates(bundle.getInt("x"), bundle.getInt("y")));
24751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    break;
248694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
249694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                case MSG_TOUCH_MOVE:
250694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    /**
251694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
252694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     * the first touch point. In future this method will need rewriting.
253694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     */
254694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if (getTouchPoints().isEmpty()) {
255694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        return;
25689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    }
25789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                    executeTouchEvent(MotionEvent.ACTION_MOVE);
258694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    for (int i = 0; i < getTouchPoints().size(); ++i) {
259694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        getTouchPoints().get(i).resetHasMoved();
260694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
26151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    break;
26251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
263694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                case MSG_CANCEL_TOUCH_POINT:
264694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if (msg.arg1 >= getTouchPoints().size()) {
265694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        Log.w(LOG_TAG + "::MSG_RELEASE_TOUCH_POINT", "TouchPoint out of bounds: "
266694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                                + msg.arg1);
267694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        break;
268694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
26951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
270694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    getTouchPoints().get(msg.arg1).cancel();
271694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
272726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy
27351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                case MSG_TOUCH_CANCEL:
274694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    /**
275694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
276726aeba80ffc6778a9bc3e0ee957b8d644183505Romain Guy                     * the first touch point. In future this method will need rewriting.
277694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     */
278694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if (getTouchPoints().isEmpty()) {
279694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        return;
280694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
281694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    executeTouchEvent(MotionEvent.ACTION_CANCEL);
282694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
283694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
284694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                case MSG_RELEASE_TOUCH_POINT:
2852577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy                    if (msg.arg1 >= getTouchPoints().size()) {
2868668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                        Log.w(LOG_TAG + "::MSG_RELEASE_TOUCH_POINT", "TouchPoint out of bounds: "
287694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                                + msg.arg1);
288694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        break;
289694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
29051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
2912577db1ec135a1470a2c42139772ec97a6c30e78Romain Guy                    getTouchPoints().get(msg.arg1).release();
2928668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                    break;
2938668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase
29451769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                case MSG_TOUCH_END:
295694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    /**
296694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     * FIXME: At the moment we don't support multi-touch. Hence, we only examine
297694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                     * the first touch point. In future this method will need rewriting.
2988668f8a633d9299091556c3b2e5ae07be8dce360Chet Haase                     */
299694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if (getTouchPoints().isEmpty()) {
300694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        return;
301694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
302694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    executeTouchEvent(MotionEvent.ACTION_UP);
303694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    // remove released points.
304694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    for (int i = getTouchPoints().size() - 1; i >= 0; --i) {
305694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        if (getTouchPoints().get(i).isReleased()) {
306694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                            getTouchPoints().remove(i);
307514fb18827186591d66973c2362c859b64b63556Romain Guy                        }
308514fb18827186591d66973c2362c859b64b63556Romain Guy                    }
309694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    break;
310c9855a53edfac818dc68714557185977556f849dRomain Guy
311c9855a53edfac818dc68714557185977556f849dRomain Guy                case MSG_SET_TOUCH_MODIFIER:
312c9855a53edfac818dc68714557185977556f849dRomain Guy                    bundle = (Bundle)msg.obj;
31351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    String modifier = bundle.getString("modifier");
314b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy                    boolean enabled = bundle.getBoolean("enabled");
315694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
316694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    int mask = 0;
317694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    if ("alt".equals(modifier.toLowerCase())) {
3189b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                        mask = KeyEvent.META_ALT_ON;
319694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    } else if ("shift".equals(modifier.toLowerCase())) {
3209cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy                        mask = KeyEvent.META_SHIFT_ON;
3219cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy                    } else if ("ctrl".equals(modifier.toLowerCase())) {
3229cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy                        mask = KeyEvent.META_SYM_ON;
323694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                    }
324894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk
325894df17eee708688c8a6e67941add2017239c790Alex Sakhartchouk                    if (enabled) {
326694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                        mTouchMetaState |= mask;
32751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    } else {
3289b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                        mTouchMetaState &= ~mask;
32951769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    }
33051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
33151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    break;
332c9855a53edfac818dc68714557185977556f849dRomain Guy
333c9855a53edfac818dc68714557185977556f849dRomain Guy                case MSG_CLEAR_TOUCH_POINTS:
334c9855a53edfac818dc68714557185977556f849dRomain Guy                    getTouchPoints().clear();
33551769a68a5cb34e9564740c6a854fcb93018789dRomain Guy                    break;
33651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
337514fb18827186591d66973c2362c859b64b63556Romain Guy                default:
338c9855a53edfac818dc68714557185977556f849dRomain Guy                    break;
339514fb18827186591d66973c2362c859b64b63556Romain Guy            }
34051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        }
34151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy    };
34251769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
343c9855a53edfac818dc68714557185977556f849dRomain Guy    public void reset(WebView webView) {
344c9855a53edfac818dc68714557185977556f849dRomain Guy        mWebView = webView;
345c9855a53edfac818dc68714557185977556f849dRomain Guy        mTouchPoints = null;
34651769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        mTouchMetaState = 0;
34751769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        mMousePoint = null;
348514fb18827186591d66973c2362c859b64b63556Romain Guy    }
349c9855a53edfac818dc68714557185977556f849dRomain Guy
350514fb18827186591d66973c2362c859b64b63556Romain Guy    public void enableDOMUIEventLogging(int domNode) {
35151769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        Message msg = mEventSenderHandler.obtainMessage(MSG_ENABLE_DOM_UI_EVENT_LOGGING);
352514fb18827186591d66973c2362c859b64b63556Romain Guy        msg.arg1 = domNode;
353514fb18827186591d66973c2362c859b64b63556Romain Guy        msg.sendToTarget();
354694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
355694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
356694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void fireKeyboardEventsToElement(int domNode) {
357694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Message msg = mEventSenderHandler.obtainMessage(MSG_FIRE_KEYBOARD_EVENTS_TO_ELEMENT);
358694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.arg1 = domNode;
359694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.sendToTarget();
360694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
361694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
3629cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy    public void leapForward(int milliseconds) {
3639cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        Message msg = mEventSenderHandler.obtainMessage(MSG_LEAP_FORWARD);
3649cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        msg.arg1 = milliseconds;
3659cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy        msg.sendToTarget();
3669b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
3679cccc2b9bdd4850a3f9679569aaec3ab98477a5dRomain Guy
3689b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    public void keyDown(String character, String[] withModifiers) {
3699b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        Bundle bundle = new Bundle();
370694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putString("character", character);
371694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putStringArray("withModifiers", withModifiers);
372694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.obtainMessage(MSG_KEY_DOWN, bundle).sendToTarget();
373694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
374694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
375694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    /** MOUSE */
376694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
377694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void mouseDown() {
378694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_DOWN);
379694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
380694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
381694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void mouseUp() {
382694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_UP);
383694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
384694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
385694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void mouseClick() {
386694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_MOUSE_CLICK);
387694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
388694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
389694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void mouseMoveTo(int x, int y) {
39051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        mEventSenderHandler.obtainMessage(MSG_MOUSE_MOVE_TO, x, y).sendToTarget();
391694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
3922bffd268f135df8308c9e67af110525a5c463424Romain Guy
39344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    /** TOUCH */
39444984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
39544984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    public void addTouchPoint(int x, int y) {
39644984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase        mEventSenderHandler.obtainMessage(MSG_ADD_TOUCH_POINT, x, y).sendToTarget();
39744984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    }
39844984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
39944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    public void touchStart() {
40044984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_START);
40144984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    }
40244984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase
40344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    public void updateTouchPoint(int id, int x, int y) {
404694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Bundle bundle = new Bundle();
405694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putInt("id", id);
406694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putInt("x", x);
407694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putInt("y", y);
408694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.obtainMessage(MSG_UPDATE_TOUCH_POINT, bundle).sendToTarget();
409694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
410694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
411694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void touchMove() {
412694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_MOVE);
413694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
414694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
415694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void cancelTouchPoint(int id) {
416694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Message msg = mEventSenderHandler.obtainMessage(MSG_CANCEL_TOUCH_POINT);
417694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.arg1 = id;
418694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.sendToTarget();
419694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
420694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
421694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void touchCancel() {
422694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_CANCEL);
423694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
424694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
425694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void releaseTouchPoint(int id) {
426694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Message msg = mEventSenderHandler.obtainMessage(MSG_RELEASE_TOUCH_POINT);
427694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.arg1 = id;
428694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        msg.sendToTarget();
429694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
430694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
431694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void touchEnd() {
432694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_TOUCH_END);
433694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
434694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
435694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void setTouchModifier(String modifier, boolean enabled) {
436694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        Bundle bundle = new Bundle();
437694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putString("modifier", modifier);
438694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        bundle.putBoolean("enabled", enabled);
439694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.obtainMessage(MSG_SET_TOUCH_MODIFIER, bundle).sendToTarget();
440694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
441694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
442694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    public void clearTouchPoints() {
443694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mEventSenderHandler.sendEmptyMessage(MSG_CLEAR_TOUCH_POINTS);
444694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
445694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
44689a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk    private List<TouchPoint> getTouchPoints() {
44789a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk        if (mTouchPoints == null) {
448694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            mTouchPoints = new LinkedList<TouchPoint>();
449694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
450694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
451694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        return mTouchPoints;
452694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    }
45389a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk
454b45c0c9774bd19a9dbe77d149abae4e124b08bf6Romain Guy    private void executeTouchEvent(int action) {
455694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int numPoints = getTouchPoints().size();
456694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        int[] pointerIds = new int[numPoints];
457694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        MotionEvent.PointerCoords[] pointerCoords = new MotionEvent.PointerCoords[numPoints];
458694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
459694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        for (int i = 0; i < numPoints; ++i) {
460694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            boolean isNeeded = false;
46144984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            switch(action) {
46244984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            case MotionEvent.ACTION_DOWN:
46344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            case MotionEvent.ACTION_UP:
46444984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                isNeeded = true;
46544984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                break;
46644984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            case MotionEvent.ACTION_MOVE:
46744984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                isNeeded = getTouchPoints().get(i).hasMoved();
46889a524ac2d4a36739e51b01b336c0bade77e2ee0Alex Sakhartchouk                break;
4691de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy            case MotionEvent.ACTION_CANCEL:
4701de1083e98cde9bdd5e8539dbc54fdea6531906eRomain Guy                isNeeded = getTouchPoints().get(i).isCancelled();
471694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                break;
472694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            default:
47344984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                Log.w(LOG_TAG + "::executeTouchEvent(),", "action not supported:" + action);
47444984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                break;
47544984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            }
476694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
477694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            numPoints = 0;
478694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            if (isNeeded) {
47944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase                pointerIds[numPoints] = getTouchPoints().get(i).getId();
4809b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                pointerCoords[numPoints] = new MotionEvent.PointerCoords();
48161c8c9c5b2006d18e9310b6521c65b36ffe75ce4Romain Guy                pointerCoords[numPoints].x = getTouchPoints().get(i).getX();
482694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                pointerCoords[numPoints].y = getTouchPoints().get(i).getY();
483e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy                ++numPoints;
484e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy            }
485e8cb9c14309b0f01c0159efdf9a7198f44a62642Romain Guy        }
486694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
487694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (numPoints == 0) {
488694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return;
489694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
490694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
491694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        MotionEvent event = MotionEvent.obtain(mTouchPoints.get(0).getDownTime(),
4927975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy                SystemClock.uptimeMillis(), action,
493694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                numPoints, pointerIds, pointerCoords,
4947975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy                mTouchMetaState, 1.0f, 1.0f, 0, 0, 0, 0);
495694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
4967975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy        mWebView.onTouchEvent(event);
49765ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk    }
4987975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy
499694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy    private void executeKeyEvent(int action, int keyCode) {
5007975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy        KeyEvent event = new KeyEvent(action, keyCode);
501694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        mWebView.onKeyDown(event.getKeyCode(), event);
5027975fb6d12cb1eb96b75e3a563627cd4c4081bd6Romain Guy    }
503694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
50444984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    /**
50544984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase     * Assumes lowercase chars, case needs to be handled by calling function.
50644984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase     */
50744984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase    private static int charToKeyCode(char c) {
50844984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase        // handle numbers
50944984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase        if (c >= '0' && c <= '9') {
51044984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            int offset = c - '0';
51144984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase            return KeyEvent.KEYCODE_0 + offset;
51244984ea0cb3702384d023b5f211deda3c4b0b656Chet Haase        }
51351769a68a5cb34e9564740c6a854fcb93018789dRomain Guy
514694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        // handle characters
515694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        if (c >= 'a' && c <= 'z') {
516694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            int offset = c - 'a';
517694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            return KeyEvent.KEYCODE_A + offset;
518694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        }
519694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
52051769a68a5cb34e9564740c6a854fcb93018789dRomain Guy        // handle all others
521694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy        switch (c) {
522694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '*':
523694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_STAR;
524694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
525694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '#':
526694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_POUND;
527694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
528694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case ',':
529694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_COMMA;
530694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
531694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '.':
532694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_PERIOD;
533694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
534694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '\t':
535694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_TAB;
536694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5375d794412e3e429e47404395badcd11b0b8639e8bRomain Guy            case ' ':
5385d794412e3e429e47404395badcd11b0b8639e8bRomain Guy                return KeyEvent.KEYCODE_SPACE;
5395d794412e3e429e47404395badcd11b0b8639e8bRomain Guy
540694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '\n':
541694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_ENTER;
542694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
543694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '\b':
544694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case 0x7F:
545694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_DEL;
5469b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5479b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            case '~':
548694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_GRAVE;
549694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
550694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '-':
551694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_MINUS;
552694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
553694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '=':
554694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_EQUALS;
555694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
556694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case '(':
557694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_LEFT_BRACKET;
558694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
55965ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk            case ')':
56065ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk                return KeyEvent.KEYCODE_RIGHT_BRACKET;
56165ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
56265ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk            case '\\':
56365ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk                return KeyEvent.KEYCODE_BACKSLASH;
56465ef909776c03417d8b597738da54ca211e37e4fAlex Sakhartchouk
565694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy            case ';':
566694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy                return KeyEvent.KEYCODE_SEMICOLON;
567694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy
5689b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            case '\'':
5699b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                return KeyEvent.KEYCODE_APOSTROPHE;
5709b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5719b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            case '/':
5729b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                return KeyEvent.KEYCODE_SLASH;
5739b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5749b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            default:
5759b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk                return c;
5769b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        }
5779b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
5789b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5799b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    private static int modifierToKeyCode(String modifier) {
5809b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        if (modifier.equals("ctrlKey")) {
5819b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            return KeyEvent.KEYCODE_ALT_LEFT;
5829b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        } else if (modifier.equals("shiftKey")) {
5831e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy            return KeyEvent.KEYCODE_SHIFT_LEFT;
5849b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        } else if (modifier.equals("altKey")) {
5859b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk            return KeyEvent.KEYCODE_SYM;
5861e45aae5de003657e5d18f74d34998f5de5db5b7Romain Guy        }
5879b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk
5889b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk        return KeyEvent.KEYCODE_UNKNOWN;
5899b9902ddbb01548f4a0199087b7035e7c10b2ae7Alex Sakhartchouk    }
590694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy}
591694b519ac647fe998fd396fe0784cc8e179aadc4Romain Guy