| OLD | NEW |
| (Empty) |
| 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 <cmath> | |
| 10 | |
| 11 #include "base/android/jni_android.h" | |
| 12 #include "jni/MotionEvent_jni.h" | |
| 13 #include "ui/events/base_event_utils.h" | |
| 14 #include "ui/events/event_constants.h" | |
| 15 | |
| 16 using base::android::AttachCurrentThread; | |
| 17 using namespace JNI_MotionEvent; | |
| 18 | |
| 19 namespace content { | |
| 20 namespace { | |
| 21 | |
| 22 MotionEventAndroid::Action FromAndroidAction(int android_action) { | |
| 23 switch (android_action) { | |
| 24 case ACTION_DOWN: | |
| 25 return MotionEventAndroid::ACTION_DOWN; | |
| 26 case ACTION_UP: | |
| 27 return MotionEventAndroid::ACTION_UP; | |
| 28 case ACTION_MOVE: | |
| 29 return MotionEventAndroid::ACTION_MOVE; | |
| 30 case ACTION_CANCEL: | |
| 31 return MotionEventAndroid::ACTION_CANCEL; | |
| 32 case ACTION_POINTER_DOWN: | |
| 33 return MotionEventAndroid::ACTION_POINTER_DOWN; | |
| 34 case ACTION_POINTER_UP: | |
| 35 return MotionEventAndroid::ACTION_POINTER_UP; | |
| 36 default: | |
| 37 NOTREACHED() << "Invalid Android MotionEvent type for gesture detection: " | |
| 38 << android_action; | |
| 39 }; | |
| 40 return MotionEventAndroid::ACTION_CANCEL; | |
| 41 } | |
| 42 | |
| 43 MotionEventAndroid::ToolType FromAndroidToolType(int android_tool_type) { | |
| 44 switch (android_tool_type) { | |
| 45 case TOOL_TYPE_UNKNOWN: | |
| 46 return MotionEventAndroid::TOOL_TYPE_UNKNOWN; | |
| 47 case TOOL_TYPE_FINGER: | |
| 48 return MotionEventAndroid::TOOL_TYPE_FINGER; | |
| 49 case TOOL_TYPE_STYLUS: | |
| 50 return MotionEventAndroid::TOOL_TYPE_STYLUS; | |
| 51 case TOOL_TYPE_MOUSE: | |
| 52 return MotionEventAndroid::TOOL_TYPE_MOUSE; | |
| 53 case TOOL_TYPE_ERASER: | |
| 54 return MotionEventAndroid::TOOL_TYPE_ERASER; | |
| 55 default: | |
| 56 NOTREACHED() << "Invalid Android MotionEvent tool type: " | |
| 57 << android_tool_type; | |
| 58 }; | |
| 59 return MotionEventAndroid::TOOL_TYPE_UNKNOWN; | |
| 60 } | |
| 61 | |
| 62 int FromAndroidButtonState(int button_state) { | |
| 63 int result = 0; | |
| 64 if ((button_state & BUTTON_BACK) != 0) | |
| 65 result |= MotionEventAndroid::BUTTON_BACK; | |
| 66 if ((button_state & BUTTON_FORWARD) != 0) | |
| 67 result |= MotionEventAndroid::BUTTON_FORWARD; | |
| 68 if ((button_state & BUTTON_PRIMARY) != 0) | |
| 69 result |= MotionEventAndroid::BUTTON_PRIMARY; | |
| 70 if ((button_state & BUTTON_SECONDARY) != 0) | |
| 71 result |= MotionEventAndroid::BUTTON_SECONDARY; | |
| 72 if ((button_state & BUTTON_TERTIARY) != 0) | |
| 73 result |= MotionEventAndroid::BUTTON_TERTIARY; | |
| 74 if ((button_state & BUTTON_STYLUS_PRIMARY) != 0) | |
| 75 result |= MotionEventAndroid::BUTTON_STYLUS_PRIMARY; | |
| 76 if ((button_state & BUTTON_STYLUS_SECONDARY) != 0) | |
| 77 result |= MotionEventAndroid::BUTTON_STYLUS_SECONDARY; | |
| 78 return result; | |
| 79 } | |
| 80 | |
| 81 int FromAndroidMetaState(int meta_state) { | |
| 82 int flags = ui::EF_NONE; | |
| 83 if ((meta_state & AMETA_SHIFT_ON) != 0) | |
| 84 flags |= ui::EF_SHIFT_DOWN; | |
| 85 if ((meta_state & AMETA_CTRL_ON) != 0) | |
| 86 flags |= ui::EF_CONTROL_DOWN; | |
| 87 if ((meta_state & AMETA_ALT_ON) != 0) | |
| 88 flags |= ui::EF_ALT_DOWN; | |
| 89 if ((meta_state & AMETA_META_ON) != 0) | |
| 90 flags |= ui::EF_COMMAND_DOWN; | |
| 91 if ((meta_state & AMETA_CAPS_LOCK_ON) != 0) | |
| 92 flags |= ui::EF_CAPS_LOCK_DOWN; | |
| 93 return flags; | |
| 94 } | |
| 95 | |
| 96 base::TimeTicks FromAndroidTime(int64 time_ms) { | |
| 97 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms); | |
| 98 } | |
| 99 | |
| 100 float ToValidFloat(float x) { | |
| 101 if (std::isnan(x)) | |
| 102 return 0.f; | |
| 103 | |
| 104 // Wildly large orientation values have been observed in the wild after device | |
| 105 // rotation. There's not much we can do in that case other than simply | |
| 106 // sanitize results beyond an absurd and arbitrary threshold. | |
| 107 if (std::abs(x) > 1e5f) | |
| 108 return 0.f; | |
| 109 | |
| 110 return x; | |
| 111 } | |
| 112 | |
| 113 size_t ToValidHistorySize(jint history_size, ui::MotionEvent::Action action) { | |
| 114 DCHECK_GE(history_size, 0); | |
| 115 // While the spec states that only ACTION_MOVE events should contain | |
| 116 // historical entries, it's possible that an embedder could repurpose an | |
| 117 // ACTION_MOVE event into a different kind of event. In that case, the | |
| 118 // historical values are meaningless, and should not be exposed. | |
| 119 if (action != ui::MotionEvent::ACTION_MOVE) | |
| 120 return 0; | |
| 121 return history_size; | |
| 122 } | |
| 123 | |
| 124 } // namespace | |
| 125 | |
| 126 MotionEventAndroid::Pointer::Pointer(jint id, | |
| 127 jfloat pos_x_pixels, | |
| 128 jfloat pos_y_pixels, | |
| 129 jfloat touch_major_pixels, | |
| 130 jfloat touch_minor_pixels, | |
| 131 jfloat orientation_rad, | |
| 132 jint tool_type) | |
| 133 : id(id), | |
| 134 pos_x_pixels(pos_x_pixels), | |
| 135 pos_y_pixels(pos_y_pixels), | |
| 136 touch_major_pixels(touch_major_pixels), | |
| 137 touch_minor_pixels(touch_minor_pixels), | |
| 138 orientation_rad(orientation_rad), | |
| 139 tool_type(tool_type) { | |
| 140 } | |
| 141 | |
| 142 MotionEventAndroid::CachedPointer::CachedPointer() | |
| 143 : id(0), | |
| 144 touch_major(0), | |
| 145 touch_minor(0), | |
| 146 orientation(0), | |
| 147 tool_type(TOOL_TYPE_UNKNOWN) { | |
| 148 } | |
| 149 | |
| 150 MotionEventAndroid::MotionEventAndroid(float pix_to_dip, | |
| 151 JNIEnv* env, | |
| 152 jobject event, | |
| 153 jlong time_ms, | |
| 154 jint android_action, | |
| 155 jint pointer_count, | |
| 156 jint history_size, | |
| 157 jint action_index, | |
| 158 jint android_button_state, | |
| 159 jint meta_state, | |
| 160 jfloat raw_offset_x_pixels, | |
| 161 jfloat raw_offset_y_pixels, | |
| 162 const Pointer& pointer0, | |
| 163 const Pointer& pointer1) | |
| 164 : pix_to_dip_(pix_to_dip), | |
| 165 cached_time_(FromAndroidTime(time_ms)), | |
| 166 cached_action_(FromAndroidAction(android_action)), | |
| 167 cached_pointer_count_(pointer_count), | |
| 168 cached_history_size_(ToValidHistorySize(history_size, cached_action_)), | |
| 169 cached_action_index_(action_index), | |
| 170 cached_button_state_(FromAndroidButtonState(android_button_state)), | |
| 171 cached_flags_(FromAndroidMetaState(meta_state)), | |
| 172 cached_raw_position_offset_(ToDips(raw_offset_x_pixels), | |
| 173 ToDips(raw_offset_y_pixels)), | |
| 174 unique_event_id_(ui::GetNextTouchEventId()) { | |
| 175 DCHECK_GT(pointer_count, 0); | |
| 176 | |
| 177 event_.Reset(env, event); | |
| 178 if (cached_pointer_count_ > MAX_POINTERS_TO_CACHE || cached_history_size_ > 0) | |
| 179 DCHECK(event_.obj()); | |
| 180 | |
| 181 cached_pointers_[0] = FromAndroidPointer(pointer0); | |
| 182 cached_pointers_[1] = FromAndroidPointer(pointer1); | |
| 183 } | |
| 184 | |
| 185 MotionEventAndroid::~MotionEventAndroid() { | |
| 186 } | |
| 187 | |
| 188 uint32 MotionEventAndroid::GetUniqueEventId() const { | |
| 189 return unique_event_id_; | |
| 190 } | |
| 191 | |
| 192 MotionEventAndroid::Action MotionEventAndroid::GetAction() const { | |
| 193 return cached_action_; | |
| 194 } | |
| 195 | |
| 196 int MotionEventAndroid::GetActionIndex() const { | |
| 197 DCHECK(cached_action_ == ACTION_POINTER_UP || | |
| 198 cached_action_ == ACTION_POINTER_DOWN) | |
| 199 << "Invalid action for GetActionIndex(): " << cached_action_; | |
| 200 DCHECK_GE(cached_action_index_, 0); | |
| 201 DCHECK_LT(cached_action_index_, static_cast<int>(cached_pointer_count_)); | |
| 202 return cached_action_index_; | |
| 203 } | |
| 204 | |
| 205 size_t MotionEventAndroid::GetPointerCount() const { | |
| 206 return cached_pointer_count_; | |
| 207 } | |
| 208 | |
| 209 int MotionEventAndroid::GetPointerId(size_t pointer_index) const { | |
| 210 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 211 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 212 return cached_pointers_[pointer_index].id; | |
| 213 return Java_MotionEvent_getPointerId( | |
| 214 AttachCurrentThread(), event_.obj(), pointer_index); | |
| 215 } | |
| 216 | |
| 217 float MotionEventAndroid::GetX(size_t pointer_index) const { | |
| 218 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 219 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 220 return cached_pointers_[pointer_index].position.x(); | |
| 221 return ToDips(Java_MotionEvent_getXF_I( | |
| 222 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 223 } | |
| 224 | |
| 225 float MotionEventAndroid::GetY(size_t pointer_index) const { | |
| 226 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 227 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 228 return cached_pointers_[pointer_index].position.y(); | |
| 229 return ToDips(Java_MotionEvent_getYF_I( | |
| 230 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 231 } | |
| 232 | |
| 233 float MotionEventAndroid::GetRawX(size_t pointer_index) const { | |
| 234 return GetX(pointer_index) + cached_raw_position_offset_.x(); | |
| 235 } | |
| 236 | |
| 237 float MotionEventAndroid::GetRawY(size_t pointer_index) const { | |
| 238 return GetY(pointer_index) + cached_raw_position_offset_.y(); | |
| 239 } | |
| 240 | |
| 241 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const { | |
| 242 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 243 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 244 return cached_pointers_[pointer_index].touch_major; | |
| 245 return ToDips(Java_MotionEvent_getTouchMajorF_I( | |
| 246 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 247 } | |
| 248 | |
| 249 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const { | |
| 250 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 251 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 252 return cached_pointers_[pointer_index].touch_minor; | |
| 253 return ToDips(Java_MotionEvent_getTouchMinorF_I( | |
| 254 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 255 } | |
| 256 | |
| 257 float MotionEventAndroid::GetOrientation(size_t pointer_index) const { | |
| 258 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 259 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 260 return cached_pointers_[pointer_index].orientation; | |
| 261 return ToValidFloat(Java_MotionEvent_getOrientationF_I( | |
| 262 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 263 } | |
| 264 | |
| 265 float MotionEventAndroid::GetPressure(size_t pointer_index) const { | |
| 266 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 267 // Note that this early return is a special case exercised only in testing, as | |
| 268 // caching the pressure values is not a worthwhile optimization (they're | |
| 269 // accessed at most once per event instance). | |
| 270 if (!event_.obj()) | |
| 271 return 0.f; | |
| 272 return Java_MotionEvent_getPressureF_I( | |
| 273 AttachCurrentThread(), event_.obj(), pointer_index); | |
| 274 } | |
| 275 | |
| 276 base::TimeTicks MotionEventAndroid::GetEventTime() const { | |
| 277 return cached_time_; | |
| 278 } | |
| 279 | |
| 280 size_t MotionEventAndroid::GetHistorySize() const { | |
| 281 return cached_history_size_; | |
| 282 } | |
| 283 | |
| 284 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime( | |
| 285 size_t historical_index) const { | |
| 286 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime( | |
| 287 AttachCurrentThread(), event_.obj(), historical_index)); | |
| 288 } | |
| 289 | |
| 290 float MotionEventAndroid::GetHistoricalTouchMajor( | |
| 291 size_t pointer_index, | |
| 292 size_t historical_index) const { | |
| 293 return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I( | |
| 294 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); | |
| 295 } | |
| 296 | |
| 297 float MotionEventAndroid::GetHistoricalX(size_t pointer_index, | |
| 298 size_t historical_index) const { | |
| 299 return ToDips(Java_MotionEvent_getHistoricalXF_I_I( | |
| 300 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); | |
| 301 } | |
| 302 | |
| 303 float MotionEventAndroid::GetHistoricalY(size_t pointer_index, | |
| 304 size_t historical_index) const { | |
| 305 return ToDips(Java_MotionEvent_getHistoricalYF_I_I( | |
| 306 AttachCurrentThread(), event_.obj(), pointer_index, historical_index)); | |
| 307 } | |
| 308 | |
| 309 ui::MotionEvent::ToolType MotionEventAndroid::GetToolType( | |
| 310 size_t pointer_index) const { | |
| 311 DCHECK_LT(pointer_index, cached_pointer_count_); | |
| 312 if (pointer_index < MAX_POINTERS_TO_CACHE) | |
| 313 return cached_pointers_[pointer_index].tool_type; | |
| 314 return FromAndroidToolType(Java_MotionEvent_getToolType( | |
| 315 AttachCurrentThread(), event_.obj(), pointer_index)); | |
| 316 } | |
| 317 | |
| 318 int MotionEventAndroid::GetButtonState() const { | |
| 319 return cached_button_state_; | |
| 320 } | |
| 321 | |
| 322 int MotionEventAndroid::GetFlags() const { | |
| 323 return cached_flags_; | |
| 324 } | |
| 325 | |
| 326 float MotionEventAndroid::ToDips(float pixels) const { | |
| 327 return pixels * pix_to_dip_; | |
| 328 } | |
| 329 | |
| 330 MotionEventAndroid::CachedPointer MotionEventAndroid::FromAndroidPointer( | |
| 331 const Pointer& pointer) const { | |
| 332 CachedPointer result; | |
| 333 result.id = pointer.id; | |
| 334 result.position = | |
| 335 gfx::PointF(ToDips(pointer.pos_x_pixels), ToDips(pointer.pos_y_pixels)); | |
| 336 result.touch_major = ToDips(pointer.touch_major_pixels); | |
| 337 result.touch_minor = ToDips(pointer.touch_minor_pixels); | |
| 338 result.orientation = ToValidFloat(pointer.orientation_rad); | |
| 339 result.tool_type = FromAndroidToolType(pointer.tool_type); | |
| 340 return result; | |
| 341 } | |
| 342 | |
| 343 // static | |
| 344 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) { | |
| 345 return JNI_MotionEvent::RegisterNativesImpl(env); | |
| 346 } | |
| 347 | |
| 348 } // namespace content | |
| OLD | NEW |