jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 1 | // Copyright 2017 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 "ui/android/event_forwarder.h" |
| 6 | |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 7 | #include "base/android/jni_array.h" |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 8 | #include "base/metrics/histogram_macros.h" |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 9 | #include "jni/EventForwarder_jni.h" |
| 10 | #include "ui/android/view_android.h" |
Michael Thiessen | e70dd08d | 2017-12-21 20:59:11 | [diff] [blame] | 11 | #include "ui/android/window_android.h" |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 12 | #include "ui/base/ui_base_switches_util.h" |
| 13 | #include "ui/events/android/drag_event_android.h" |
Jinsuk Kim | 63626ce4 | 2017-11-23 06:19:56 | [diff] [blame] | 14 | #include "ui/events/android/gesture_event_android.h" |
Jinsuk Kim | e6c2eafb | 2018-02-23 01:10:36 | [diff] [blame] | 15 | #include "ui/events/android/gesture_event_type.h" |
Jinsuk Kim | 5a3ae93c | 2018-04-25 21:49:06 | [diff] [blame^] | 16 | #include "ui/events/android/key_event_android.h" |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 17 | #include "ui/events/android/motion_event_android.h" |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 18 | #include "ui/events/base_event_utils.h" |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 19 | |
| 20 | namespace ui { |
| 21 | |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 22 | using base::android::AppendJavaStringArrayToStringVector; |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 23 | using base::android::JavaParamRef; |
| 24 | using base::android::ScopedJavaLocalRef; |
| 25 | |
| 26 | EventForwarder::EventForwarder(ViewAndroid* view) : view_(view) {} |
| 27 | |
| 28 | EventForwarder::~EventForwarder() { |
| 29 | if (!java_obj_.is_null()) { |
| 30 | Java_EventForwarder_destroy(base::android::AttachCurrentThread(), |
| 31 | java_obj_); |
| 32 | java_obj_.Reset(); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | ScopedJavaLocalRef<jobject> EventForwarder::GetJavaObject() { |
| 37 | if (java_obj_.is_null()) { |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 38 | JNIEnv* env = base::android::AttachCurrentThread(); |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 39 | java_obj_.Reset( |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 40 | Java_EventForwarder_create(env, reinterpret_cast<intptr_t>(this), |
| 41 | switches::IsTouchDragDropEnabled())); |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 42 | } |
| 43 | return ScopedJavaLocalRef<jobject>(java_obj_); |
| 44 | } |
| 45 | |
Michael Thiessen | e70dd08d | 2017-12-21 20:59:11 | [diff] [blame] | 46 | ScopedJavaLocalRef<jobject> EventForwarder::GetJavaWindowAndroid( |
| 47 | JNIEnv* env, |
| 48 | const JavaParamRef<jobject>& obj) { |
| 49 | return view_->GetWindowAndroid()->GetJavaObject(); |
| 50 | } |
| 51 | |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 52 | jboolean EventForwarder::OnTouchEvent(JNIEnv* env, |
| 53 | const JavaParamRef<jobject>& obj, |
| 54 | const JavaParamRef<jobject>& motion_event, |
| 55 | jlong time_ms, |
| 56 | jint android_action, |
| 57 | jint pointer_count, |
| 58 | jint history_size, |
| 59 | jint action_index, |
| 60 | jfloat pos_x_0, |
| 61 | jfloat pos_y_0, |
| 62 | jfloat pos_x_1, |
| 63 | jfloat pos_y_1, |
| 64 | jint pointer_id_0, |
| 65 | jint pointer_id_1, |
| 66 | jfloat touch_major_0, |
| 67 | jfloat touch_major_1, |
| 68 | jfloat touch_minor_0, |
| 69 | jfloat touch_minor_1, |
| 70 | jfloat orientation_0, |
| 71 | jfloat orientation_1, |
| 72 | jfloat tilt_0, |
| 73 | jfloat tilt_1, |
| 74 | jfloat raw_pos_x, |
| 75 | jfloat raw_pos_y, |
| 76 | jint android_tool_type_0, |
| 77 | jint android_tool_type_1, |
| 78 | jint android_button_state, |
| 79 | jint android_meta_state, |
Jinsuk Kim | 2b85947 | 2017-08-30 02:47:19 | [diff] [blame] | 80 | jboolean for_touch_handle) { |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 81 | ui::MotionEventAndroid::Pointer pointer0( |
| 82 | pointer_id_0, pos_x_0, pos_y_0, touch_major_0, touch_minor_0, |
| 83 | orientation_0, tilt_0, android_tool_type_0); |
| 84 | ui::MotionEventAndroid::Pointer pointer1( |
| 85 | pointer_id_1, pos_x_1, pos_y_1, touch_major_1, touch_minor_1, |
| 86 | orientation_1, tilt_1, android_tool_type_1); |
| 87 | ui::MotionEventAndroid event( |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 88 | env, motion_event.obj(), 1.f / view_->GetDipScale(), 0.f, 0.f, 0.f, |
| 89 | time_ms, android_action, pointer_count, history_size, action_index, |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 90 | 0 /* action_button */, android_button_state, android_meta_state, |
Jinsuk Kim | 2b85947 | 2017-08-30 02:47:19 | [diff] [blame] | 91 | raw_pos_x - pos_x_0, raw_pos_y - pos_y_0, for_touch_handle, &pointer0, |
| 92 | &pointer1); |
| 93 | return view_->OnTouchEvent(event); |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | void EventForwarder::OnMouseEvent(JNIEnv* env, |
| 97 | const JavaParamRef<jobject>& obj, |
| 98 | jlong time_ms, |
| 99 | jint android_action, |
| 100 | jfloat x, |
| 101 | jfloat y, |
| 102 | jint pointer_id, |
| 103 | jfloat orientation, |
| 104 | jfloat pressure, |
| 105 | jfloat tilt, |
| 106 | jint android_action_button, |
| 107 | jint android_button_state, |
| 108 | jint android_meta_state, |
| 109 | jint android_tool_type) { |
| 110 | // Construct a motion_event object minimally, only to convert the raw |
| 111 | // parameters to ui::MotionEvent values. Since we used only the cached values |
| 112 | // at index=0, it is okay to even pass a null event to the constructor. |
| 113 | ui::MotionEventAndroid::Pointer pointer( |
| 114 | pointer_id, x, y, 0.0f /* touch_major */, 0.0f /* touch_minor */, |
| 115 | orientation, tilt, android_tool_type); |
| 116 | ui::MotionEventAndroid event( |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 117 | env, nullptr /* event */, 1.f / view_->GetDipScale(), 0.f, 0.f, 0.f, |
| 118 | time_ms, android_action, 1 /* pointer_count */, 0 /* history_size */, |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 119 | 0 /* action_index */, android_action_button, android_button_state, |
| 120 | android_meta_state, 0 /* raw_offset_x_pixels */, |
Jinsuk Kim | 2b85947 | 2017-08-30 02:47:19 | [diff] [blame] | 121 | 0 /* raw_offset_y_pixels */, false /* for_touch_handle */, &pointer, |
| 122 | nullptr); |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 123 | view_->OnMouseEvent(event); |
| 124 | } |
| 125 | |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 126 | void EventForwarder::OnMouseWheelEvent(JNIEnv* env, |
| 127 | const JavaParamRef<jobject>& obj, |
| 128 | jlong time_ms, |
| 129 | jfloat x, |
| 130 | jfloat y, |
| 131 | jfloat ticks_x, |
Jinsuk Kim | 00e4698 | 2018-03-07 07:54:36 | [diff] [blame] | 132 | jfloat ticks_y) { |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 133 | if (!ticks_x && !ticks_y) |
| 134 | return; |
| 135 | |
| 136 | // Compute Event.Latency.OS.MOUSE_WHEEL histogram. |
| 137 | base::TimeTicks current_time = ui::EventTimeForNow(); |
| 138 | base::TimeTicks event_time = |
| 139 | base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms); |
| 140 | base::TimeDelta delta = current_time - event_time; |
| 141 | UMA_HISTOGRAM_CUSTOM_COUNTS("Event.Latency.OS.MOUSE_WHEEL", |
| 142 | delta.InMicroseconds(), 1, 1000000, 50); |
| 143 | ui::MotionEventAndroid::Pointer pointer( |
| 144 | 0, x, y, 0.0f /* touch_major */, 0.0f /* touch_minor */, 0.0f, 0.0f, 0); |
Jinsuk Kim | 00e4698 | 2018-03-07 07:54:36 | [diff] [blame] | 145 | |
| 146 | auto* window = view_->GetWindowAndroid(); |
Jinsuk Kim | 4583ba5 | 2018-03-14 04:58:56 | [diff] [blame] | 147 | float pixels_per_tick = |
| 148 | window ? window->mouse_wheel_scroll_factor() |
| 149 | : kDefaultMouseWheelTickMultiplier * view_->GetDipScale(); |
Jinsuk Kim | 2b85947 | 2017-08-30 02:47:19 | [diff] [blame] | 150 | ui::MotionEventAndroid event( |
| 151 | env, nullptr, 1.f / view_->GetDipScale(), ticks_x, ticks_y, |
| 152 | pixels_per_tick, time_ms, 0 /* action */, 1 /* pointer_count */, |
| 153 | 0 /* history_size */, 0 /* action_index */, 0, 0, 0, |
| 154 | 0 /* raw_offset_x_pixels */, 0 /* raw_offset_y_pixels */, |
| 155 | false /* for_touch_handle */, &pointer, nullptr); |
jinsukkim | b40b402c | 2017-03-29 09:39:08 | [diff] [blame] | 156 | |
| 157 | view_->OnMouseWheelEvent(event); |
| 158 | } |
| 159 | |
jinsukkim | da11b4d | 2017-05-26 06:44:41 | [diff] [blame] | 160 | void EventForwarder::OnDragEvent(JNIEnv* env, |
| 161 | const JavaParamRef<jobject>& jobj, |
| 162 | jint action, |
| 163 | jint x, |
| 164 | jint y, |
| 165 | jint screen_x, |
| 166 | jint screen_y, |
| 167 | const JavaParamRef<jobjectArray>& j_mimeTypes, |
| 168 | const JavaParamRef<jstring>& j_content) { |
| 169 | float dip_scale = view_->GetDipScale(); |
| 170 | gfx::PointF location(x / dip_scale, y / dip_scale); |
| 171 | gfx::PointF root_location(screen_x / dip_scale, screen_y / dip_scale); |
| 172 | std::vector<base::string16> mime_types; |
| 173 | AppendJavaStringArrayToStringVector(env, j_mimeTypes, &mime_types); |
| 174 | |
| 175 | DragEventAndroid event(env, action, location, root_location, mime_types, |
| 176 | j_content.obj()); |
| 177 | view_->OnDragEvent(event); |
| 178 | } |
| 179 | |
Jinsuk Kim | 5a3ae93c | 2018-04-25 21:49:06 | [diff] [blame^] | 180 | jboolean EventForwarder::OnGestureEvent(JNIEnv* env, |
| 181 | const JavaParamRef<jobject>& jobj, |
| 182 | jint type, |
| 183 | jlong time_ms, |
| 184 | jfloat scale) { |
Jinsuk Kim | 63626ce4 | 2017-11-23 06:19:56 | [diff] [blame] | 185 | float dip_scale = view_->GetDipScale(); |
| 186 | auto size = view_->GetSize(); |
| 187 | float x = size.width() / 2; |
| 188 | float y = size.height() / 2; |
| 189 | gfx::PointF root_location = |
| 190 | ScalePoint(view_->GetLocationOnScreen(x, y), 1.f / dip_scale); |
Jinsuk Kim | e6c2eafb | 2018-02-23 01:10:36 | [diff] [blame] | 191 | return view_->OnGestureEvent(GestureEventAndroid( |
| 192 | type, gfx::PointF(x / dip_scale, y / dip_scale), root_location, time_ms, |
| 193 | scale, 0, 0, 0, 0, false, false)); |
| 194 | } |
| 195 | |
Jinsuk Kim | 5a3ae93c | 2018-04-25 21:49:06 | [diff] [blame^] | 196 | jboolean EventForwarder::OnKeyUp(JNIEnv* env, |
| 197 | const JavaParamRef<jobject>& obj, |
| 198 | const JavaParamRef<jobject>& key_event, |
| 199 | jint key_code) { |
| 200 | return view_->OnKeyUp(KeyEventAndroid(env, key_event, key_code)); |
| 201 | } |
| 202 | |
| 203 | jboolean EventForwarder::DispatchKeyEvent( |
| 204 | JNIEnv* env, |
| 205 | const JavaParamRef<jobject>& obj, |
| 206 | const JavaParamRef<jobject>& key_event) { |
| 207 | return view_->DispatchKeyEvent(KeyEventAndroid(env, key_event, 0)); |
| 208 | } |
| 209 | |
Jinsuk Kim | 7862733 | 2018-03-05 23:33:39 | [diff] [blame] | 210 | void EventForwarder::Scroll(JNIEnv* env, |
| 211 | const JavaParamRef<jobject>& jobj, |
| 212 | jlong time_ms, |
| 213 | jfloat delta_x, |
| 214 | jfloat delta_y) { |
| 215 | float dip_scale = view_->GetDipScale(); |
| 216 | float delta_xdip = delta_x / dip_scale; |
| 217 | float delta_ydip = delta_y / dip_scale; |
| 218 | view_->OnGestureEvent(GestureEventAndroid( |
| 219 | GESTURE_EVENT_TYPE_SCROLL_START, gfx::PointF(), gfx::PointF(), time_ms, 0, |
| 220 | -delta_xdip, -delta_ydip, 0, 0, true, false)); |
| 221 | view_->OnGestureEvent(GestureEventAndroid( |
| 222 | GESTURE_EVENT_TYPE_SCROLL_BY, gfx::PointF(), gfx::PointF(), time_ms, 0, |
| 223 | -delta_xdip, -delta_ydip, 0, 0, true, false)); |
| 224 | view_->OnGestureEvent(GestureEventAndroid( |
| 225 | GESTURE_EVENT_TYPE_SCROLL_END, gfx::PointF(), gfx::PointF(), time_ms, 0, |
| 226 | -delta_xdip, -delta_ydip, 0, 0, true, false)); |
| 227 | } |
| 228 | |
| 229 | void EventForwarder::DoubleTap(JNIEnv* env, |
| 230 | const JavaParamRef<jobject>& jobj, |
| 231 | jlong time_ms, |
| 232 | jint x, |
| 233 | jint y) { |
| 234 | float dip_scale = view_->GetDipScale(); |
| 235 | view_->OnGestureEvent(GestureEventAndroid( |
| 236 | GESTURE_EVENT_TYPE_DOUBLE_TAP, gfx::PointF(x / dip_scale, y / dip_scale), |
| 237 | gfx::PointF(), time_ms, 0, 0, 0, 0, 0, true, false)); |
| 238 | } |
| 239 | |
| 240 | void EventForwarder::StartFling(JNIEnv* env, |
| 241 | const JavaParamRef<jobject>& jobj, |
| 242 | jlong time_ms, |
| 243 | jfloat velocity_x, |
| 244 | jfloat velocity_y, |
| 245 | jboolean synthetic_scroll) { |
| 246 | CancelFling(env, jobj, time_ms); |
Jinsuk Kim | e6c2eafb | 2018-02-23 01:10:36 | [diff] [blame] | 247 | if (velocity_x == 0 && velocity_y == 0) |
| 248 | return; |
| 249 | // Use velocity as delta in scroll event. |
| 250 | view_->OnGestureEvent(GestureEventAndroid( |
| 251 | GESTURE_EVENT_TYPE_SCROLL_START, gfx::PointF(), gfx::PointF(), time_ms, 0, |
| 252 | velocity_x, velocity_y, 0, 0, true, synthetic_scroll)); |
| 253 | view_->OnGestureEvent(GestureEventAndroid( |
| 254 | GESTURE_EVENT_TYPE_FLING_START, gfx::PointF(), gfx::PointF(), time_ms, 0, |
| 255 | 0, 0, velocity_x, velocity_y, true, synthetic_scroll)); |
| 256 | } |
| 257 | |
Jinsuk Kim | 7862733 | 2018-03-05 23:33:39 | [diff] [blame] | 258 | void EventForwarder::CancelFling(JNIEnv* env, |
| 259 | const JavaParamRef<jobject>& jobj, |
| 260 | jlong time_ms) { |
Jinsuk Kim | e6c2eafb | 2018-02-23 01:10:36 | [diff] [blame] | 261 | view_->OnGestureEvent( |
| 262 | GestureEventAndroid(GESTURE_EVENT_TYPE_FLING_CANCEL, gfx::PointF(), |
| 263 | gfx::PointF(), time_ms, 0, 0, 0, 0, 0, false, false)); |
Jinsuk Kim | 63626ce4 | 2017-11-23 06:19:56 | [diff] [blame] | 264 | } |
| 265 | |
jinsukkim | 5c3a120 | 2017-03-10 00:02:14 | [diff] [blame] | 266 | } // namespace ui |