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 int64 ToAndroidTime(base::TimeTicks time) {
58 return (time - base::TimeTicks()).InMilliseconds();
61 base::TimeTicks FromAndroidTime(int64 time_ms) {
62 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
67 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
75 jfloat pos_x_0_pixels,
76 jfloat pos_y_0_pixels,
77 jfloat pos_x_1_pixels,
78 jfloat pos_y_1_pixels,
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);
95 event_.Reset(env, event);
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];
109 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
112 : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))),
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());
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));
132 cached_pointer_ids_[i] = 0;
133 cached_touch_majors_[i] = 0.f;
137 cached_raw_position_offset_ =
138 ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event),
139 Java_MotionEvent_getRawY(env, event))) -
140 cached_positions_[0];
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];
161 MotionEventAndroid::~MotionEventAndroid() {
163 Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj());
166 int MotionEventAndroid::GetId() const {
170 MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
171 return cached_action_;
174 int MotionEventAndroid::GetActionIndex() const {
175 return cached_action_index_;
178 size_t MotionEventAndroid::GetPointerCount() const {
179 return cached_pointer_count_;
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);
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));
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));
206 float MotionEventAndroid::GetRawX(size_t pointer_index) const {
207 return GetX(pointer_index) + cached_raw_position_offset_.x();
210 float MotionEventAndroid::GetRawY(size_t pointer_index) const {
211 return GetY(pointer_index) + cached_raw_position_offset_.y();
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));
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);
228 base::TimeTicks MotionEventAndroid::GetEventTime() const {
232 size_t MotionEventAndroid::GetHistorySize() const {
233 return cached_history_size_;
236 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime(
237 size_t historical_index) const {
238 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
239 AttachCurrentThread(), event_.obj(), historical_index));
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));
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));
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));
261 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const {
262 return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this));
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(),
275 MotionEventAndroid::ACTION_CANCEL,
277 position_pixels.y()).obj()));
280 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
281 return ToDips(Java_MotionEvent_getTouchMinorF_I(
282 AttachCurrentThread(), event_.obj(), pointer_index));
285 float MotionEventAndroid::GetOrientation() const {
286 return Java_MotionEvent_getOrientationF(AttachCurrentThread(), event_.obj());
289 base::TimeTicks MotionEventAndroid::GetDownTime() const {
290 return FromAndroidTime(
291 Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj()));
294 float MotionEventAndroid::ToDips(float pixels) const {
295 return pixels * pix_to_dip_;
298 gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const {
299 return gfx::ScalePoint(point_pixels, pix_to_dip_);
303 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
304 return JNI_MotionEvent::RegisterNativesImpl(env);
308 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
309 const MotionEventAndroid& event) {
310 return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(),
315 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain(
316 base::TimeTicks down_time,
317 base::TimeTicks event_time,
321 return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(),
322 ToAndroidTime(down_time),
323 ToAndroidTime(event_time),
324 ToAndroidAction(action),
330 } // namespace content