Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / input / motion_event_android.cc
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
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
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
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     case TOOL_TYPE_ERASER:
68       return MotionEventAndroid::TOOL_TYPE_ERASER;
69     default:
70       NOTREACHED() << "Invalid Android MotionEvent tool type: "
71                    << android_tool_type;
72   };
73   return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
74 }
75
76 int FromAndroidButtonState(int button_state) {
77   int result = 0;
78   if ((button_state & BUTTON_BACK) != 0)
79     result |= MotionEventAndroid::BUTTON_BACK;
80   if ((button_state & BUTTON_FORWARD) != 0)
81     result |= MotionEventAndroid::BUTTON_FORWARD;
82   if ((button_state & BUTTON_PRIMARY) != 0)
83     result |= MotionEventAndroid::BUTTON_PRIMARY;
84   if ((button_state & BUTTON_SECONDARY) != 0)
85     result |= MotionEventAndroid::BUTTON_SECONDARY;
86   if ((button_state & BUTTON_TERTIARY) != 0)
87     result |= MotionEventAndroid::BUTTON_TERTIARY;
88   return result;
89 }
90
91 int64 ToAndroidTime(base::TimeTicks time) {
92   return (time - base::TimeTicks()).InMilliseconds();
93 }
94
95 base::TimeTicks FromAndroidTime(int64 time_ms) {
96   return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
97 }
98
99 }  // namespace
100
101 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
102                                        JNIEnv* env,
103                                        jobject event,
104                                        jlong time_ms,
105                                        jint android_action,
106                                        jint pointer_count,
107                                        jint history_size,
108                                        jint action_index,
109                                        jfloat pos_x_0_pixels,
110                                        jfloat pos_y_0_pixels,
111                                        jfloat pos_x_1_pixels,
112                                        jfloat pos_y_1_pixels,
113                                        jint pointer_id_0,
114                                        jint pointer_id_1,
115                                        jfloat touch_major_0_pixels,
116                                        jfloat touch_major_1_pixels,
117                                        jfloat raw_pos_x_pixels,
118                                        jfloat raw_pos_y_pixels,
119                                        jint android_tool_type_0,
120                                        jint android_tool_type_1,
121                                        jint android_button_state)
122     : cached_time_(FromAndroidTime(time_ms)),
123       cached_action_(FromAndroidAction(android_action)),
124       cached_pointer_count_(pointer_count),
125       cached_history_size_(history_size),
126       cached_action_index_(action_index),
127       cached_button_state_(FromAndroidButtonState(android_button_state)),
128       pix_to_dip_(pix_to_dip),
129       should_recycle_(false) {
130   DCHECK_GT(pointer_count, 0);
131   DCHECK_GE(history_size, 0);
132
133   event_.Reset(env, event);
134   DCHECK(event_.obj());
135
136   cached_positions_[0] = ToDips(gfx::PointF(pos_x_0_pixels, pos_y_0_pixels));
137   cached_positions_[1] = ToDips(gfx::PointF(pos_x_1_pixels, pos_y_1_pixels));
138   cached_pointer_ids_[0] = pointer_id_0;
139   cached_pointer_ids_[1] = pointer_id_1;
140   cached_touch_majors_[0] = ToDips(touch_major_0_pixels);
141   cached_touch_majors_[1] = ToDips(touch_major_1_pixels);
142   cached_raw_position_offset_ =
143       ToDips(gfx::PointF(raw_pos_x_pixels, raw_pos_y_pixels)) -
144       cached_positions_[0];
145   cached_tool_types_[0] = FromAndroidToolType(android_tool_type_0);
146   cached_tool_types_[1] = FromAndroidToolType(android_tool_type_1);
147 }
148
149 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
150                                        JNIEnv* env,
151                                        jobject event)
152     : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))),
153       cached_action_(
154           FromAndroidAction(Java_MotionEvent_getActionMasked(env, event))),
155       cached_pointer_count_(Java_MotionEvent_getPointerCount(env, event)),
156       cached_history_size_(Java_MotionEvent_getHistorySize(env, event)),
157       cached_action_index_(Java_MotionEvent_getActionIndex(env, event)),
158       cached_button_state_(
159           FromAndroidButtonState(Java_MotionEvent_getButtonState(env, event))),
160       pix_to_dip_(pix_to_dip),
161       should_recycle_(true) {
162   event_.Reset(env, event);
163   DCHECK(event_.obj());
164
165   for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
166     if (i < cached_pointer_count_) {
167       cached_positions_[i] =
168           ToDips(gfx::PointF(Java_MotionEvent_getXF_I(env, event, i),
169                              Java_MotionEvent_getYF_I(env, event, i)));
170       cached_pointer_ids_[i] = Java_MotionEvent_getPointerId(env, event, i);
171       cached_touch_majors_[i] =
172           ToDips(Java_MotionEvent_getTouchMajorF_I(env, event, i));
173       cached_tool_types_[i] =
174           FromAndroidToolType(Java_MotionEvent_getToolType(env, event, i));
175     } else {
176       cached_pointer_ids_[i] = 0;
177       cached_touch_majors_[i] = 0.f;
178       cached_tool_types_[i] = MotionEvent::TOOL_TYPE_UNKNOWN;
179     }
180   }
181
182   cached_raw_position_offset_ =
183       ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event),
184                          Java_MotionEvent_getRawY(env, event))) -
185       cached_positions_[0];
186 }
187
188 MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& other)
189     : event_(Obtain(other)),
190       cached_time_(other.cached_time_),
191       cached_action_(other.cached_action_),
192       cached_pointer_count_(other.cached_pointer_count_),
193       cached_history_size_(other.cached_history_size_),
194       cached_action_index_(other.cached_action_index_),
195       cached_raw_position_offset_(other.cached_raw_position_offset_),
196       cached_button_state_(other.cached_button_state_),
197       pix_to_dip_(other.pix_to_dip_),
198       should_recycle_(true) {
199   DCHECK(event_.obj());
200   for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
201     cached_positions_[i] = other.cached_positions_[i];
202     cached_pointer_ids_[i] = other.cached_pointer_ids_[i];
203     cached_touch_majors_[i] = other.cached_touch_majors_[i];
204     cached_tool_types_[i] = other.cached_tool_types_[i];
205   }
206 }
207
208 MotionEventAndroid::~MotionEventAndroid() {
209   if (should_recycle_)
210     Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj());
211 }
212
213 int MotionEventAndroid::GetId() const {
214   return 0;
215 }
216
217 MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
218   return cached_action_;
219 }
220
221 int MotionEventAndroid::GetActionIndex() const {
222   return cached_action_index_;
223 }
224
225 size_t MotionEventAndroid::GetPointerCount() const {
226   return cached_pointer_count_;
227 }
228
229 int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
230   DCHECK_LT(pointer_index, cached_pointer_count_);
231   if (pointer_index < MAX_POINTERS_TO_CACHE)
232     return cached_pointer_ids_[pointer_index];
233   return Java_MotionEvent_getPointerId(
234       AttachCurrentThread(), event_.obj(), pointer_index);
235 }
236
237 float MotionEventAndroid::GetX(size_t pointer_index) const {
238   DCHECK_LT(pointer_index, cached_pointer_count_);
239   if (pointer_index < MAX_POINTERS_TO_CACHE)
240     return cached_positions_[pointer_index].x();
241   return ToDips(Java_MotionEvent_getXF_I(
242       AttachCurrentThread(), event_.obj(), pointer_index));
243 }
244
245 float MotionEventAndroid::GetY(size_t pointer_index) const {
246   DCHECK_LT(pointer_index, cached_pointer_count_);
247   if (pointer_index < MAX_POINTERS_TO_CACHE)
248     return cached_positions_[pointer_index].y();
249   return ToDips(Java_MotionEvent_getYF_I(
250       AttachCurrentThread(), event_.obj(), pointer_index));
251 }
252
253 float MotionEventAndroid::GetRawX(size_t pointer_index) const {
254   return GetX(pointer_index) + cached_raw_position_offset_.x();
255 }
256
257 float MotionEventAndroid::GetRawY(size_t pointer_index) const {
258   return GetY(pointer_index) + cached_raw_position_offset_.y();
259 }
260
261 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const {
262   DCHECK_LT(pointer_index, cached_pointer_count_);
263   if (pointer_index < MAX_POINTERS_TO_CACHE)
264     return cached_touch_majors_[pointer_index];
265   return ToDips(Java_MotionEvent_getTouchMajorF_I(
266       AttachCurrentThread(), event_.obj(), pointer_index));
267 }
268
269 float MotionEventAndroid::GetPressure(size_t pointer_index) const {
270   DCHECK_LT(pointer_index, cached_pointer_count_);
271   return Java_MotionEvent_getPressureF_I(
272       AttachCurrentThread(), event_.obj(), pointer_index);
273 }
274
275 base::TimeTicks MotionEventAndroid::GetEventTime() const {
276   return cached_time_;
277 }
278
279 size_t MotionEventAndroid::GetHistorySize() const {
280   return cached_history_size_;
281 }
282
283 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime(
284     size_t historical_index) const {
285   return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
286       AttachCurrentThread(), event_.obj(), historical_index));
287 }
288
289 float MotionEventAndroid::GetHistoricalTouchMajor(
290     size_t pointer_index,
291     size_t historical_index) const {
292   return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I(
293       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
294 }
295
296 float MotionEventAndroid::GetHistoricalX(size_t pointer_index,
297                                          size_t historical_index) const {
298   return ToDips(Java_MotionEvent_getHistoricalXF_I_I(
299       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
300 }
301
302 float MotionEventAndroid::GetHistoricalY(size_t pointer_index,
303                                          size_t historical_index) const {
304   return ToDips(Java_MotionEvent_getHistoricalYF_I_I(
305       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
306 }
307
308 ui::MotionEvent::ToolType MotionEventAndroid::GetToolType(
309     size_t pointer_index) const {
310   DCHECK_LT(pointer_index, cached_pointer_count_);
311   if (pointer_index < MAX_POINTERS_TO_CACHE)
312     return cached_tool_types_[pointer_index];
313   return FromAndroidToolType(Java_MotionEvent_getToolType(
314       AttachCurrentThread(), event_.obj(), pointer_index));
315 }
316
317 int MotionEventAndroid::GetButtonState() const {
318   return cached_button_state_;
319 }
320
321 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const {
322   return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this));
323 }
324
325 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Cancel() const {
326   // The input coordinates to |MotionEventAndroid| are always in device pixels,
327   // but the cached coordinates are in DIPs.
328   const gfx::PointF position_pixels =
329       gfx::ScalePoint(cached_positions_[0], 1.f / pix_to_dip_);
330   return scoped_ptr<MotionEvent>(
331       new MotionEventAndroid(pix_to_dip_,
332                              AttachCurrentThread(),
333                              Obtain(GetDownTime(),
334                                     GetEventTime(),
335                                     MotionEventAndroid::ACTION_CANCEL,
336                                     position_pixels.x(),
337                                     position_pixels.y()).obj()));
338 }
339
340 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
341   return ToDips(Java_MotionEvent_getTouchMinorF_I(
342       AttachCurrentThread(), event_.obj(), pointer_index));
343 }
344
345 float MotionEventAndroid::GetOrientation() const {
346   return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_.obj());
347 }
348
349 base::TimeTicks MotionEventAndroid::GetDownTime() const {
350   return FromAndroidTime(
351       Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj()));
352 }
353
354 float MotionEventAndroid::ToDips(float pixels) const {
355   return pixels * pix_to_dip_;
356 }
357
358 gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const {
359   return gfx::ScalePoint(point_pixels, pix_to_dip_);
360 }
361
362 // static
363 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
364   return JNI_MotionEvent::RegisterNativesImpl(env);
365 }
366
367 // static
368 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
369     const MotionEventAndroid& event) {
370   return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
371                                           event.event_.obj());
372 }
373
374 // static
375 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
376     base::TimeTicks down_time,
377     base::TimeTicks event_time,
378     Action action,
379     float x_pixels,
380     float y_pixels) {
381   return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
382                                                  ToAndroidTime(down_time),
383                                                  ToAndroidTime(event_time),
384                                                  ToAndroidAction(action),
385                                                  x_pixels,
386                                                  y_pixels,
387                                                  0);
388 }
389
390 }  // namespace content