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.
5 #include "content/browser/renderer_host/input/motion_event_android.h"
7 #include "base/android/jni_android.h"
8 #include "jni/MotionEvent_jni.h"
10 using base::android::AttachCurrentThread
;
11 using namespace JNI_MotionEvent
;
16 int ToAndroidAction(MotionEventAndroid::Action action
) {
18 case MotionEventAndroid::ACTION_DOWN
:
20 case MotionEventAndroid::ACTION_UP
:
22 case MotionEventAndroid::ACTION_MOVE
:
24 case MotionEventAndroid::ACTION_CANCEL
:
26 case MotionEventAndroid::ACTION_POINTER_DOWN
:
27 return ACTION_POINTER_DOWN
;
28 case MotionEventAndroid::ACTION_POINTER_UP
:
29 return ACTION_POINTER_UP
;
31 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: "
36 MotionEventAndroid::Action
FromAndroidAction(int android_action
) {
37 switch (android_action
) {
39 return MotionEventAndroid::ACTION_DOWN
;
41 return MotionEventAndroid::ACTION_UP
;
43 return MotionEventAndroid::ACTION_MOVE
;
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
;
51 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: "
54 return MotionEventAndroid::ACTION_CANCEL
;
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
;
66 return MotionEventAndroid::TOOL_TYPE_MOUSE
;
67 case TOOL_TYPE_ERASER
:
68 return MotionEventAndroid::TOOL_TYPE_ERASER
;
70 NOTREACHED() << "Invalid Android MotionEvent tool type: "
73 return MotionEventAndroid::TOOL_TYPE_UNKNOWN
;
76 int FromAndroidButtonState(int button_state
) {
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
;
91 int64
ToAndroidTime(base::TimeTicks time
) {
92 return (time
- base::TimeTicks()).InMilliseconds();
95 base::TimeTicks
FromAndroidTime(int64 time_ms
) {
96 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms
);
101 MotionEventAndroid::MotionEventAndroid(float pix_to_dip
,
109 jfloat pos_x_0_pixels
,
110 jfloat pos_y_0_pixels
,
111 jfloat pos_x_1_pixels
,
112 jfloat pos_y_1_pixels
,
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);
133 event_
.Reset(env
, event
);
134 DCHECK(event_
.obj());
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
);
149 MotionEventAndroid::MotionEventAndroid(float pix_to_dip
,
152 : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env
, event
))),
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());
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
));
176 cached_pointer_ids_
[i
] = 0;
177 cached_touch_majors_
[i
] = 0.f
;
178 cached_tool_types_
[i
] = MotionEvent::TOOL_TYPE_UNKNOWN
;
182 cached_raw_position_offset_
=
183 ToDips(gfx::PointF(Java_MotionEvent_getRawX(env
, event
),
184 Java_MotionEvent_getRawY(env
, event
))) -
185 cached_positions_
[0];
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
];
208 MotionEventAndroid::~MotionEventAndroid() {
210 Java_MotionEvent_recycle(AttachCurrentThread(), event_
.obj());
213 int MotionEventAndroid::GetId() const {
217 MotionEventAndroid::Action
MotionEventAndroid::GetAction() const {
218 return cached_action_
;
221 int MotionEventAndroid::GetActionIndex() const {
222 return cached_action_index_
;
225 size_t MotionEventAndroid::GetPointerCount() const {
226 return cached_pointer_count_
;
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
);
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
));
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
));
253 float MotionEventAndroid::GetRawX(size_t pointer_index
) const {
254 return GetX(pointer_index
) + cached_raw_position_offset_
.x();
257 float MotionEventAndroid::GetRawY(size_t pointer_index
) const {
258 return GetY(pointer_index
) + cached_raw_position_offset_
.y();
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
));
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
);
275 base::TimeTicks
MotionEventAndroid::GetEventTime() const {
279 size_t MotionEventAndroid::GetHistorySize() const {
280 return cached_history_size_
;
283 base::TimeTicks
MotionEventAndroid::GetHistoricalEventTime(
284 size_t historical_index
) const {
285 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
286 AttachCurrentThread(), event_
.obj(), historical_index
));
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
));
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
));
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
));
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
));
317 int MotionEventAndroid::GetButtonState() const {
318 return cached_button_state_
;
321 scoped_ptr
<ui::MotionEvent
> MotionEventAndroid::Clone() const {
322 return scoped_ptr
<MotionEvent
>(new MotionEventAndroid(*this));
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(),
335 MotionEventAndroid::ACTION_CANCEL
,
337 position_pixels
.y()).obj()));
340 float MotionEventAndroid::GetTouchMinor(size_t pointer_index
) const {
341 return ToDips(Java_MotionEvent_getTouchMinorF_I(
342 AttachCurrentThread(), event_
.obj(), pointer_index
));
345 float MotionEventAndroid::GetOrientation() const {
346 return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_
.obj());
349 base::TimeTicks
MotionEventAndroid::GetDownTime() const {
350 return FromAndroidTime(
351 Java_MotionEvent_getDownTime(AttachCurrentThread(), event_
.obj()));
354 float MotionEventAndroid::ToDips(float pixels
) const {
355 return pixels
* pix_to_dip_
;
358 gfx::PointF
MotionEventAndroid::ToDips(const gfx::PointF
& point_pixels
) const {
359 return gfx::ScalePoint(point_pixels
, pix_to_dip_
);
363 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv
* env
) {
364 return JNI_MotionEvent::RegisterNativesImpl(env
);
368 base::android::ScopedJavaLocalRef
<jobject
> MotionEventAndroid::Obtain(
369 const MotionEventAndroid
& event
) {
370 return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
375 base::android::ScopedJavaLocalRef
<jobject
> MotionEventAndroid::Obtain(
376 base::TimeTicks down_time
,
377 base::TimeTicks event_time
,
381 return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
382 ToAndroidTime(down_time
),
383 ToAndroidTime(event_time
),
384 ToAndroidAction(action
),
390 } // namespace content