mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [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 | |
Christopher Grant | 2b3383c2 | 2018-02-26 15:41:58 | [diff] [blame] | 5 | #include "chrome/browser/android/vr/android_ui_gesture_target.h" |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 6 | |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 7 | #include <cmath> |
| 8 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 9 | #include "chrome/browser/vr/input_event.h" |
Findit | ddef784 | 2019-06-22 02:15:16 | [diff] [blame] | 10 | #include "jni/AndroidUiGestureTarget_jni.h" |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 11 | |
| 12 | using base::android::JavaParamRef; |
| 13 | using base::android::JavaRef; |
| 14 | using content::MotionEventAction; |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 15 | |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 16 | static constexpr int kFrameDurationMs = 16; |
| 17 | static constexpr int kScrollEventsPerFrame = 2; |
| 18 | |
Christopher Grant | 4128a48 | 2018-02-15 16:07:28 | [diff] [blame] | 19 | namespace vr { |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 20 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 21 | AndroidUiGestureTarget::AndroidUiGestureTarget(JNIEnv* env, |
| 22 | const JavaParamRef<jobject>& obj, |
| 23 | float scale_factor, |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 24 | float scroll_ratio, |
| 25 | int touch_slop) |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 26 | : scale_factor_(scale_factor), |
| 27 | scroll_ratio_(scroll_ratio), |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 28 | touch_slop_(touch_slop), |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 29 | java_ref_(env, obj) {} |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 30 | |
| 31 | AndroidUiGestureTarget::~AndroidUiGestureTarget() = default; |
| 32 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 33 | void AndroidUiGestureTarget::DispatchInputEvent( |
| 34 | std::unique_ptr<InputEvent> event) { |
| 35 | int64_t event_time_ms = event->time_stamp().since_origin().InMilliseconds(); |
| 36 | switch (event->type()) { |
| 37 | case InputEvent::kScrollBegin: { |
| 38 | SetPointer(event->position_in_widget()); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 39 | Inject(content::MOTION_EVENT_ACTION_START, event_time_ms); |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 40 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 41 | float xdiff = event->scroll_data.delta_x; |
| 42 | float ydiff = event->scroll_data.delta_y; |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 43 | |
| 44 | if (xdiff == 0 && ydiff == 0) |
| 45 | ydiff = touch_slop_; |
| 46 | double dist = std::sqrt((xdiff * xdiff) + (ydiff * ydiff)); |
| 47 | if (dist < touch_slop_) { |
| 48 | xdiff *= touch_slop_ / dist; |
| 49 | ydiff *= touch_slop_ / dist; |
| 50 | } |
| 51 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 52 | float xtarget = xdiff * scroll_ratio_ + event->position_in_widget().x(); |
| 53 | float ytarget = ydiff * scroll_ratio_ + event->position_in_widget().y(); |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 54 | scroll_x_ = xtarget > 0 ? std::ceil(xtarget) : std::floor(xtarget); |
| 55 | scroll_y_ = ytarget > 0 ? std::ceil(ytarget) : std::floor(ytarget); |
| 56 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 57 | SetPointer(scroll_x_, scroll_y_); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 58 | // Send a move immediately so that we can't accidentally trigger a click. |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 59 | Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 60 | break; |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 61 | } |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 62 | case InputEvent::kScrollEnd: |
Amirhossein Simjour | 8490926 | 2018-02-14 20:58:07 | [diff] [blame] | 63 | SetPointer(scroll_x_, scroll_y_); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 64 | Inject(content::MOTION_EVENT_ACTION_END, event_time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 65 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 66 | case InputEvent::kScrollUpdate: { |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 67 | float scale = scroll_ratio_ / kScrollEventsPerFrame; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 68 | scroll_x_ += event->scroll_data.delta_x * scale; |
| 69 | scroll_y_ += event->scroll_data.delta_y * scale; |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 70 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 71 | SetPointer(scroll_x_, scroll_y_); |
| 72 | Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms); |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 73 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 74 | scroll_x_ += event->scroll_data.delta_x * scale; |
| 75 | scroll_y_ += event->scroll_data.delta_y * scale; |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 76 | SetDelayedEvent(scroll_x_, scroll_y_, content::MOTION_EVENT_ACTION_MOVE, |
| 77 | event_time_ms, kFrameDurationMs / kScrollEventsPerFrame); |
| 78 | |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 79 | break; |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 80 | } |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 81 | case InputEvent::kFlingCancel: |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 82 | Inject(content::MOTION_EVENT_ACTION_START, event_time_ms); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 83 | Inject(content::MOTION_EVENT_ACTION_CANCEL, event_time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 84 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 85 | case InputEvent::kHoverEnter: |
| 86 | SetPointer(event->position_in_widget()); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 87 | Inject(content::MOTION_EVENT_ACTION_HOVER_ENTER, event_time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 88 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 89 | case InputEvent::kHoverLeave: |
| 90 | case InputEvent::kHoverMove: |
Aldo Culquicondor | 5319555 | 2018-06-19 21:53:13 | [diff] [blame] | 91 | // The platform ignores HOVER_EXIT, so we instead send a fixed |
| 92 | // out-of-bounds point (http://crbug.com/715114). |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 93 | SetPointer(event->position_in_widget()); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 94 | Inject(content::MOTION_EVENT_ACTION_HOVER_MOVE, event_time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 95 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 96 | case InputEvent::kButtonDown: |
| 97 | SetPointer(event->position_in_widget()); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 98 | Inject(content::MOTION_EVENT_ACTION_START, event_time_ms); |
Aldo Culquicondor | 5319555 | 2018-06-19 21:53:13 | [diff] [blame] | 99 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 100 | case InputEvent::kButtonUp: |
| 101 | SetPointer(event->position_in_widget()); |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 102 | Inject(content::MOTION_EVENT_ACTION_END, event_time_ms); |
mthiesse | 2a36d197 | 2017-06-14 16:00:14 | [diff] [blame] | 103 | break; |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 104 | case InputEvent::kMove: |
| 105 | SetPointer(event->position_in_widget()); |
Aldo Culquicondor | 5319555 | 2018-06-19 21:53:13 | [diff] [blame] | 106 | Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms); |
mthiesse | 2a36d197 | 2017-06-14 16:00:14 | [diff] [blame] | 107 | break; |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 108 | default: |
mthiesse | 2a36d197 | 2017-06-14 16:00:14 | [diff] [blame] | 109 | NOTREACHED() << "Unsupported event type sent to Android UI."; |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 110 | break; |
| 111 | } |
| 112 | } |
| 113 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 114 | void AndroidUiGestureTarget::Inject(MotionEventAction action, int64_t time_ms) { |
| 115 | JNIEnv* env = base::android::AttachCurrentThread(); |
| 116 | base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
| 117 | if (obj.is_null()) |
| 118 | return; |
| 119 | |
| 120 | Java_AndroidUiGestureTarget_inject(env, obj, action, time_ms); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 121 | } |
| 122 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 123 | void AndroidUiGestureTarget::SetPointer(const gfx::PointF& position) { |
| 124 | SetPointer(position.x(), position.y()); |
| 125 | } |
| 126 | |
| 127 | void AndroidUiGestureTarget::SetPointer(float x, float y) { |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 128 | JNIEnv* env = base::android::AttachCurrentThread(); |
| 129 | base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
| 130 | if (obj.is_null()) |
| 131 | return; |
| 132 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 133 | Java_AndroidUiGestureTarget_setPointer(env, obj, |
| 134 | static_cast<int>(x * scale_factor_), |
| 135 | static_cast<int>(y * scale_factor_)); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 136 | } |
| 137 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 138 | void AndroidUiGestureTarget::SetDelayedEvent(float x, |
| 139 | float y, |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 140 | MotionEventAction action, |
| 141 | int64_t time_ms, |
| 142 | int delay_ms) { |
| 143 | JNIEnv* env = base::android::AttachCurrentThread(); |
| 144 | base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); |
| 145 | if (obj.is_null()) |
| 146 | return; |
| 147 | |
Aldo Culquicondor | 89d943a | 2018-07-04 16:31:01 | [diff] [blame] | 148 | Java_AndroidUiGestureTarget_setDelayedEvent( |
| 149 | env, obj, static_cast<int>(x * scale_factor_), |
| 150 | static_cast<int>(y * scale_factor_), action, time_ms, delay_ms); |
Ian Vollick | 98c28a6 | 2018-07-03 21:31:27 | [diff] [blame] | 151 | } |
| 152 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 153 | // static |
| 154 | AndroidUiGestureTarget* AndroidUiGestureTarget::FromJavaObject( |
| 155 | const JavaRef<jobject>& obj) { |
Michael Thiessen | 6396120 | 2018-01-23 01:17:53 | [diff] [blame] | 156 | if (obj.is_null()) |
| 157 | return nullptr; |
| 158 | |
Jinsuk Kim | 9604d8b | 2017-08-07 02:47:30 | [diff] [blame] | 159 | JNIEnv* env = base::android::AttachCurrentThread(); |
| 160 | return reinterpret_cast<AndroidUiGestureTarget*>( |
| 161 | Java_AndroidUiGestureTarget_getNativeObject(env, obj)); |
| 162 | } |
| 163 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 164 | static jlong JNI_AndroidUiGestureTarget_Init(JNIEnv* env, |
| 165 | const JavaParamRef<jobject>& obj, |
| 166 | jfloat scale_factor, |
Michael Thiessen | 1af4c93 | 2018-02-27 00:09:34 | [diff] [blame] | 167 | jfloat scroll_ratio, |
| 168 | jint touch_slop) { |
| 169 | return reinterpret_cast<intptr_t>(new AndroidUiGestureTarget( |
| 170 | env, obj, scale_factor, scroll_ratio, touch_slop)); |
mthiesse | 8ba7911 | 2017-02-24 23:58:33 | [diff] [blame] | 171 | } |
| 172 | |
Christopher Grant | 4128a48 | 2018-02-15 16:07:28 | [diff] [blame] | 173 | } // namespace vr |