Home | History | Annotate | Download | only in input
      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