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 <android/input.h> 8 9 #include "base/android/jni_android.h" 10 #include "base/float_util.h" 11 #include "jni/MotionEvent_jni.h" 12 #include "ui/events/event_constants.h" 13 14 using base::android::AttachCurrentThread; 15 using namespace JNI_MotionEvent; 16 17 namespace content { 18 namespace { 19 20 int ToAndroidAction(MotionEventAndroid::Action action) { 21 switch (action) { 22 case MotionEventAndroid::ACTION_DOWN: 23 return ACTION_DOWN; 24 case MotionEventAndroid::ACTION_UP: 25 return ACTION_UP; 26 case MotionEventAndroid::ACTION_MOVE: 27 return ACTION_MOVE; 28 case MotionEventAndroid::ACTION_CANCEL: 29 return ACTION_CANCEL; 30 case MotionEventAndroid::ACTION_POINTER_DOWN: 31 return ACTION_POINTER_DOWN; 32 case MotionEventAndroid::ACTION_POINTER_UP: 33 return ACTION_POINTER_UP; 34 }; 35 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: " 36 << action; 37 return ACTION_CANCEL; 38 } 39 40 MotionEventAndroid::Action FromAndroidAction(int android_action) { 41 switch (android_action) { 42 case ACTION_DOWN: 43 return MotionEventAndroid::ACTION_DOWN; 44 case ACTION_UP: 45 return MotionEventAndroid::ACTION_UP; 46 case ACTION_MOVE: 47 return MotionEventAndroid::ACTION_MOVE; 48 case ACTION_CANCEL: 49 return MotionEventAndroid::ACTION_CANCEL; 50 case ACTION_POINTER_DOWN: 51 return MotionEventAndroid::ACTION_POINTER_DOWN; 52 case ACTION_POINTER_UP: 53 return MotionEventAndroid::ACTION_POINTER_UP; 54 default: 55 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: " 56 << android_action; 57 }; 58 return MotionEventAndroid::ACTION_CANCEL; 59 } 60 61 MotionEventAndroid::ToolType FromAndroidToolType(int android_tool_type) { 62 switch (android_tool_type) { 63 case TOOL_TYPE_UNKNOWN: 64 return MotionEventAndroid::TOOL_TYPE_UNKNOWN; 65 case TOOL_TYPE_FINGER: 66 return MotionEventAndroid::TOOL_TYPE_FINGER; 67 case TOOL_TYPE_STYLUS: 68 return MotionEventAndroid::TOOL_TYPE_STYLUS; 69 case TOOL_TYPE_MOUSE: 70 return MotionEventAndroid::TOOL_TYPE_MOUSE; 71 case TOOL_TYPE_ERASER: 72 return MotionEventAndroid::TOOL_TYPE_ERASER; 73 default: 74 NOTREACHED() << "Invalid Android MotionEvent tool type: " 75 << android_tool_type; 76 }; 77 return MotionEventAndroid::TOOL_TYPE_UNKNOWN; 78 } 79 80 int FromAndroidButtonState(int button_state) { 81 int result = 0; 82 if ((button_state & BUTTON_BACK) != 0) 83 result |= MotionEventAndroid::BUTTON_BACK; 84 if ((button_state & BUTTON_FORWARD) != 0) 85 result |= MotionEventAndroid::BUTTON_FORWARD; 86 if ((button_state & BUTTON_PRIMARY) != 0) 87 result |= MotionEventAndroid::BUTTON_PRIMARY; 88 if ((button_state & BUTTON_SECONDARY) != 0) 89 result |= MotionEventAndroid::BUTTON_SECONDARY; 90 if ((button_state & BUTTON_TERTIARY) != 0) 91 result |= MotionEventAndroid::BUTTON_TERTIARY; 92 return result; 93 } 94 95 int FromAndroidMetaState(int meta_state) { 96 int flags = ui::EF_NONE; 97 if ((meta_state & AMETA_SHIFT_ON) != 0) 98 flags |= ui::EF_SHIFT_DOWN; 99 if ((meta_state & AMETA_CTRL_ON) != 0) 100 flags |= ui::EF_CONTROL_DOWN; 101 if ((meta_state & AMETA_ALT_ON) != 0) 102 flags |= ui::EF_ALT_DOWN; 103 if ((meta_state & AMETA_META_ON) != 0) 104 flags |= ui::EF_COMMAND_DOWN; 105 if ((meta_state & AMETA_CAPS_LOCK_ON) != 0) 106 flags |= ui::EF_CAPS_LOCK_DOWN; 107 return flags; 108 } 109 110 int64 ToAndroidTime(base::TimeTicks time) { 111 return (time - base::TimeTicks()).InMilliseconds(); 112 } 113 114 base::TimeTicks FromAndroidTime(int64 time_ms) { 115 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms); 116 } 117 118 float ToValidFloat(float x) { 119 return base::IsNaN(x) ? 0.f : x; 120 } 121 122 } // namespace 123 124 MotionEventAndroid::MotionEventAndroid(float pix_to_dip, 125 JNIEnv* env, 126 jobject event, 127 jlong time_ms, 128 jint android_action, 129 jint pointer_count, 130 jint history_size, 131 jint action_index, 132 jfloat pos_x_0_pixels, 133 jfloat pos_y_0_pixels, 134 jfloat pos_x_1_pixels, 135 jfloat pos_y_1_pixels, 136 jint pointer_id_0, 137 jint pointer_id_1, 138 jfloat touch_major_0_pixels, 139 jfloat touch_major_1_pixels, 140 jfloat touch_minor_0_pixels, 141 jfloat touch_minor_1_pixels, 142 jfloat orientation_0_rad, 143 jfloat orientation_1_rad, 144 jfloat raw_pos_x_pixels, 145 jfloat raw_pos_y_pixels, 146 jint android_tool_type_0, 147 jint android_tool_type_1, 148 jint android_button_state, 149 jint meta_state) 150 : cached_time_(FromAndroidTime(time_ms)), 151 cached_action_(FromAndroidAction(android_action)), 152 cached_pointer_count_(pointer_count), 153 cached_history_size_(history_size), 154 cached_action_index_(action_index), 155 cached_button_state_(FromAndroidButtonState(android_button_state)), 156 cached_flags_(FromAndroidMetaState(meta_state)), 157 pix_to_dip_(pix_to_dip), 158 should_recycle_(false) { 159 DCHECK_GT(pointer_count, 0); 160 DCHECK_GE(history_size, 0); 161 162 event_.Reset(env, event); 163 DCHECK(event_.obj()); 164 165 cached_positions_[0] = ToDips(gfx::PointF(pos_x_0_pixels, pos_y_0_pixels)); 166 cached_positions_[1] = ToDips(gfx::PointF(pos_x_1_pixels, pos_y_1_pixels)); 167 cached_pointer_ids_[0] = pointer_id_0; 168 cached_pointer_ids_[1] = pointer_id_1; 169 cached_touch_majors_[0] = ToDips(touch_major_0_pixels); 170 cached_touch_majors_[1] = ToDips(touch_major_1_pixels); 171 cached_touch_minors_[0] = ToDips(touch_minor_0_pixels); 172 cached_touch_minors_[1] = ToDips(touch_minor_1_pixels); 173 cached_orientations_[0] = ToValidFloat(orientation_0_rad); 174 cached_orientations_[1] = ToValidFloat(orientation_1_rad); 175 cached_raw_position_offset_ = 176 ToDips(gfx::PointF(raw_pos_x_pixels, raw_pos_y_pixels)) - 177 cached_positions_[0]; 178 cached_tool_types_[0] = FromAndroidToolType(android_tool_type_0); 179 cached_tool_types_[1] = FromAndroidToolType(android_tool_type_1); 180 } 181 182 MotionEventAndroid::MotionEventAndroid(float pix_to_dip, 183 JNIEnv* env, 184 jobject event) 185 : cached_time_(FromAndroidTime(Java_MotionEvent_getEventTime(env, event))), 186 cached_action_( 187 FromAndroidAction(Java_MotionEvent_getActionMasked(env, event))), 188 cached_pointer_count_(Java_MotionEvent_getPointerCount(env, event)), 189 cached_history_size_(Java_MotionEvent_getHistorySize(env, event)), 190 cached_action_index_(Java_MotionEvent_getActionIndex(env, event)), 191 cached_button_state_( 192 FromAndroidButtonState(Java_MotionEvent_getButtonState(env, event))), 193 cached_flags_( 194 FromAndroidMetaState(Java_MotionEvent_getMetaState(env, event))), 195 pix_to_dip_(pix_to_dip), 196 should_recycle_(true) { 197 event_.Reset(env, event); 198 DCHECK(event_.obj()); 199 200 for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) { 201 if (i < cached_pointer_count_) { 202 cached_positions_[i] = 203 ToDips(gfx::PointF(Java_MotionEvent_getXF_I(env, event, i), 204 Java_MotionEvent_getYF_I(env, event, i))); 205 cached_pointer_ids_[i] = Java_MotionEvent_getPointerId(env, event, i); 206 cached_touch_majors_[i] = 207 ToDips(Java_MotionEvent_getTouchMajorF_I(env, event, i)); 208 cached_touch_minors_[i] = 209 ToDips(Java_MotionEvent_getTouchMinorF_I(env, event, i)); 210 cached_orientations_[i] = 211 ToValidFloat(Java_MotionEvent_getOrientationF_I(env, event, i)); 212 cached_tool_types_[i] = 213 FromAndroidToolType(Java_MotionEvent_getToolType(env, event, i)); 214 } else { 215 cached_pointer_ids_[i] = 0; 216 cached_touch_majors_[i] = 0.f; 217 cached_touch_minors_[i] = 0.f; 218 cached_orientations_[i] = 0.f; 219 cached_tool_types_[i] = MotionEvent::TOOL_TYPE_UNKNOWN; 220 } 221 } 222 223 cached_raw_position_offset_ = 224 ToDips(gfx::PointF(Java_MotionEvent_getRawX(env, event), 225 Java_MotionEvent_getRawY(env, event))) - 226 cached_positions_[0]; 227 } 228 229 MotionEventAndroid::MotionEventAndroid(const MotionEventAndroid& other) 230 : event_(Obtain(other)), 231 cached_time_(other.cached_time_), 232 cached_action_(other.cached_action_), 233 cached_pointer_count_(other.cached_pointer_count_), 234 cached_history_size_(other.cached_history_size_), 235 cached_action_index_(other.cached_action_index_), 236 cached_raw_position_offset_(other.cached_raw_position_offset_), 237 cached_button_state_(other.cached_button_state_), 238 cached_flags_(other.cached_flags_), 239 pix_to_dip_(other.pix_to_dip_), 240 should_recycle_(true) { 241 DCHECK(event_.obj()); 242 for (size_t i = 0; i < MAX_POINTERS_TO_CACHE; ++i) { 243 cached_positions_[i] = other.cached_positions_[i]; 244 cached_pointer_ids_[i] = other.cached_pointer_ids_[i]; 245 cached_touch_majors_[i] = other.cached_touch_majors_[i]; 246 cached_touch_minors_[i] = other.cached_touch_minors_[i]; 247 cached_orientations_[i] = other.cached_orientations_[i]; 248 cached_tool_types_[i] = other.cached_tool_types_[i]; 249 } 250 } 251 252 MotionEventAndroid::~MotionEventAndroid() { 253 if (should_recycle_) 254 Java_MotionEvent_recycle(AttachCurrentThread(), event_.obj()); 255 } 256 257 int MotionEventAndroid::GetId() const { 258 return 0; 259 } 260 261 MotionEventAndroid::Action MotionEventAndroid::GetAction() const { 262 return cached_action_; 263 } 264 265 int MotionEventAndroid::GetActionIndex() const { 266 return cached_action_index_; 267 } 268 269 size_t MotionEventAndroid::GetPointerCount() const { 270 return cached_pointer_count_; 271 } 272 273 int MotionEventAndroid::GetPointerId(size_t pointer_index) const { 274 DCHECK_LT(pointer_index, cached_pointer_count_); 275 if (pointer_index < MAX_POINTERS_TO_CACHE) 276 return cached_pointer_ids_[pointer_index]; 277 return Java_MotionEvent_getPointerId( 278 AttachCurrentThread(), event_.obj(), pointer_index); 279 } 280 281 float MotionEventAndroid::GetX(size_t pointer_index) const { 282 DCHECK_LT(pointer_index, cached_pointer_count_); 283 if (pointer_index < MAX_POINTERS_TO_CACHE) 284 return cached_positions_[pointer_index].x(); 285 return ToDips(Java_MotionEvent_getXF_I( 286 AttachCurrentThread(), event_.obj(), pointer_index)); 287 } 288 289 float MotionEventAndroid::GetY(size_t pointer_index) const { 290 DCHECK_LT(pointer_index, cached_pointer_count_); 291 if (pointer_index < MAX_POINTERS_TO_CACHE) 292 return cached_positions_[pointer_index].y(); 293 return ToDips(Java_MotionEvent_getYF_I( 294 AttachCurrentThread(), event_.obj(), pointer_index)); 295 } 296 297 float MotionEventAndroid::GetRawX(size_t pointer_index) const { 298 return GetX(pointer_index) + cached_raw_position_offset_.x(); 299 } 300 301 float MotionEventAndroid::GetRawY(size_t pointer_index) const { 302 return GetY(pointer_index) + cached_raw_position_offset_.y(); 303 } 304 305 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const { 306 DCHECK_LT(pointer_index, cached_pointer_count_); 307 if (pointer_index < MAX_POINTERS_TO_CACHE) 308 return cached_touch_majors_[pointer_index]; 309 return ToDips(Java_MotionEvent_getTouchMajorF_I( 310 AttachCurrentThread(), event_.obj(), pointer_index)); 311 } 312 313 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const { 314 DCHECK_LT(pointer_index, cached_pointer_count_); 315 if (pointer_index < MAX_POINTERS_TO_CACHE) 316 return cached_touch_minors_[pointer_index]; 317 return ToDips(Java_MotionEvent_getTouchMinorF_I(AttachCurrentThread(), 318 event_.obj(), pointer_index)); 319 } 320 321 float MotionEventAndroid::GetOrientation(size_t pointer_index) const { 322 DCHECK_LT(pointer_index, cached_pointer_count_); 323 if (pointer_index < MAX_POINTERS_TO_CACHE) 324 return cached_orientations_[pointer_index]; 325 return ToValidFloat(Java_MotionEvent_getOrientationF_I( 326 AttachCurrentThread(), event_.obj(), pointer_index)); 327 } 328 329 float MotionEventAndroid::GetPressure(size_t pointer_index) const { 330 DCHECK_LT(pointer_index, cached_pointer_count_); 331 return Java_MotionEvent_getPressureF_I( 332 AttachCurrentThread(), event_.obj(), pointer_index); 333 } 334 335 base::TimeTicks MotionEventAndroid::GetEventTime() const { 336 return cached_time_; 337 } 338 339 size_t MotionEventAndroid::GetHistorySize() const { 340 return cached_history_size_; 341 } 342 343 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime( 344 size_t historical_index) const { 345 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime( 346 AttachCurrentThread(), event_.obj(), historical_index)); 347 } 348 349 float MotionEventAndroid::GetHistoricalTouchMajor( 350 size_t pointer_index, 351 size_t historical_index) const { 352 return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I( 353 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); 354 } 355 356 float MotionEventAndroid::GetHistoricalX(size_t pointer_index, 357 size_t historical_index) const { 358 return ToDips(Java_MotionEvent_getHistoricalXF_I_I( 359 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); 360 } 361 362 float MotionEventAndroid::GetHistoricalY(size_t pointer_index, 363 size_t historical_index) const { 364 return ToDips(Java_MotionEvent_getHistoricalYF_I_I( 365 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); 366 } 367 368 ui::MotionEvent::ToolType MotionEventAndroid::GetToolType( 369 size_t pointer_index) const { 370 DCHECK_LT(pointer_index, cached_pointer_count_); 371 if (pointer_index < MAX_POINTERS_TO_CACHE) 372 return cached_tool_types_[pointer_index]; 373 return FromAndroidToolType(Java_MotionEvent_getToolType( 374 AttachCurrentThread(), event_.obj(), pointer_index)); 375 } 376 377 int MotionEventAndroid::GetButtonState() const { 378 return cached_button_state_; 379 } 380 381 int MotionEventAndroid::GetFlags() const { 382 return cached_flags_; 383 } 384 385 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Clone() const { 386 return scoped_ptr<MotionEvent>(new MotionEventAndroid(*this)); 387 } 388 389 scoped_ptr<ui::MotionEvent> MotionEventAndroid::Cancel() const { 390 // The input coordinates to |MotionEventAndroid| are always in device pixels, 391 // but the cached coordinates are in DIPs. 392 const gfx::PointF position_pixels = 393 gfx::ScalePoint(cached_positions_[0], 1.f / pix_to_dip_); 394 return scoped_ptr<MotionEvent>( 395 new MotionEventAndroid(pix_to_dip_, 396 AttachCurrentThread(), 397 Obtain(GetDownTime(), 398 GetEventTime(), 399 MotionEventAndroid::ACTION_CANCEL, 400 position_pixels.x(), 401 position_pixels.y()).obj())); 402 } 403 404 base::TimeTicks MotionEventAndroid::GetDownTime() const { 405 return FromAndroidTime( 406 Java_MotionEvent_getDownTime(AttachCurrentThread(), event_.obj())); 407 } 408 409 float MotionEventAndroid::ToDips(float pixels) const { 410 return pixels * pix_to_dip_; 411 } 412 413 gfx::PointF MotionEventAndroid::ToDips(const gfx::PointF& point_pixels) const { 414 return gfx::ScalePoint(point_pixels, pix_to_dip_); 415 } 416 417 // static 418 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) { 419 return JNI_MotionEvent::RegisterNativesImpl(env); 420 } 421 422 // static 423 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain( 424 const MotionEventAndroid& event) { 425 return Java_MotionEvent_obtainAVME_AVME(AttachCurrentThread(), 426 event.event_.obj()); 427 } 428 429 // static 430 base::android::ScopedJavaLocalRef<jobject> MotionEventAndroid::Obtain( 431 base::TimeTicks down_time, 432 base::TimeTicks event_time, 433 Action action, 434 float x_pixels, 435 float y_pixels) { 436 return Java_MotionEvent_obtainAVME_J_J_I_F_F_I(AttachCurrentThread(), 437 ToAndroidTime(down_time), 438 ToAndroidTime(event_time), 439 ToAndroidAction(action), 440 x_pixels, 441 y_pixels, 442 0); 443 } 444 445 } // namespace content 446