• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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