mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
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
This commit is contained in:
parent
3c90612675
commit
999fc7afa6
@ -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 = [
|
||||
|
||||
@ -0,0 +1,126 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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>();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user