提交 c8912dd1 编写于 作者: E Eric Seidel

Add support for scroll and fling gestures to SkyShell.

This is not complete gesture support by far, but it's a start.
MojoShell and Chrome use a C++ GestureDetector, this code attempts
to use the Android (Java) GestureDetector instead.

We probably should not be sending gesturetap until we've decided
it's not a scroll, etc, but this implementation does not go that far.

I had to fix a bug whereby we were assuming the InputEvent.time_stamp
was in TimeDelta's internal format, which was wrong.  When we get
time_stamp from Android its in ms since boot.

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/969493002
上级 29e3ba99
......@@ -94,8 +94,10 @@ class SkyScrollable extends SkyElement {
double newScrollOffset = math.max(0.0, math.min(scrollRange, value));
if (newScrollOffset == _scrollOffset)
return;
// TODO(eseidel): We should scroll in device pixels instead of logical
// pixels, but to do that correctly we need to use a device pixel unit.
_scrollOffset = newScrollOffset;
String transform = 'translateY(${(-_scrollOffset).toStringAsFixed(2)}px)';
String transform = 'translateY(${(-_scrollOffset).toInt()}px)';
_scrollable.style['transform'] = transform;
double topPercent = newScrollOffset / innerHeight * 100.0;
......
......@@ -10,6 +10,11 @@ enum EventType {
POINTER_UP,
POINTER_MOVE,
POINTER_CANCEL,
GESTURE_SCROLL_BEGIN,
GESTURE_SCROLL_UPDATE,
GESTURE_SCROLL_END,
GESTURE_FLING_START,
GESTURE_FLING_CANCEL,
};
enum PointerKind {
......@@ -36,8 +41,18 @@ struct PointerData {
float tilt;
};
struct GestureData {
float x;
float y;
float dx;
float dy;
float velocityX;
float velocityY;
};
struct InputEvent {
EventType type;
int64 time_stamp;
PointerData? pointer_data;
GestureData? gesture_data;
};
......@@ -72,11 +72,12 @@ shared_library("sky_shell") {
android_library("java") {
java_files = [
"org/domokit/sky/shell/GestureProvider.java",
"org/domokit/sky/shell/JavaServiceProvider.java",
"org/domokit/sky/shell/PlatformView.java",
"org/domokit/sky/shell/SkyMain.java",
"org/domokit/sky/shell/SkyActivity.java",
"org/domokit/sky/shell/SkyApplication.java",
"org/domokit/sky/shell/SkyMain.java",
]
deps = [
......
// Copyright 2016 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.
package org.domokit.sky.shell;
import android.content.Context;
import android.view.GestureDetector;
import android.view.MotionEvent;
import org.chromium.mojom.sky.EventType;
import org.chromium.mojom.sky.GestureData;
import org.chromium.mojom.sky.InputEvent;
/**
* Knows how to drive a GestureDetector to turn MotionEvents into Sky's
* InputEvents. Seems like this should not be needed. That there must exist
* some Android class to do most of this work for us?
*/
public class GestureProvider implements GestureDetector.OnGestureListener {
private static final String TAG = "GestureProvider";
/**
* Callback interface
*/
public interface OnGestureListener {
void onGestureEvent(InputEvent e);
}
private OnGestureListener mListener;
private GestureDetector mDetector;
private boolean mScrolling;
private boolean mFlinging;
public GestureProvider(Context context, OnGestureListener listener) {
mListener = listener;
mDetector = new GestureDetector(context, this);
}
private InputEvent createGestureEvent(MotionEvent event) {
GestureData gestureData = new GestureData();
gestureData.x = event.getX();
gestureData.y = event.getY();
InputEvent inputEvent = new InputEvent();
inputEvent.timeStamp = event.getEventTime();
inputEvent.gestureData = gestureData;
return inputEvent;
}
public void onTouchEvent(MotionEvent event) {
// TODO(eseidel): I am not confident that these stops are correct.
int maskedAction = event.getActionMasked();
if (mScrolling && maskedAction == MotionEvent.ACTION_UP) {
mScrolling = false;
InputEvent inputEvent = createGestureEvent(event);
inputEvent.type = EventType.GESTURE_SCROLL_END;
mListener.onGestureEvent(inputEvent);
}
if (mFlinging && maskedAction == MotionEvent.ACTION_DOWN) {
mFlinging = false;
InputEvent inputEvent = createGestureEvent(event);
inputEvent.type = EventType.GESTURE_FLING_CANCEL;
mListener.onGestureEvent(inputEvent);
}
mDetector.onTouchEvent(event);
}
@Override
public boolean onDown(MotionEvent event) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2,
float velocityX, float velocityY) {
mFlinging = true;
// Use the first event as a scroll start (for the target hit-test)
InputEvent inputEvent = createGestureEvent(e1);
inputEvent.gestureData.velocityX = velocityX;
inputEvent.gestureData.velocityY = velocityY;
inputEvent.type = EventType.GESTURE_FLING_START;
mListener.onGestureEvent(inputEvent);
return true;
}
@Override
public void onLongPress(MotionEvent event) {
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
float distanceY) {
// Use the first event as a scroll start (for the target hit-test)
InputEvent inputEvent = createGestureEvent(e1);
inputEvent.gestureData.dx = distanceX;
inputEvent.gestureData.dy = -distanceY;
// If we haven't started scrolling, send a scroll_begin.
if (!mScrolling) {
mScrolling = true;
inputEvent.type = EventType.GESTURE_SCROLL_BEGIN;
mListener.onGestureEvent(inputEvent);
}
inputEvent.type = EventType.GESTURE_SCROLL_UPDATE;
mListener.onGestureEvent(inputEvent);
return true;
}
@Override
public void onShowPress(MotionEvent event) {
}
@Override
public boolean onSingleTapUp(MotionEvent event) {
return true;
}
}
\ No newline at end of file
......@@ -26,10 +26,14 @@ import org.chromium.mojom.sky.ViewportObserver;
* A view containing Sky
*/
@JNINamespace("sky::shell")
public class PlatformView extends SurfaceView {
public class PlatformView extends SurfaceView
implements GestureProvider.OnGestureListener {
private static final String TAG = "PlatformView";
private long mNativePlatformView;
private ViewportObserver.Proxy mViewportObserver;
private final SurfaceHolder.Callback mSurfaceCallback;
private GestureProvider mGestureProvider;
public PlatformView(Context context) {
super(context);
......@@ -62,6 +66,8 @@ public class PlatformView extends SurfaceView {
}
};
getHolder().addCallback(mSurfaceCallback);
mGestureProvider = new GestureProvider(context, this);
}
@Override
......@@ -116,6 +122,8 @@ public class PlatformView extends SurfaceView {
@Override
public boolean onTouchEvent(MotionEvent event) {
mGestureProvider.onTouchEvent(event);
int maskedAction = event.getActionMasked();
// ACTION_UP, ACTION_POINTER_UP, ACTION_DOWN, and ACTION_POINTER_DOWN
// only apply to a single pointer, other events apply to all pointers.
......@@ -135,6 +143,11 @@ public class PlatformView extends SurfaceView {
return true;
}
@Override
public void onGestureEvent(InputEvent event) {
mViewportObserver.onInputEvent(event);
}
public void loadUrl(String url) {
mViewportObserver.loadUrl(url);
}
......
......@@ -15,8 +15,7 @@ scoped_ptr<blink::WebInputEvent> BuildWebPointerEvent(
const InputEventPtr& event, float device_pixel_ratio) {
scoped_ptr<blink::WebPointerEvent> web_event(new blink::WebPointerEvent);
web_event->timeStampMS =
base::TimeDelta::FromInternalValue(event->time_stamp).InMillisecondsF();
web_event->timeStampMS = event->time_stamp;
switch (event->type) {
case EVENT_TYPE_POINTER_DOWN:
......@@ -47,15 +46,66 @@ scoped_ptr<blink::WebInputEvent> BuildWebPointerEvent(
return web_event.Pass();
}
scoped_ptr<blink::WebInputEvent> BuildWebGestureEvent(
const InputEventPtr& event, float device_pixel_ratio) {
scoped_ptr<blink::WebGestureEvent> web_event(new blink::WebGestureEvent);
web_event->timeStampMS = event->time_stamp;
switch (event->type) {
case EVENT_TYPE_GESTURE_SCROLL_BEGIN:
web_event->type = blink::WebInputEvent::GestureScrollBegin;
break;
case EVENT_TYPE_GESTURE_SCROLL_END:
web_event->type = blink::WebInputEvent::GestureScrollEnd;
break;
case EVENT_TYPE_GESTURE_SCROLL_UPDATE:
web_event->type = blink::WebInputEvent::GestureScrollUpdate;
web_event->data.scrollUpdate.deltaX =
event->gesture_data->dx / device_pixel_ratio;
web_event->data.scrollUpdate.deltaY =
event->gesture_data->dy / device_pixel_ratio;
break;
case EVENT_TYPE_GESTURE_FLING_START:
web_event->type = blink::WebInputEvent::GestureFlingStart;
web_event->data.flingStart.velocityX =
event->gesture_data->velocityX / device_pixel_ratio;
web_event->data.flingStart.velocityY =
event->gesture_data->velocityY / device_pixel_ratio;
break;
case EVENT_TYPE_GESTURE_FLING_CANCEL:
web_event->type = blink::WebInputEvent::GestureFlingCancel;
break;
default:
break;
}
if (event->gesture_data) {
web_event->x = event->gesture_data->x / device_pixel_ratio;
web_event->y = event->gesture_data->y / device_pixel_ratio;
}
return web_event.Pass();
}
} // namespace
scoped_ptr<blink::WebInputEvent> ConvertEvent(const InputEventPtr& event,
float device_pixel_ratio) {
if (event->type == EVENT_TYPE_POINTER_DOWN ||
event->type == EVENT_TYPE_POINTER_UP ||
event->type == EVENT_TYPE_POINTER_MOVE ||
event->type == EVENT_TYPE_POINTER_CANCEL) {
return BuildWebPointerEvent(event, device_pixel_ratio);
switch (event->type) {
case EVENT_TYPE_POINTER_DOWN:
case EVENT_TYPE_POINTER_UP:
case EVENT_TYPE_POINTER_MOVE:
case EVENT_TYPE_POINTER_CANCEL:
return BuildWebPointerEvent(event, device_pixel_ratio);
case EVENT_TYPE_GESTURE_SCROLL_BEGIN:
case EVENT_TYPE_GESTURE_SCROLL_UPDATE:
case EVENT_TYPE_GESTURE_SCROLL_END:
case EVENT_TYPE_GESTURE_FLING_START:
case EVENT_TYPE_GESTURE_FLING_CANCEL:
return BuildWebGestureEvent(event, device_pixel_ratio);
case EVENT_TYPE_UNKNOWN:
NOTIMPLEMENTED() << "ConvertEvent received unexpected EVENT_TYPE_UNKNOWN";
}
return scoped_ptr<blink::WebInputEvent>();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册