You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
implement View.onInterceptTouchEvent() callback
This is needed to support nested scrolling A second GtkEventControllerLegacy gets registerd with GTK_PHASE_CAPTURE
This commit is contained in:
@@ -311,6 +311,14 @@ JNIEXPORT void JNICALL Java_android_view_View_setBackgroundColor
|
|||||||
JNIEXPORT void JNICALL Java_android_view_View_native_1setVisibility
|
JNIEXPORT void JNICALL Java_android_view_View_native_1setVisibility
|
||||||
(JNIEnv *, jobject, jlong, jint, jfloat);
|
(JNIEnv *, jobject, jlong, jint, jfloat);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: android_view_View
|
||||||
|
* Method: native_getGlobalVisibleRect
|
||||||
|
* Signature: (JLandroid/graphics/Rect;)Z
|
||||||
|
*/
|
||||||
|
JNIEXPORT jboolean JNICALL Java_android_view_View_native_1getGlobalVisibleRect
|
||||||
|
(JNIEnv *, jobject, jlong, jobject);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ void set_up_handle_cache(JNIEnv *env)
|
|||||||
handle_cache.view.getScrollY = _METHOD(handle_cache.view.class, "getScrollY", "()I");
|
handle_cache.view.getScrollY = _METHOD(handle_cache.view.class, "getScrollY", "()I");
|
||||||
handle_cache.view.performClick = _METHOD(handle_cache.view.class, "performClick", "()Z");
|
handle_cache.view.performClick = _METHOD(handle_cache.view.class, "performClick", "()Z");
|
||||||
handle_cache.view.onTouchEvent = _METHOD(handle_cache.view.class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
handle_cache.view.onTouchEvent = _METHOD(handle_cache.view.class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||||
|
handle_cache.view.onInterceptTouchEvent = _METHOD(handle_cache.view.class, "onInterceptTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||||
handle_cache.view.layoutInternal = _METHOD(handle_cache.view.class, "layoutInternal", "(II)V");
|
handle_cache.view.layoutInternal = _METHOD(handle_cache.view.class, "layoutInternal", "(II)V");
|
||||||
handle_cache.view.measure = _METHOD(handle_cache.view.class, "measure", "(II)V");
|
handle_cache.view.measure = _METHOD(handle_cache.view.class, "measure", "(II)V");
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ struct handle_cache {
|
|||||||
jmethodID getScrollY;
|
jmethodID getScrollY;
|
||||||
jmethodID performClick;
|
jmethodID performClick;
|
||||||
jmethodID onTouchEvent;
|
jmethodID onTouchEvent;
|
||||||
|
jmethodID onInterceptTouchEvent;
|
||||||
jmethodID layoutInternal;
|
jmethodID layoutInternal;
|
||||||
jmethodID measure;
|
jmethodID measure;
|
||||||
} view;
|
} view;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include <gtk/gtk.h>
|
#include <gtk/gtk.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "../defines.h"
|
#include "../defines.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
@@ -10,9 +11,9 @@
|
|||||||
|
|
||||||
#define SOURCE_TOUCHSCREEN 0x1002
|
#define SOURCE_TOUCHSCREEN 0x1002
|
||||||
|
|
||||||
struct touch_callback_data { JavaVM *jvm; jobject this; jobject on_touch_listener; jclass on_touch_listener_class;};
|
struct touch_callback_data { JavaVM *jvm; jobject this; jobject on_touch_listener; jclass on_touch_listener_class; bool intercepted; };
|
||||||
|
|
||||||
static bool call_ontouch_callback(int action, double x, double y, struct touch_callback_data *d)
|
static bool call_ontouch_callback(int action, double x, double y, struct touch_callback_data *d, GtkPropagationPhase phase)
|
||||||
{
|
{
|
||||||
bool ret;
|
bool ret;
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
@@ -20,8 +21,10 @@ static bool call_ontouch_callback(int action, double x, double y, struct touch_c
|
|||||||
|
|
||||||
jobject motion_event = (*env)->NewObject(env, handle_cache.motion_event.class, handle_cache.motion_event.constructor, SOURCE_TOUCHSCREEN, action, (float)x, (float)y);
|
jobject motion_event = (*env)->NewObject(env, handle_cache.motion_event.class, handle_cache.motion_event.constructor, SOURCE_TOUCHSCREEN, action, (float)x, (float)y);
|
||||||
|
|
||||||
/* NULL listener means the callback was registered for onTouchEvent */
|
if (phase == GTK_PHASE_CAPTURE && !d->intercepted) {
|
||||||
if(d->on_touch_listener)
|
d->intercepted = (*env)->CallBooleanMethod(env, d->this, handle_cache.view.onInterceptTouchEvent, motion_event);
|
||||||
|
ret = d->intercepted;
|
||||||
|
} else if(d->on_touch_listener) /* NULL listener means the callback was registered for onTouchEvent */
|
||||||
ret = (*env)->CallBooleanMethod(env, d->on_touch_listener, _METHOD(d->on_touch_listener_class, "onTouch", "(Landroid/view/View;Landroid/view/MotionEvent;)Z"), d->this, motion_event);
|
ret = (*env)->CallBooleanMethod(env, d->on_touch_listener, _METHOD(d->on_touch_listener_class, "onTouch", "(Landroid/view/View;Landroid/view/MotionEvent;)Z"), d->this, motion_event);
|
||||||
else
|
else
|
||||||
ret = (*env)->CallBooleanMethod(env, d->this, _METHOD(d->on_touch_listener_class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z"), motion_event);
|
ret = (*env)->CallBooleanMethod(env, d->this, _METHOD(d->on_touch_listener_class, "onTouchEvent", "(Landroid/view/MotionEvent;)Z"), motion_event);
|
||||||
@@ -30,6 +33,9 @@ static bool call_ontouch_callback(int action, double x, double y, struct touch_c
|
|||||||
(*env)->ExceptionDescribe(env);
|
(*env)->ExceptionDescribe(env);
|
||||||
|
|
||||||
(*env)->DeleteLocalRef(env, motion_event);
|
(*env)->DeleteLocalRef(env, motion_event);
|
||||||
|
|
||||||
|
if (action == MOTION_EVENT_ACTION_UP)
|
||||||
|
d->intercepted = false;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
static void gdk_event_get_widget_relative_position(GdkEvent *event, GtkWidget *widget, double *x, double *y)
|
static void gdk_event_get_widget_relative_position(GdkEvent *event, GtkWidget *widget, double *x, double *y)
|
||||||
@@ -49,25 +55,26 @@ static gboolean on_event(GtkEventControllerLegacy *event_controller, GdkEvent *e
|
|||||||
double y;
|
double y;
|
||||||
|
|
||||||
GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(event_controller));
|
GtkWidget *widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(event_controller));
|
||||||
|
GtkPropagationPhase phase = gtk_event_controller_get_propagation_phase(GTK_EVENT_CONTROLLER(event_controller));
|
||||||
|
|
||||||
// TODO: this doesn't work for multitouch
|
// TODO: this doesn't work for multitouch
|
||||||
switch(gdk_event_get_event_type(event)) {
|
switch(gdk_event_get_event_type(event)) {
|
||||||
case GDK_BUTTON_PRESS:
|
case GDK_BUTTON_PRESS:
|
||||||
case GDK_TOUCH_BEGIN:
|
case GDK_TOUCH_BEGIN:
|
||||||
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
||||||
return call_ontouch_callback(MOTION_EVENT_ACTION_DOWN, x, y, d);
|
return call_ontouch_callback(MOTION_EVENT_ACTION_DOWN, x, y, d, phase);
|
||||||
break;
|
break;
|
||||||
case GDK_BUTTON_RELEASE:
|
case GDK_BUTTON_RELEASE:
|
||||||
case GDK_TOUCH_END:
|
case GDK_TOUCH_END:
|
||||||
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
||||||
return call_ontouch_callback(MOTION_EVENT_ACTION_UP, x, y, d);
|
return call_ontouch_callback(MOTION_EVENT_ACTION_UP, x, y, d, phase);
|
||||||
break;
|
break;
|
||||||
case GDK_MOTION_NOTIFY:
|
case GDK_MOTION_NOTIFY:
|
||||||
if (!(gdk_event_get_modifier_state(event) & GDK_BUTTON1_MASK))
|
if (!(gdk_event_get_modifier_state(event) & GDK_BUTTON1_MASK))
|
||||||
break;
|
break;
|
||||||
case GDK_TOUCH_UPDATE:
|
case GDK_TOUCH_UPDATE:
|
||||||
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
gdk_event_get_widget_relative_position(event, widget, &x, &y);
|
||||||
return call_ontouch_callback(MOTION_EVENT_ACTION_MOVE, x, y, d);
|
return call_ontouch_callback(MOTION_EVENT_ACTION_MOVE, x, y, d, phase);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -130,6 +137,20 @@ void _setOnTouchListener(JNIEnv *env, jobject this, GtkWidget *widget, jobject o
|
|||||||
g_signal_connect(controller, "event", G_CALLBACK(on_event), callback_data);
|
g_signal_connect(controller, "event", G_CALLBACK(on_event), callback_data);
|
||||||
gtk_widget_add_controller(widget, controller);
|
gtk_widget_add_controller(widget, controller);
|
||||||
g_object_set_data(G_OBJECT(widget), "on_touch_listener", controller);
|
g_object_set_data(G_OBJECT(widget), "on_touch_listener", controller);
|
||||||
|
|
||||||
|
jmethodID onintercepttouchevent_method = _METHOD(_CLASS(this), "onInterceptTouchEvent", "(Landroid/view/MotionEvent;)Z");
|
||||||
|
if (onintercepttouchevent_method != handle_cache.view.onInterceptTouchEvent) {
|
||||||
|
GtkEventController *old_controller = g_object_get_data(G_OBJECT(widget), "on_intercept_touch_listener");
|
||||||
|
if(old_controller)
|
||||||
|
gtk_widget_remove_controller(widget, old_controller);
|
||||||
|
|
||||||
|
GtkEventController *controller = GTK_EVENT_CONTROLLER(gtk_event_controller_legacy_new());
|
||||||
|
gtk_event_controller_set_propagation_phase(controller, GTK_PHASE_CAPTURE);
|
||||||
|
|
||||||
|
g_signal_connect(controller, "event", G_CALLBACK(on_event), callback_data);
|
||||||
|
gtk_widget_add_controller(widget, controller);
|
||||||
|
g_object_set_data(G_OBJECT(widget), "on_intercept_touch_listener", controller);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_android_view_View_setOnTouchListener(JNIEnv *env, jobject this, jobject on_touch_listener)
|
JNIEXPORT void JNICALL Java_android_view_View_setOnTouchListener(JNIEnv *env, jobject this, jobject on_touch_listener)
|
||||||
@@ -418,3 +439,26 @@ JNIEXPORT void JNICALL Java_android_view_View_native_1setBackgroundDrawable(JNIE
|
|||||||
GdkPaintable *paintable = GDK_PAINTABLE(_PTR(paintable_ptr));
|
GdkPaintable *paintable = GDK_PAINTABLE(_PTR(paintable_ptr));
|
||||||
wrapper_widget_set_background(WRAPPER_WIDGET(gtk_widget_get_parent(widget)), paintable);
|
wrapper_widget_set_background(WRAPPER_WIDGET(gtk_widget_get_parent(widget)), paintable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jboolean JNICALL Java_android_view_View_native_1getGlobalVisibleRect(JNIEnv *env, jobject this, jlong widget_ptr, jobject rect) {
|
||||||
|
GtkWidget *widget = GTK_WIDGET(_PTR(widget_ptr));
|
||||||
|
graphene_point_t point_in = {0, 0};
|
||||||
|
graphene_point_t point_out;
|
||||||
|
double off_x;
|
||||||
|
double off_y;
|
||||||
|
gboolean ret;
|
||||||
|
GtkWidget *window = GTK_WIDGET(gtk_widget_get_native(widget));
|
||||||
|
gtk_native_get_surface_transform(GTK_NATIVE(window), &off_x, &off_y);
|
||||||
|
ret = gtk_widget_compute_point(widget, window, &point_in, &point_out);
|
||||||
|
if (!ret)
|
||||||
|
return false;
|
||||||
|
_SET_INT_FIELD(rect, "left", point_out.x - off_x);
|
||||||
|
_SET_INT_FIELD(rect, "top", point_out.y - off_y);
|
||||||
|
point_in = (graphene_point_t){gtk_widget_get_width(widget), gtk_widget_get_height(widget)};
|
||||||
|
ret = gtk_widget_compute_point(widget, window, &point_in, &point_out);
|
||||||
|
if (!ret)
|
||||||
|
return false;
|
||||||
|
_SET_INT_FIELD(rect, "right", point_out.x - off_x);
|
||||||
|
_SET_INT_FIELD(rect, "bottom", point_out.y - off_y);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1547,6 +1547,9 @@ public final class MotionEvent extends InputEvent {
|
|||||||
// 0, 0, xPrecision, yPrecision,
|
// 0, 0, xPrecision, yPrecision,
|
||||||
// downTime * NS_PER_MS, eventTime * NS_PER_MS,
|
// downTime * NS_PER_MS, eventTime * NS_PER_MS,
|
||||||
// 1, pp, pc);
|
// 1, pp, pc);
|
||||||
|
ev.action = action;
|
||||||
|
ev.coord_x = x;
|
||||||
|
ev.coord_y = y;
|
||||||
return ev;
|
return ev;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2693,7 +2696,8 @@ public final class MotionEvent extends InputEvent {
|
|||||||
* @see #EDGE_BOTTOM
|
* @see #EDGE_BOTTOM
|
||||||
*/
|
*/
|
||||||
public final int getEdgeFlags() {
|
public final int getEdgeFlags() {
|
||||||
return nativeGetEdgeFlags(mNativePtr);
|
// return nativeGetEdgeFlags(mNativePtr);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ public class VelocityTracker {
|
|||||||
public void recycle() {}
|
public void recycle() {}
|
||||||
|
|
||||||
public void computeCurrentVelocity(int units, float maxVelocity) {}
|
public void computeCurrentVelocity(int units, float maxVelocity) {}
|
||||||
|
public void computeCurrentVelocity(int units) {}
|
||||||
|
|
||||||
public float getXVelocity(int id) {return 0.f;}
|
public float getXVelocity(int id) {return 0.f;}
|
||||||
public float getYVelocity(int id) {return 0.f;}
|
public float getYVelocity(int id) {return 0.f;}
|
||||||
|
|||||||
@@ -1623,4 +1623,16 @@ public class View extends Object {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {}
|
public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) {}
|
||||||
|
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent event) {return false;}
|
||||||
|
|
||||||
|
public boolean dispatchTouchEvent(MotionEvent event) {return false;}
|
||||||
|
|
||||||
|
public boolean canScrollHorizontally(int direction) {return false;}
|
||||||
|
|
||||||
|
protected native boolean native_getGlobalVisibleRect(long widget, Rect visibleRect);
|
||||||
|
|
||||||
|
public boolean getGlobalVisibleRect(Rect visibleRect) {
|
||||||
|
return native_getGlobalVisibleRect(widget, visibleRect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user