7409955bc9cb441978e306e5b8815c76900c6db7
[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 int64 ToAndroidTime(base::TimeTicks time) {
58   return (time - base::TimeTicks()).InMilliseconds();
59 }
60
61 base::TimeTicks FromAndroidTime(int64 time_ms) {
62   return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
63 }
64
65 }  // namespace
66
67 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
68                                        JNIEnv* env,
69                                        jobject event,
70                                        jlong time_ms,
71                                        jint android_action,
72                                        jint pointer_count,
73                                        jint history_size,
74                                        jint action_index,
75                                        jfloat pos_x_0_pixels,
76                                        jfloat pos_y_0_pixels,
77                                        jfloat pos_x_1_pixels,
78                                        jfloat pos_y_1_pixels,
79                                        jint pointer_id_0,
80                                        jint pointer_id_1,
81                                        jfloat touch_major_0_pixels,
82                                        jfloat touch_major_1_pixels,
83                                        jfloat raw_pos_x_pixels,
84                                        jfloat raw_pos_y_pixels)
85     : cached_time_(FromAndroidTime(time_ms)),
86       cached_action_(FromAndroidAction(android_action)),
87       cached_pointer_count_(pointer_count),
88       cached_history_size_(history_size),
89       cached_action_index_(action_index),
90       pix_to_dip_(pix_to_dip),
91       should_recycle_(false) {
92   DCHECK_GT(pointer_count, 0);
93   DCHECK_GE(history_size, 0);
94
95   event_.Reset(env, event);
96   DCHECK(event_.obj());
97
98   cached_positions_[0] = ToDips(gfx::PointF(pos_x_0_pixels, pos_y_0_pixels));
99   cached_positions_[1] = ToDips(gfx::PointF(pos_x_1_pixels, pos_y_1_pixels));
100   cached_pointer_ids_[0] = pointer_id_0;
101   cached_pointer_ids_[1] = pointer_id_1;
102   cached_touch_majors_[0] = ToDips(touch_major_0_pixels);
103   cached_touch_majors_[1] = ToDips(touch_major_1_pixels);
104   cached_raw_position_offset_ =
105       ToDips(gfx::PointF(raw_pos_x_pixels, raw_pos_y_pixels)) -
106       cached_positions_[0];
107 }
108
109 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
110                                        JNIEnv* env,
111                                        jobject event)
112     : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))),
113       cached_action_(
114           FromAndroidAction(Java_MotionEvent_getActionMasked(env, event))),
115       cached_pointer_count_(Java_MotionEvent_getPointerCount(env, event)),
116       cached_history_size_(Java_MotionEvent_getHistorySize(env, event)),
117       cached_action_index_(Java_MotionEvent_getActionIndex(env, event)),
118       pix_to_dip_(pix_to_dip),
119       should_recycle_(true) {
120   event_.Reset(env, event);
121   DCHECK(event_.obj());
122
123   for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
124     if (i < cached_pointer_count_) {
125       cached_positions_[i] =
126           ToDips(gfx::PointF(Java_MotionEvent_getXF_I(env, event, i),
127                              Java_MotionEvent_getYF_I(env, event, i)));
128       cached_pointer_ids_[i] = Java_MotionEvent_getPointerId(env, event, i);
129       cached_touch_majors_[i] =
130           ToDips(Java_MotionEvent_getTouchMajorF_I(env, event, i));
131     } else {
132       cached_pointer_ids_[i] = 0;
133       cached_touch_majors_[i] = 0.f;
134     }
135   }
136
137   cached_raw_position_offset_ =
138       ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event),
139                          Java_MotionEvent_getRawY(env, event))) -
140       cached_positions_[0];
141 }
142
143 MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& other)
144     : event_(Obtain(other)),
145       cached_time_(other.cached_time_),
146       cached_action_(other.cached_action_),
147       cached_pointer_count_(other.cached_pointer_count_),
148       cached_history_size_(other.cached_history_size_),
149       cached_action_index_(other.cached_action_index_),
150       cached_raw_position_offset_(other.cached_raw_position_offset_),
151       pix_to_dip_(other.pix_to_dip_),
152       should_recycle_(true) {
153   DCHECK(event_.obj());
154   for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) {
155     cached_positions_[i] = other.cached_positions_[i];
156     cached_pointer_ids_[i] = other.cached_pointer_ids_[i];
157     cached_touch_majors_[i] = other.cached_touch_majors_[i];
158   }
159 }
160
161 MotionEventAndroid::~MotionEventAndroid() {
162   if (should_recycle_)
163     Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj());
164 }
165
166 int MotionEventAndroid::GetId() const {
167   return 0;
168 }
169
170 MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
171   return cached_action_;
172 }
173
174 int MotionEventAndroid::GetActionIndex() const {
175   return cached_action_index_;
176 }
177
178 size_t MotionEventAndroid::GetPointerCount() const {
179   return cached_pointer_count_;
180 }
181
182 int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
183   DCHECK_LT(pointer_index, cached_pointer_count_);
184   if (pointer_index < MAX_POINTERS_TO_CACHE)
185     return cached_pointer_ids_[pointer_index];
186   return Java_MotionEvent_getPointerId(
187       AttachCurrentThread(), event_.obj(), pointer_index);
188 }
189
190 float MotionEventAndroid::GetX(size_t pointer_index) const {
191   DCHECK_LT(pointer_index, cached_pointer_count_);
192   if (pointer_index < MAX_POINTERS_TO_CACHE)
193     return cached_positions_[pointer_index].x();
194   return ToDips(Java_MotionEvent_getXF_I(
195       AttachCurrentThread(), event_.obj(), pointer_index));
196 }
197
198 float MotionEventAndroid::GetY(size_t pointer_index) const {
199   DCHECK_LT(pointer_index, cached_pointer_count_);
200   if (pointer_index < MAX_POINTERS_TO_CACHE)
201     return cached_positions_[pointer_index].y();
202   return ToDips(Java_MotionEvent_getYF_I(
203       AttachCurrentThread(), event_.obj(), pointer_index));
204 }
205
206 float MotionEventAndroid::GetRawX(size_t pointer_index) const {
207   return GetX(pointer_index) + cached_raw_position_offset_.x();
208 }
209
210 float MotionEventAndroid::GetRawY(size_t pointer_index) const {
211   return GetY(pointer_index) + cached_raw_position_offset_.y();
212 }
213
214 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const {
215   DCHECK_LT(pointer_index, cached_pointer_count_);
216   if (pointer_index < MAX_POINTERS_TO_CACHE)
217     return cached_touch_majors_[pointer_index];
218   return ToDips(Java_MotionEvent_getTouchMajorF_I(
219       AttachCurrentThread(), event_.obj(), pointer_index));
220 }
221
222 float MotionEventAndroid::GetPressure(size_t pointer_index) const {
223   DCHECK_LT(pointer_index, cached_pointer_count_);
224   return Java_MotionEvent_getPressureF_I(
225       AttachCurrentThread(), event_.obj(), pointer_index);
226 }
227
228 base::TimeTicks MotionEventAndroid::GetEventTime() const {
229   return cached_time_;
230 }
231
232 size_t MotionEventAndroid::GetHistorySize() const {
233   return cached_history_size_;
234 }
235
236 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime(
237     size_t historical_index) const {
238   return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
239       AttachCurrentThread(), event_.obj(), historical_index));
240 }
241
242 float MotionEventAndroid::GetHistoricalTouchMajor(
243     size_t pointer_index,
244     size_t historical_index) const {
245   return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I(
246       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
247 }
248
249 float MotionEventAndroid::GetHistoricalX(size_t pointer_index,
250                                          size_t historical_index) const {
251   return ToDips(Java_MotionEvent_getHistoricalXF_I_I(
252       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
253 }
254
255 float MotionEventAndroid::GetHistoricalY(size_t pointer_index,
256                                          size_t historical_index) const {
257   return ToDips(Java_MotionEvent_getHistoricalYF_I_I(
258       AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
259 }
260
261 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const {
262   return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this));
263 }
264
265 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Cancel() const {
266   // The input coordinates to |MotionEventAndroid| are always in device pixels,
267   // but the cached coordinates are in DIPs.
268   const gfx::PointF position_pixels =
269       gfx::ScalePoint(cached_positions_[0], 1.f / pix_to_dip_);
270   return scoped_ptr<MotionEvent>(
271       new MotionEventAndroid(pix_to_dip_,
272                              AttachCurrentThread(),
273                              Obtain(GetDownTime(),
274                                     GetEventTime(),
275                                     MotionEventAndroid::ACTION_CANCEL,
276                                     position_pixels.x(),
277                                     position_pixels.y()).obj()));
278 }
279
280 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
281   return ToDips(Java_MotionEvent_getTouchMinorF_I(
282       AttachCurrentThread(), event_.obj(), pointer_index));
283 }
284
285 float MotionEventAndroid::GetOrientation() const {
286   return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_.obj());
287 }
288
289 base::TimeTicks MotionEventAndroid::GetDownTime() const {
290   return FromAndroidTime(
291       Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj()));
292 }
293
294 float MotionEventAndroid::ToDips(float pixels) const {
295   return pixels * pix_to_dip_;
296 }
297
298 gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const {
299   return gfx::ScalePoint(point_pixels, pix_to_dip_);
300 }
301
302 // static
303 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
304   return JNI_MotionEvent::RegisterNativesImpl(env);
305 }
306
307 // static
308 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
309     const MotionEventAndroid& event) {
310   return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
311                                           event.event_.obj());
312 }
313
314 // static
315 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
316     base::TimeTicks down_time,
317     base::TimeTicks event_time,
318     Action action,
319     float x_pixels,
320     float y_pixels) {
321   return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
322                                                  ToAndroidTime(down_time),
323                                                  ToAndroidTime(event_time),
324                                                  ToAndroidAction(action),
325                                                  x_pixels,
326                                                  y_pixels,
327                                                  0);
328 }
329
330 }  // namespace content