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