blob: 2f753338049fac80b41fe964f38cd3ea261e0166 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/android/vr_shell/android_ui_gesture_target.h"
#include "jni/AndroidUiGestureTarget_jni.h"
#include "third_party/WebKit/public/platform/WebGestureEvent.h"
#include "third_party/WebKit/public/platform/WebInputEvent.h"
#include "third_party/WebKit/public/platform/WebMouseEvent.h"
using base::android::JavaParamRef;
using base::android::JavaRef;
using content::MotionEventAction;
namespace vr_shell {
AndroidUiGestureTarget::AndroidUiGestureTarget(JNIEnv* env,
const JavaParamRef<jobject>& obj,
float scale_factor,
float scroll_ratio)
: scale_factor_(scale_factor),
scroll_ratio_(scroll_ratio),
java_ref_(env, obj) {}
AndroidUiGestureTarget::~AndroidUiGestureTarget() = default;
void AndroidUiGestureTarget::DispatchWebInputEvent(
std::unique_ptr<blink::WebInputEvent> event) {
blink::WebMouseEvent* mouse;
blink::WebGestureEvent* gesture;
if (blink::WebInputEvent::IsMouseEventType(event->GetType())) {
mouse = static_cast<blink::WebMouseEvent*>(event.get());
} else {
gesture = static_cast<blink::WebGestureEvent*>(event.get());
}
int64_t event_time_ms = event->TimeStampSeconds() * 1000;
switch (event->GetType()) {
case blink::WebGestureEvent::kGestureScrollBegin:
DCHECK(gesture->data.scroll_begin.delta_hint_units ==
blink::WebGestureEvent::ScrollUnits::kPrecisePixels);
scroll_x_ = (scroll_ratio_ * gesture->data.scroll_begin.delta_x_hint);
scroll_y_ = (scroll_ratio_ * gesture->data.scroll_begin.delta_y_hint);
SetPointer(0, 0);
Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
SetPointer(scroll_x_, scroll_y_);
// Send a move immediately so that we can't accidentally trigger a click.
Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms);
break;
case blink::WebGestureEvent::kGestureScrollEnd:
Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
break;
case blink::WebGestureEvent::kGestureScrollUpdate:
scroll_x_ += (scroll_ratio_ * gesture->data.scroll_update.delta_x);
scroll_y_ += (scroll_ratio_ * gesture->data.scroll_update.delta_y);
SetPointer(scroll_x_, scroll_y_);
Inject(content::MOTION_EVENT_ACTION_MOVE, event_time_ms);
break;
case blink::WebGestureEvent::kGestureTapDown:
SetPointer(gesture->x, gesture->y);
Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
break;
case blink::WebGestureEvent::kGestureFlingCancel:
Inject(content::MOTION_EVENT_ACTION_CANCEL, event_time_ms);
break;
case blink::WebGestureEvent::kGestureFlingStart:
// Flings are automatically generated for android UI. Ignore this input.
break;
case blink::WebMouseEvent::kMouseEnter:
SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
Inject(content::MOTION_EVENT_ACTION_HOVER_ENTER, event_time_ms);
break;
case blink::WebMouseEvent::kMouseMove:
SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
Inject(content::MOTION_EVENT_ACTION_HOVER_MOVE, event_time_ms);
break;
case blink::WebMouseEvent::kMouseLeave:
SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
Inject(content::MOTION_EVENT_ACTION_HOVER_EXIT, event_time_ms);
break;
case blink::WebMouseEvent::kMouseDown:
// Mouse down events are translated into touch events on Android anyways,
// so we can just send touch events.
// We intentionally don't support long press or drags/swipes with mouse
// input as this could trigger long press and open 2D popups.
SetPointer(mouse->PositionInWidget().x, mouse->PositionInWidget().y);
Inject(content::MOTION_EVENT_ACTION_START, event_time_ms);
Inject(content::MOTION_EVENT_ACTION_END, event_time_ms);
break;
case blink::WebMouseEvent::kMouseUp:
// No need to do anything for mouseUp as mouseDown already handled up.
break;
default:
NOTREACHED() << "Unsupported event type sent to Android UI.";
break;
}
}
void AndroidUiGestureTarget::Inject(MotionEventAction action, int64_t time_ms) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AndroidUiGestureTarget_inject(env, obj, action, time_ms);
}
void AndroidUiGestureTarget::SetPointer(int x, int y) {
JNIEnv* env = base::android::AttachCurrentThread();
base::android::ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
if (obj.is_null())
return;
Java_AndroidUiGestureTarget_setPointer(env, obj, x * scale_factor_,
y * scale_factor_);
}
// static
AndroidUiGestureTarget* AndroidUiGestureTarget::FromJavaObject(
const JavaRef<jobject>& obj) {
JNIEnv* env = base::android::AttachCurrentThread();
return reinterpret_cast<AndroidUiGestureTarget*>(
Java_AndroidUiGestureTarget_getNativeObject(env, obj));
}
static jlong JNI_AndroidUiGestureTarget_Init(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jfloat scale_factor,
jfloat scroll_ratio) {
return reinterpret_cast<intptr_t>(
new AndroidUiGestureTarget(env, obj, scale_factor, scroll_ratio));
}
} // namespace vr_shell