1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.content.browser; |
6 | |
7 | import android.util.Log; |
8 | import android.view.MotionEvent; |
9 | |
10 | import org.chromium.base.CalledByNative; |
11 | |
12 | // This class converts android MotionEvent into an array of touch points so |
13 | // that they can be forwarded to the renderer process. |
14 | class TouchPoint { |
15 | |
16 | public static final int CONVERSION_ERROR = -1; |
17 | |
18 | // Type of motion event to send to the native side. The values originate from their |
19 | // webkit WebInputEvent counterparts, and are set via initializeConstants(). |
20 | static int TOUCH_EVENT_TYPE_START; |
21 | static int TOUCH_EVENT_TYPE_MOVE; |
22 | static int TOUCH_EVENT_TYPE_END; |
23 | static int TOUCH_EVENT_TYPE_CANCEL; |
24 | |
25 | // Type of motion event to send to the native side. The values originate from their |
26 | // webkit WebTouchPoint counterparts, and are set via initializeConstants(). |
27 | private static int TOUCH_POINT_STATE_UNDEFINED; |
28 | private static int TOUCH_POINT_STATE_RELEASED; |
29 | private static int TOUCH_POINT_STATE_PRESSED; |
30 | private static int TOUCH_POINT_STATE_MOVED; |
31 | private static int TOUCH_POINT_STATE_STATIONARY; |
32 | private static int TOUCH_POINT_STATE_CANCELLED; |
33 | |
34 | private final int mState; |
35 | private final int mId; |
36 | private final float mX; |
37 | private final float mY; |
38 | private final float mSize; |
39 | private final float mPressure; |
40 | |
41 | TouchPoint(int state, int id, float x, float y, float size, float pressure) { |
42 | mState = state; |
43 | mId = id; |
44 | mX = x; |
45 | mY = y; |
46 | mSize = size; |
47 | mPressure = pressure; |
48 | } |
49 | |
50 | // The following methods are called by native to parse the java TouchPoint |
51 | // object it has received. |
52 | @SuppressWarnings("unused") |
53 | @CalledByNative |
54 | public int getState() { return mState; } |
55 | |
56 | @SuppressWarnings("unused") |
57 | @CalledByNative |
58 | public int getId() { return mId; } |
59 | |
60 | @SuppressWarnings("unused") |
61 | @CalledByNative |
62 | public int getX() { return (int) mX; } |
63 | |
64 | @SuppressWarnings("unused") |
65 | @CalledByNative |
66 | public int getY() { return (int) mY; } |
67 | |
68 | @SuppressWarnings("unused") |
69 | @CalledByNative |
70 | public double getSize() { return mSize; } |
71 | |
72 | @SuppressWarnings("unused") |
73 | @CalledByNative |
74 | public double getPressure() { return mPressure; } |
75 | |
76 | // Converts a MotionEvent into an array of touch points. |
77 | // Returns the WebTouchEvent::Type for the MotionEvent and -1 for failure. |
78 | public static int createTouchPoints(MotionEvent event, TouchPoint[] pts) { |
79 | int type; |
80 | int defaultState; |
81 | |
82 | switch (event.getActionMasked()) { |
83 | case MotionEvent.ACTION_DOWN: |
84 | type = TOUCH_EVENT_TYPE_START; |
85 | defaultState = TOUCH_POINT_STATE_PRESSED; |
86 | break; |
87 | case MotionEvent.ACTION_MOVE: |
88 | type = TOUCH_EVENT_TYPE_MOVE; |
89 | defaultState = TOUCH_POINT_STATE_MOVED; |
90 | break; |
91 | case MotionEvent.ACTION_UP: |
92 | type = TOUCH_EVENT_TYPE_END; |
93 | defaultState = TOUCH_POINT_STATE_RELEASED; |
94 | break; |
95 | case MotionEvent.ACTION_CANCEL: |
96 | type = TOUCH_EVENT_TYPE_CANCEL; |
97 | defaultState = TOUCH_POINT_STATE_CANCELLED; |
98 | break; |
99 | case MotionEvent.ACTION_POINTER_DOWN: // fall through. |
100 | case MotionEvent.ACTION_POINTER_UP: |
101 | type = TOUCH_EVENT_TYPE_MOVE; |
102 | defaultState = TOUCH_POINT_STATE_STATIONARY; |
103 | break; |
104 | default: |
105 | Log.e("Chromium", "Unknown motion event action: " + event.getActionMasked()); |
106 | return CONVERSION_ERROR; |
107 | } |
108 | |
109 | for (int i = 0; i < pts.length; ++i) { |
110 | int state = defaultState; |
111 | if (defaultState == TOUCH_POINT_STATE_STATIONARY && event.getActionIndex() == i) { |
112 | // An additional pointer has started or ended. Map this pointer state as |
113 | // required, and all other pointers as "stationary". |
114 | state = event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN ? |
115 | TOUCH_POINT_STATE_PRESSED : TOUCH_POINT_STATE_RELEASED; |
116 | } |
117 | pts[i] = new TouchPoint(state, event.getPointerId(i), |
118 | event.getX(i), event.getY(i), |
119 | event.getSize(i), event.getPressure(i)); |
120 | } |
121 | |
122 | return type; |
123 | } |
124 | |
125 | // This method is called by native to initialize all the constants from |
126 | // their counterparts in WebInputEvent and WebTouchPoint. |
127 | @SuppressWarnings("unused") |
128 | @CalledByNative |
129 | private static void initializeConstants( |
130 | int touchTypeStart, int touchTypeMove, int touchTypeEnd, int touchTypeCancel, |
131 | int touchPointUndefined, int touchPointReleased, int touchPointPressed, |
132 | int touchPointMoved, int touchPointStationary, int touchPointCancelled) { |
133 | TOUCH_EVENT_TYPE_START = touchTypeStart; |
134 | TOUCH_EVENT_TYPE_MOVE = touchTypeMove; |
135 | TOUCH_EVENT_TYPE_END = touchTypeEnd; |
136 | TOUCH_EVENT_TYPE_CANCEL = touchTypeCancel; |
137 | TOUCH_POINT_STATE_UNDEFINED = touchPointUndefined; |
138 | TOUCH_POINT_STATE_RELEASED = touchPointReleased; |
139 | TOUCH_POINT_STATE_PRESSED = touchPointPressed; |
140 | TOUCH_POINT_STATE_MOVED = touchPointMoved; |
141 | TOUCH_POINT_STATE_STATIONARY = touchPointStationary; |
142 | TOUCH_POINT_STATE_CANCELLED = touchPointCancelled; |
143 | } |
144 | |
145 | /** |
146 | * Initialize the constants to distinct values if they have not been initialized. |
147 | * During pure-Java testing, initializeConstants() may not be called by native code. |
148 | * Unit tests should call this method before using the values. |
149 | */ |
150 | static void initializeConstantsForTesting() { |
151 | if (TOUCH_EVENT_TYPE_START == TOUCH_EVENT_TYPE_MOVE) { |
152 | initializeConstants(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
153 | } |
154 | } |
155 | } |