Add ICU message format support
[chromium-blink-merge.git] / content / browser / renderer_host / input / motion_event_android.cc
blob8d36c812cc0084dc9ba3d5cb2d9fa0459ff23832
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 <android/input.h>
9 #include <cmath>
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"
16 using base::android::AttachCurrentThread;
17 using namespace JNI_MotionEvent;
19 namespace content {
20 namespace {
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;
40 return MotionEventAndroid::ACTION_CANCEL;
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;
59 return MotionEventAndroid::TOOL_TYPE_UNKNOWN;
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 return result;
77 int FromAndroidMetaState(int meta_state) {
78 int flags = ui::EF_NONE;
79 if ((meta_state & AMETA_SHIFT_ON) != 0)
80 flags |= ui::EF_SHIFT_DOWN;
81 if ((meta_state & AMETA_CTRL_ON) != 0)
82 flags |= ui::EF_CONTROL_DOWN;
83 if ((meta_state & AMETA_ALT_ON) != 0)
84 flags |= ui::EF_ALT_DOWN;
85 if ((meta_state & AMETA_META_ON) != 0)
86 flags |= ui::EF_COMMAND_DOWN;
87 if ((meta_state & AMETA_CAPS_LOCK_ON) != 0)
88 flags |= ui::EF_CAPS_LOCK_DOWN;
89 return flags;
92 base::TimeTicks FromAndroidTime(int64 time_ms) {
93 return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
96 float ToValidFloat(float x) {
97 if (std::isnan(x))
98 return 0.f;
100 // Wildly large orientation values have been observed in the wild after device
101 // rotation. There's not much we can do in that case other than simply
102 // sanitize results beyond an absurd and arbitrary threshold.
103 if (std::abs(x) > 1e5f)
104 return 0.f;
106 return x;
109 size_t ToValidHistorySize(jint history_size, ui::MotionEvent::Action action) {
110 DCHECK_GE(history_size, 0);
111 // While the spec states that only ACTION_MOVE events should contain
112 // historical entries, it's possible that an embedder could repurpose an
113 // ACTION_MOVE event into a different kind of event. In that case, the
114 // historical values are meaningless, and should not be exposed.
115 if (action != ui::MotionEvent::ACTION_MOVE)
116 return 0;
117 return history_size;
120 } // namespace
122 MotionEventAndroid::Pointer::Pointer(jint id,
123 jfloat pos_x_pixels,
124 jfloat pos_y_pixels,
125 jfloat touch_major_pixels,
126 jfloat touch_minor_pixels,
127 jfloat orientation_rad,
128 jint tool_type)
129 : id(id),
130 pos_x_pixels(pos_x_pixels),
131 pos_y_pixels(pos_y_pixels),
132 touch_major_pixels(touch_major_pixels),
133 touch_minor_pixels(touch_minor_pixels),
134 orientation_rad(orientation_rad),
135 tool_type(tool_type) {
138 MotionEventAndroid::CachedPointer::CachedPointer()
139 : id(0),
140 touch_major(0),
141 touch_minor(0),
142 orientation(0),
143 tool_type(TOOL_TYPE_UNKNOWN) {
146 MotionEventAndroid::MotionEventAndroid(float pix_to_dip,
147 JNIEnv* env,
148 jobject event,
149 jlong time_ms,
150 jint android_action,
151 jint pointer_count,
152 jint history_size,
153 jint action_index,
154 jint android_button_state,
155 jint meta_state,
156 jfloat raw_offset_x_pixels,
157 jfloat raw_offset_y_pixels,
158 const Pointer& pointer0,
159 const Pointer& pointer1)
160 : pix_to_dip_(pix_to_dip),
161 cached_time_(FromAndroidTime(time_ms)),
162 cached_action_(FromAndroidAction(android_action)),
163 cached_pointer_count_(pointer_count),
164 cached_history_size_(ToValidHistorySize(history_size, cached_action_)),
165 cached_action_index_(action_index),
166 cached_button_state_(FromAndroidButtonState(android_button_state)),
167 cached_flags_(FromAndroidMetaState(meta_state)),
168 cached_raw_position_offset_(ToDips(raw_offset_x_pixels),
169 ToDips(raw_offset_y_pixels)),
170 unique_event_id_(ui::GetNextTouchEventId()) {
171 DCHECK_GT(pointer_count, 0);
173 event_.Reset(env, event);
174 if (cached_pointer_count_ > MAX_POINTERS_TO_CACHE || cached_history_size_ > 0)
175 DCHECK(event_.obj());
177 cached_pointers_[0] = FromAndroidPointer(pointer0);
178 cached_pointers_[1] = FromAndroidPointer(pointer1);
181 MotionEventAndroid::~MotionEventAndroid() {
184 uint32 MotionEventAndroid::GetUniqueEventId() const {
185 return unique_event_id_;
188 MotionEventAndroid::Action MotionEventAndroid::GetAction() const {
189 return cached_action_;
192 int MotionEventAndroid::GetActionIndex() const {
193 DCHECK(cached_action_ == ACTION_POINTER_UP ||
194 cached_action_ == ACTION_POINTER_DOWN)
195 << "Invalid action for GetActionIndex(): " << cached_action_;
196 DCHECK_GE(cached_action_index_, 0);
197 DCHECK_LT(cached_action_index_, static_cast<int>(cached_pointer_count_));
198 return cached_action_index_;
201 size_t MotionEventAndroid::GetPointerCount() const {
202 return cached_pointer_count_;
205 int MotionEventAndroid::GetPointerId(size_t pointer_index) const {
206 DCHECK_LT(pointer_index, cached_pointer_count_);
207 if (pointer_index < MAX_POINTERS_TO_CACHE)
208 return cached_pointers_[pointer_index].id;
209 return Java_MotionEvent_getPointerId(
210 AttachCurrentThread(), event_.obj(), pointer_index);
213 float MotionEventAndroid::GetX(size_t pointer_index) const {
214 DCHECK_LT(pointer_index, cached_pointer_count_);
215 if (pointer_index < MAX_POINTERS_TO_CACHE)
216 return cached_pointers_[pointer_index].position.x();
217 return ToDips(Java_MotionEvent_getXF_I(
218 AttachCurrentThread(), event_.obj(), pointer_index));
221 float MotionEventAndroid::GetY(size_t pointer_index) const {
222 DCHECK_LT(pointer_index, cached_pointer_count_);
223 if (pointer_index < MAX_POINTERS_TO_CACHE)
224 return cached_pointers_[pointer_index].position.y();
225 return ToDips(Java_MotionEvent_getYF_I(
226 AttachCurrentThread(), event_.obj(), pointer_index));
229 float MotionEventAndroid::GetRawX(size_t pointer_index) const {
230 return GetX(pointer_index) + cached_raw_position_offset_.x();
233 float MotionEventAndroid::GetRawY(size_t pointer_index) const {
234 return GetY(pointer_index) + cached_raw_position_offset_.y();
237 float MotionEventAndroid::GetTouchMajor(size_t pointer_index) const {
238 DCHECK_LT(pointer_index, cached_pointer_count_);
239 if (pointer_index < MAX_POINTERS_TO_CACHE)
240 return cached_pointers_[pointer_index].touch_major;
241 return ToDips(Java_MotionEvent_getTouchMajorF_I(
242 AttachCurrentThread(), event_.obj(), pointer_index));
245 float MotionEventAndroid::GetTouchMinor(size_t pointer_index) const {
246 DCHECK_LT(pointer_index, cached_pointer_count_);
247 if (pointer_index < MAX_POINTERS_TO_CACHE)
248 return cached_pointers_[pointer_index].touch_minor;
249 return ToDips(Java_MotionEvent_getTouchMinorF_I(
250 AttachCurrentThread(), event_.obj(), pointer_index));
253 float MotionEventAndroid::GetOrientation(size_t pointer_index) const {
254 DCHECK_LT(pointer_index, cached_pointer_count_);
255 if (pointer_index < MAX_POINTERS_TO_CACHE)
256 return cached_pointers_[pointer_index].orientation;
257 return ToValidFloat(Java_MotionEvent_getOrientationF_I(
258 AttachCurrentThread(), event_.obj(), pointer_index));
261 float MotionEventAndroid::GetPressure(size_t pointer_index) const {
262 DCHECK_LT(pointer_index, cached_pointer_count_);
263 // Note that this early return is a special case exercised only in testing, as
264 // caching the pressure values is not a worthwhile optimization (they're
265 // accessed at most once per event instance).
266 if (!event_.obj())
267 return 0.f;
268 return Java_MotionEvent_getPressureF_I(
269 AttachCurrentThread(), event_.obj(), pointer_index);
272 base::TimeTicks MotionEventAndroid::GetEventTime() const {
273 return cached_time_;
276 size_t MotionEventAndroid::GetHistorySize() const {
277 return cached_history_size_;
280 base::TimeTicks MotionEventAndroid::GetHistoricalEventTime(
281 size_t historical_index) const {
282 return FromAndroidTime(Java_MotionEvent_getHistoricalEventTime(
283 AttachCurrentThread(), event_.obj(), historical_index));
286 float MotionEventAndroid::GetHistoricalTouchMajor(
287 size_t pointer_index,
288 size_t historical_index) const {
289 return ToDips(Java_MotionEvent_getHistoricalTouchMajorF_I_I(
290 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
293 float MotionEventAndroid::GetHistoricalX(size_t pointer_index,
294 size_t historical_index) const {
295 return ToDips(Java_MotionEvent_getHistoricalXF_I_I(
296 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
299 float MotionEventAndroid::GetHistoricalY(size_t pointer_index,
300 size_t historical_index) const {
301 return ToDips(Java_MotionEvent_getHistoricalYF_I_I(
302 AttachCurrentThread(), event_.obj(), pointer_index, historical_index));
305 ui::MotionEvent::ToolType MotionEventAndroid::GetToolType(
306 size_t pointer_index) const {
307 DCHECK_LT(pointer_index, cached_pointer_count_);
308 if (pointer_index < MAX_POINTERS_TO_CACHE)
309 return cached_pointers_[pointer_index].tool_type;
310 return FromAndroidToolType(Java_MotionEvent_getToolType(
311 AttachCurrentThread(), event_.obj(), pointer_index));
314 int MotionEventAndroid::GetButtonState() const {
315 return cached_button_state_;
318 int MotionEventAndroid::GetFlags() const {
319 return cached_flags_;
322 float MotionEventAndroid::ToDips(float pixels) const {
323 return pixels * pix_to_dip_;
326 MotionEventAndroid::CachedPointer MotionEventAndroid::FromAndroidPointer(
327 const Pointer& pointer) const {
328 CachedPointer result;
329 result.id = pointer.id;
330 result.position =
331 gfx::PointF(ToDips(pointer.pos_x_pixels), ToDips(pointer.pos_y_pixels));
332 result.touch_major = ToDips(pointer.touch_major_pixels);
333 result.touch_minor = ToDips(pointer.touch_minor_pixels);
334 result.orientation = ToValidFloat(pointer.orientation_rad);
335 result.tool_type = FromAndroidToolType(pointer.tool_type);
336 return result;
339 // static
340 bool MotionEventAndroid::RegisterMotionEventAndroid(JNIEnv* env) {
341 return JNI_MotionEvent::RegisterNativesImpl(env);
344 } // namespace content