1 // Copyright 2014 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 #include "content/browser/renderer_host/input/motion_event_android.h"
6
7 #include "base/android/jni_android.h"
8 #include "jni/MotionEvent_jni.h"
9
10 using base::android::AttachCurrentThread;
11 using namespace JNI_MotionEvent;
12
13 namespace content {
14 namespace {
15
ToAndroidAction(MotionEventAndroid::Action action)16 int ToAndroidAction(MotionEventAndroid::Action action) {
17 switch (action) {
18 case MotionEventAndroid::ACTION_DOWN:
19 return ACTION_DOWN;
20 case MotionEventAndroid::ACTION_UP:
21 return ACTION_UP;
22 case MotionEventAndroid::ACTION_MOVE:
23 return ACTION_MOVE;
24 case MotionEventAndroid::ACTION_CANCEL:
25 return ACTION_CANCEL;
26 case MotionEventAndroid::ACTION_POINTER_DOWN:
27 return ACTION_POINTER_DOWN;
28 case MotionEventAndroid::ACTION_POINTER_UP:
29 return ACTION_POINTER_UP;
30 };
31 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: "
32 << action;
33 return ACTION_CANCEL;
34 }
35
FromAndroidAction(int android_action)36 MotionEventAndroid::Action FromAndroidAction(int android_action) {
37 switch (android_action) {
38 case ACTION_DOWN:
39 return MotionEventAndroid::ACTION_DOWN;
40 case ACTION_UP:
41 return MotionEventAndroid::ACTION_UP;
42 case ACTION_MOVE:
43 return MotionEventAndroid::ACTION_MOVE;
44 case ACTION_CANCEL:
45 return MotionEventAndroid::ACTION_CANCEL;
46 case ACTION_POINTER_DOWN:
47 return MotionEventAndroid::ACTION_POINTER_DOWN;
48 case ACTION_POINTER_UP:
49 return MotionEventAndroid::ACTION_POINTER_UP;
50 default:
51 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: "
52 << android_action;
53 };
54 return MotionEventAndroid::ACTION_CANCEL;
55 }
56
FromAndroidToolType(int android_tool_type)57 MotionEventAndroid::ToolType FromAndroidToolType(int android_tool_type) {
58 switch (android_tool_type) {
59 case TOOL_TYPE_UNKNOWN:
60 return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
61 case TOOL_TYPE_FINGER:
62 return MotionEventAndroid::TOOL_TYPE_FINGER;
63 case TOOL_TYPE_STYLUS:
64 return MotionEventAndroid::TOOL_TYPE_STYLUS;
65 case TOOL_TYPE_MOUSE:
66 return MotionEventAndroid::TOOL_TYPE_MOUSE;
67 default:
68 NOTREACHED() << "Invalid Android MotionEvent tool type: "
69 << android_tool_type;
70 };
71 return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
72 }
73
FromAndroidButtonState(int button_state)74 int FromAndroidButtonState(int button_state) {
75 int result = 0;
76 if ((button_state & BUTTON_BACK) != 0)
77 result |= MotionEventAndroid::BUTTON_BACK;
78 if ((button_state & BUTTON_FORWARD) != 0)
79 result |= MotionEventAndroid::BUTTON_FORWARD;
80 if ((button_state & BUTTON_PRIMARY) != 0)
81 result |= MotionEventAndroid::BUTTON_PRIMARY;
82 if ((button_state & BUTTON_SECONDARY) != 0)
83 result |= MotionEventAndroid::BUTTON_SECONDARY;
84 if ((button_state & BUTTON_TERTIARY) != 0)
85 result |= MotionEventAndroid::BUTTON_TERTIARY;
86 return result;
87 }
88
ToAndroidTime(base::TimeTicks time)89 int64 ToAndroidTime(base::TimeTicks time) {
90 return (time - base::TimeTicks()).InMilliseconds();
91 }
92
FromAndroidTime(int64 time_ms)93 base::TimeTicks FromAndroidTime(int64 time_ms) {
94 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
95 }
96
97 } // namespace
98
MotionEventAndroid(float pix_to_dip,JNIEnv * env,jobject event,jlong time_ms,jint android_action,jint pointer_count,jint history_size,jint action_index,jfloat pos_x_0_pixels,jfloat pos_y_0_pixels,jfloat pos_x_1_pixels,jfloat pos_y_1_pixels,jint pointer_id_0,jint pointer_id_1,jfloat touch_major_0_pixels,jfloat touch_major_1_pixels,jfloat raw_pos_x_pixels,jfloat raw_pos_y_pixels,jint android_tool_type_0,jint android_tool_type_1,jint android_button_state)99 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
100 JNIEnv* env,
101 jobject event,
102 jlong time_ms,
103 jint android_action,
104 jint pointer_count,
105 jint history_size,
106 jint action_index,
107 jfloat pos_x_0_pixels,
108 jfloat pos_y_0_pixels,
109 jfloat pos_x_1_pixels,
110 jfloat pos_y_1_pixels,
111 jint pointer_id_0,
112 jint pointer_id_1,
113 jfloat touch_major_0_pixels,
114 jfloat touch_major_1_pixels,
115 jfloat raw_pos_x_pixels,
116 jfloat raw_pos_y_pixels,
117 jint android_tool_type_0,
118 jint android_tool_type_1,
119 jint android_button_state)
120 : cached_time_(FromAndroidTime(time_ms)),
121 cached_action_(FromAndroidAction(android_action)),
122 cached_pointer_count_(pointer_count),
123 cached_history_size_(history_size),
124 cached_action_index_(action_index),
125 cached_button_state_(FromAndroidButtonState(android_button_state)),
126 pix_to_dip_(pix_to_dip),
127 should_recycle_(false) {
128 DCHECK_GT(pointer_count, 0);
129 DCHECK_GE(history_size, 0);
130
131 event_.Reset(env, event);
132 DCHECK(event_.obj());
133
134 cached_positions_[0] = ToDips(gfx::PointF(pos_x_0_pixels, pos_y_0_pixels));
135 cached_positions_[1] = ToDips(gfx::PointF(pos_x_1_pixels, pos_y_1_pixels));
136 cached_pointer_ids_[0] = pointer_id_0;
137 cached_pointer_ids_[1] = pointer_id_1;
138 cached_touch_majors_[0] = ToDips(touch_major_0_pixels);
139 cached_touch_majors_[1] = ToDips(touch_major_1_pixels);
140 cached_raw_position_offset_ =
141 ToDips(gfx::PointF(raw_pos_x_pixels, raw_pos_y_pixels)) -
142 cached_positions_[0];
143 cached_tool_types_[0] = FromAndroidToolType(android_tool_type_0);
144 cached_tool_types_[1] = FromAndroidToolType(android_tool_type_1);
145 }
146
MotionEventAndroid(float pix_to_dip,JNIEnv * env,jobject event)147 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
148 JNIEnv* env,
149 jobject event)
150 : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))),
151 cached_action_(
152 FromAndroidAction(Java_MotionEvent_getActionMasked(env, event))),
153 cached_pointer_count_(Java_MotionEvent_getPointerCount(env, event)),
154 cached_history_size_(Java_MotionEvent_getHistorySize(env, event)),
155 cached_action_index_(Java_MotionEvent_getActionIndex(env, event)),
156 cached_button_state_(
157 FromAndroidButtonState(Java_MotionEvent_getButtonState(env, event))),
158 pix_to_dip_(pix_to_dip),
159 should_recycle_(true) {
160 event_.Reset(env, event);
161 DCHECK(event_.obj());
162
163 for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
164 if (i < cached_pointer_count_) {
165 cached_positions_[i] =
166 ToDips(gfx::PointF(Java_MotionEvent_getXF_I(env, event, i),
167 Java_MotionEvent_getYF_I(env, event, i)));
168 cached_pointer_ids_[i] = Java_MotionEvent_getPointerId(env, event, i);
169 cached_touch_majors_[i] =
170 ToDips(Java_MotionEvent_getTouchMajorF_I(env, event, i));
171 cached_tool_types_[i] =
172 FromAndroidToolType(Java_MotionEvent_getToolType(env, event, i));
173 } else {
174 cached_pointer_ids_[i] = 0;
175 cached_touch_majors_[i] = 0.f;
176 cached_tool_types_[i] = MotionEvent::TOOL_TYPE_UNKNOWN;
177 }
178 }
179
180 cached_raw_position_offset_ =
181 ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event),
182 Java_MotionEvent_getRawY(env, event))) -
183 cached_positions_[0];
184 }
185
MotionEventAndroid(const MotionEventAndroid & other)186 MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& other)
187 : event_(Obtain(other)),
188 cached_time_(other.cached_time_),
189 cached_action_(other.cached_action_),
190 cached_pointer_count_(other.cached_pointer_count_),
191 cached_history_size_(other.cached_history_size_),
192 cached_action_index_(other.cached_action_index_),
193 cached_raw_position_offset_(other.cached_raw_position_offset_),
194 cached_button_state_(other.cached_button_state_),
195 pix_to_dip_(other.pix_to_dip_),
196 should_recycle_(true) {
197 DCHECK(event_.obj());
198 for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
199 cached_positions_[i] = other.cached_positions_[i];
200 cached_pointer_ids_[i] = other.cached_pointer_ids_[i];
201 cached_touch_majors_[i] = other.cached_touch_majors_[i];
202 cached_tool_types_[i] = other.cached_tool_types_[i];
203 }
204 }
205
~MotionEventAndroid()206 MotionEventAndroid::~MotionEventAndroid() {
207 if (should_recycle_)
208 Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj());
209 }
210
GetId() const211 int MotionEventAndroid::GetId() const {
212 return 0;
213 }
214
GetAction() const215 MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
216 return cached_action_;
217 }
218
GetActionIndex() const219 int MotionEventAndroid::GetActionIndex() const {
220 return cached_action_index_;
221 }
222
GetPointerCount() const223 size_t MotionEventAndroid::GetPointerCount() const {
224 return cached_pointer_count_;
225 }
226
GetPointerId(size_t pointer_index) const227 int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
228 DCHECK_LT(pointer_index, cached_pointer_count_);
229 if (pointer_index < MAX_POINTERS_TO_CACHE)
230 return cached_pointer_ids_[pointer_index];
231 return Java_MotionEvent_getPointerId(
232 AttachCurrentThread(), event_.obj(), pointer_index);
233 }
234
GetX(size_t pointer_index) const235 float MotionEventAndroid::GetX(size_t pointer_index) const {
236 DCHECK_LT(pointer_index, cached_pointer_count_);
237 if (pointer_index < MAX_POINTERS_TO_CACHE)
238 return cached_positions_[pointer_index].x();
239 return ToDips(Java_MotionEvent_getXF_I(
240 AttachCurrentThread(), event_.obj(), pointer_index));
241 }
242
GetY(size_t pointer_index) const243 float MotionEventAndroid::GetY(size_t pointer_index) const {
244 DCHECK_LT(pointer_index, cached_pointer_count_);
245 if (pointer_index < MAX_POINTERS_TO_CACHE)
246 return cached_positions_[pointer_index].y();
247 return ToDips(Java_MotionEvent_getYF_I(
248 AttachCurrentThread(), event_.obj(), pointer_index));
249 }
250
GetRawX(size_t pointer_index) const251 float MotionEventAndroid::GetRawX(size_t pointer_index) const {
252 return GetX(pointer_index) + cached_raw_position_offset_.x();
253 }
254
GetRawY(size_t pointer_index) const255 float MotionEventAndroid::GetRawY(size_t pointer_index) const {
256 return GetY(pointer_index) + cached_raw_position_offset_.y();
257 }
258
GetTouchMajor(size_t pointer_index) const259 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const {
260 DCHECK_LT(pointer_index, cached_pointer_count_);
261 if (pointer_index < MAX_POINTERS_TO_CACHE)
262 return cached_touch_majors_[pointer_index];
263 return ToDips(Java_MotionEvent_getTouchMajorF_I(
264 AttachCurrentThread(), event_.obj(), pointer_index));
265 }
266
GetPressure(size_t pointer_index) const267 float MotionEventAndroid::GetPressure(size_t pointer_index) const {
268 DCHECK_LT(pointer_index, cached_pointer_count_);
269 return Java_MotionEvent_getPressureF_I(
270 AttachCurrentThread(), event_.obj(), pointer_index);
271 }
272
GetEventTime() const273 base::TimeTicks MotionEventAndroid::GetEventTime() const {
274 return cached_time_;
275 }
276
GetHistorySize() const277 size_t MotionEventAndroid::GetHistorySize() const {
278 return cached_history_size_;
279 }
280
GetHistoricalEventTime(size_t historical_index) const281 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime(
282 size_t historical_index) const {
283 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
284 AttachCurrentThread(), event_.obj(), historical_index));
285 }
286
GetHistoricalTouchMajor(size_t pointer_index,size_t historical_index) const287 float MotionEventAndroid::GetHistoricalTouchMajor(
288 size_t pointer_index,
289 size_t historical_index) const {
290 return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I(
291 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
292 }
293
GetHistoricalX(size_t pointer_index,size_t historical_index) const294 float MotionEventAndroid::GetHistoricalX(size_t pointer_index,
295 size_t historical_index) const {
296 return ToDips(Java_MotionEvent_getHistoricalXF_I_I(
297 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
298 }
299
GetHistoricalY(size_t pointer_index,size_t historical_index) const300 float MotionEventAndroid::GetHistoricalY(size_t pointer_index,
301 size_t historical_index) const {
302 return ToDips(Java_MotionEvent_getHistoricalYF_I_I(
303 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
304 }
305
GetToolType(size_t pointer_index) const306 ui::MotionEvent::ToolType MotionEventAndroid::GetToolType(
307 size_t pointer_index) const {
308 DCHECK_LT(pointer_index, cached_pointer_count_);
309 if (pointer_index < MAX_POINTERS_TO_CACHE)
310 return cached_tool_types_[pointer_index];
311 return FromAndroidToolType(Java_MotionEvent_getToolType(
312 AttachCurrentThread(), event_.obj(), pointer_index));
313 }
314
GetButtonState() const315 int MotionEventAndroid::GetButtonState() const {
316 return cached_button_state_;
317 }
318
Clone() const319 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const {
320 return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this));
321 }
322
Cancel() const323 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Cancel() const {
324 // The input coordinates to |MotionEventAndroid| are always in device pixels,
325 // but the cached coordinates are in DIPs.
326 const gfx::PointF position_pixels =
327 gfx::ScalePoint(cached_positions_[0], 1.f / pix_to_dip_);
328 return scoped_ptr<MotionEvent>(
329 new MotionEventAndroid(pix_to_dip_,
330 AttachCurrentThread(),
331 Obtain(GetDownTime(),
332 GetEventTime(),
333 MotionEventAndroid::ACTION_CANCEL,
334 position_pixels.x(),
335 position_pixels.y()).obj()));
336 }
337
GetTouchMinor(size_t pointer_index) const338 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
339 return ToDips(Java_MotionEvent_getTouchMinorF_I(
340 AttachCurrentThread(), event_.obj(), pointer_index));
341 }
342
GetOrientation() const343 float MotionEventAndroid::GetOrientation() const {
344 return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_.obj());
345 }
346
GetDownTime() const347 base::TimeTicks MotionEventAndroid::GetDownTime() const {
348 return FromAndroidTime(
349 Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj()));
350 }
351
ToDips(float pixels) const352 float MotionEventAndroid::ToDips(float pixels) const {
353 return pixels * pix_to_dip_;
354 }
355
ToDips(const gfx::PointF & point_pixels) const356 gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const {
357 return gfx::ScalePoint(point_pixels, pix_to_dip_);
358 }
359
360 // static
RegisterMotionEventAndroid(JNIEnv * env)361 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
362 return JNI_MotionEvent::RegisterNativesImpl(env);
363 }
364
365 // static
Obtain(const MotionEventAndroid & event)366 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
367 const MotionEventAndroid& event) {
368 return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
369 event.event_.obj());
370 }
371
372 // static
Obtain(base::TimeTicks down_time,base::TimeTicks event_time,Action action,float x_pixels,float y_pixels)373 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
374 base::TimeTicks down_time,
375 base::TimeTicks event_time,
376 Action action,
377 float x_pixels,
378 float y_pixels) {
379 return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
380 ToAndroidTime(down_time),
381 ToAndroidTime(event_time),
382 ToAndroidAction(action),
383 x_pixels,
384 y_pixels,
385 0);
386 }
387
388 } // namespace content
389