From f2e71cd50fd267ee4447214146079c960d2ba338 Mon Sep 17 00:00:00 2001 From: Julian Winkler Date: Tue, 22 Aug 2023 13:51:37 +0200 Subject: [PATCH] implement android.widget.Button using GtkButton --- meson.build | 1 + .../generated_headers/android_widget_Button.h | 229 ++++++++++++++++++ .../widgets/android_widget_Button.c | 62 +++++ src/api-impl/android/widget/Button.java | 21 ++ 4 files changed, 313 insertions(+) create mode 100644 src/api-impl-jni/generated_headers/android_widget_Button.h create mode 100644 src/api-impl-jni/widgets/android_widget_Button.c diff --git a/meson.build b/meson.build index 87b3b429..dd2ed546 100644 --- a/meson.build +++ b/meson.build @@ -68,6 +68,7 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/android_content_res_AssetManager.c', 'src/api-impl-jni/audio/android_media_AudioTrack.c', 'src/api-impl-jni/audio/android_media_SoundPool.c', + 'src/api-impl-jni/widgets/android_widget_Button.c', 'src/api-impl-jni/widgets/android_widget_RelativeLayout.c', 'src/api-impl-jni/widgets/android_widget_ScrollView.c', 'src/api-impl-jni/widgets/android_opengl_GLSurfaceView.c', diff --git a/src/api-impl-jni/generated_headers/android_widget_Button.h b/src/api-impl-jni/generated_headers/android_widget_Button.h new file mode 100644 index 00000000..22b82e01 --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_widget_Button.h @@ -0,0 +1,229 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_widget_Button */ + +#ifndef _Included_android_widget_Button +#define _Included_android_widget_Button +#ifdef __cplusplus +extern "C" { +#endif +#undef android_widget_Button_NO_ID +#define android_widget_Button_NO_ID -1L +#undef android_widget_Button_NOT_FOCUSABLE +#define android_widget_Button_NOT_FOCUSABLE 0L +#undef android_widget_Button_FOCUSABLE +#define android_widget_Button_FOCUSABLE 1L +#undef android_widget_Button_FOCUSABLE_MASK +#define android_widget_Button_FOCUSABLE_MASK 1L +#undef android_widget_Button_FITS_SYSTEM_WINDOWS +#define android_widget_Button_FITS_SYSTEM_WINDOWS 2L +#undef android_widget_Button_VISIBLE +#define android_widget_Button_VISIBLE 0L +#undef android_widget_Button_INVISIBLE +#define android_widget_Button_INVISIBLE 4L +#undef android_widget_Button_GONE +#define android_widget_Button_GONE 8L +#undef android_widget_Button_VISIBILITY_MASK +#define android_widget_Button_VISIBILITY_MASK 12L +#undef android_widget_Button_ENABLED +#define android_widget_Button_ENABLED 0L +#undef android_widget_Button_DISABLED +#define android_widget_Button_DISABLED 32L +#undef android_widget_Button_ENABLED_MASK +#define android_widget_Button_ENABLED_MASK 32L +#undef android_widget_Button_WILL_NOT_DRAW +#define android_widget_Button_WILL_NOT_DRAW 128L +#undef android_widget_Button_DRAW_MASK +#define android_widget_Button_DRAW_MASK 128L +#undef android_widget_Button_SCROLLBARS_NONE +#define android_widget_Button_SCROLLBARS_NONE 0L +#undef android_widget_Button_SCROLLBARS_HORIZONTAL +#define android_widget_Button_SCROLLBARS_HORIZONTAL 256L +#undef android_widget_Button_SCROLLBARS_VERTICAL +#define android_widget_Button_SCROLLBARS_VERTICAL 512L +#undef android_widget_Button_SCROLLBARS_MASK +#define android_widget_Button_SCROLLBARS_MASK 768L +#undef android_widget_Button_FILTER_TOUCHES_WHEN_OBSCURED +#define android_widget_Button_FILTER_TOUCHES_WHEN_OBSCURED 1024L +#undef android_widget_Button_OPTIONAL_FITS_SYSTEM_WINDOWS +#define android_widget_Button_OPTIONAL_FITS_SYSTEM_WINDOWS 2048L +#undef android_widget_Button_FADING_EDGE_NONE +#define android_widget_Button_FADING_EDGE_NONE 0L +#undef android_widget_Button_FADING_EDGE_HORIZONTAL +#define android_widget_Button_FADING_EDGE_HORIZONTAL 4096L +#undef android_widget_Button_FADING_EDGE_VERTICAL +#define android_widget_Button_FADING_EDGE_VERTICAL 8192L +#undef android_widget_Button_FADING_EDGE_MASK +#define android_widget_Button_FADING_EDGE_MASK 12288L +#undef android_widget_Button_CLICKABLE +#define android_widget_Button_CLICKABLE 16384L +#undef android_widget_Button_DRAWING_CACHE_ENABLED +#define android_widget_Button_DRAWING_CACHE_ENABLED 32768L +#undef android_widget_Button_SAVE_DISABLED +#define android_widget_Button_SAVE_DISABLED 65536L +#undef android_widget_Button_SAVE_DISABLED_MASK +#define android_widget_Button_SAVE_DISABLED_MASK 65536L +#undef android_widget_Button_WILL_NOT_CACHE_DRAWING +#define android_widget_Button_WILL_NOT_CACHE_DRAWING 131072L +#undef android_widget_Button_FOCUSABLE_IN_TOUCH_MODE +#define android_widget_Button_FOCUSABLE_IN_TOUCH_MODE 262144L +#undef android_widget_Button_DRAWING_CACHE_QUALITY_LOW +#define android_widget_Button_DRAWING_CACHE_QUALITY_LOW 524288L +#undef android_widget_Button_DRAWING_CACHE_QUALITY_HIGH +#define android_widget_Button_DRAWING_CACHE_QUALITY_HIGH 1048576L +#undef android_widget_Button_DRAWING_CACHE_QUALITY_AUTO +#define android_widget_Button_DRAWING_CACHE_QUALITY_AUTO 0L +#undef android_widget_Button_DRAWING_CACHE_QUALITY_MASK +#define android_widget_Button_DRAWING_CACHE_QUALITY_MASK 1572864L +#undef android_widget_Button_LONG_CLICKABLE +#define android_widget_Button_LONG_CLICKABLE 2097152L +#undef android_widget_Button_DUPLICATE_PARENT_STATE +#define android_widget_Button_DUPLICATE_PARENT_STATE 4194304L +#undef android_widget_Button_SCROLLBARS_INSIDE_OVERLAY +#define android_widget_Button_SCROLLBARS_INSIDE_OVERLAY 0L +#undef android_widget_Button_SCROLLBARS_INSIDE_INSET +#define android_widget_Button_SCROLLBARS_INSIDE_INSET 16777216L +#undef android_widget_Button_SCROLLBARS_OUTSIDE_OVERLAY +#define android_widget_Button_SCROLLBARS_OUTSIDE_OVERLAY 33554432L +#undef android_widget_Button_SCROLLBARS_OUTSIDE_INSET +#define android_widget_Button_SCROLLBARS_OUTSIDE_INSET 50331648L +#undef android_widget_Button_SCROLLBARS_INSET_MASK +#define android_widget_Button_SCROLLBARS_INSET_MASK 16777216L +#undef android_widget_Button_SCROLLBARS_OUTSIDE_MASK +#define android_widget_Button_SCROLLBARS_OUTSIDE_MASK 33554432L +#undef android_widget_Button_SCROLLBARS_STYLE_MASK +#define android_widget_Button_SCROLLBARS_STYLE_MASK 50331648L +#undef android_widget_Button_KEEP_SCREEN_ON +#define android_widget_Button_KEEP_SCREEN_ON 67108864L +#undef android_widget_Button_SOUND_EFFECTS_ENABLED +#define android_widget_Button_SOUND_EFFECTS_ENABLED 134217728L +#undef android_widget_Button_HAPTIC_FEEDBACK_ENABLED +#define android_widget_Button_HAPTIC_FEEDBACK_ENABLED 268435456L +#undef android_widget_Button_PARENT_SAVE_DISABLED +#define android_widget_Button_PARENT_SAVE_DISABLED 536870912L +#undef android_widget_Button_PARENT_SAVE_DISABLED_MASK +#define android_widget_Button_PARENT_SAVE_DISABLED_MASK 536870912L +#undef android_widget_Button_FOCUSABLES_ALL +#define android_widget_Button_FOCUSABLES_ALL 0L +#undef android_widget_Button_FOCUSABLES_TOUCH_MODE +#define android_widget_Button_FOCUSABLES_TOUCH_MODE 1L +#undef android_widget_Button_FOCUS_BACKWARD +#define android_widget_Button_FOCUS_BACKWARD 1L +#undef android_widget_Button_FOCUS_FORWARD +#define android_widget_Button_FOCUS_FORWARD 2L +#undef android_widget_Button_FOCUS_LEFT +#define android_widget_Button_FOCUS_LEFT 17L +#undef android_widget_Button_FOCUS_UP +#define android_widget_Button_FOCUS_UP 33L +#undef android_widget_Button_FOCUS_RIGHT +#define android_widget_Button_FOCUS_RIGHT 66L +#undef android_widget_Button_FOCUS_DOWN +#define android_widget_Button_FOCUS_DOWN 130L +#undef android_widget_Button_MEASURED_SIZE_MASK +#define android_widget_Button_MEASURED_SIZE_MASK 16777215L +#undef android_widget_Button_MEASURED_STATE_MASK +#define android_widget_Button_MEASURED_STATE_MASK -16777216L +#undef android_widget_Button_MEASURED_HEIGHT_STATE_SHIFT +#define android_widget_Button_MEASURED_HEIGHT_STATE_SHIFT 16L +#undef android_widget_Button_MEASURED_STATE_TOO_SMALL +#define android_widget_Button_MEASURED_STATE_TOO_SMALL 16777216L +#undef android_widget_Button_PFLAG2_DRAG_CAN_ACCEPT +#define android_widget_Button_PFLAG2_DRAG_CAN_ACCEPT 1L +#undef android_widget_Button_PFLAG2_DRAG_HOVERED +#define android_widget_Button_PFLAG2_DRAG_HOVERED 2L +#undef android_widget_Button_LAYOUT_DIRECTION_LTR +#define android_widget_Button_LAYOUT_DIRECTION_LTR 0L +#undef android_widget_Button_LAYOUT_DIRECTION_RTL +#define android_widget_Button_LAYOUT_DIRECTION_RTL 1L +#undef android_widget_Button_LAYOUT_DIRECTION_INHERIT +#define android_widget_Button_LAYOUT_DIRECTION_INHERIT 2L +#undef android_widget_Button_LAYOUT_DIRECTION_LOCALE +#define android_widget_Button_LAYOUT_DIRECTION_LOCALE 3L +#undef android_widget_Button_PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT +#define android_widget_Button_PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT 2L +#undef android_widget_Button_PFLAG2_LAYOUT_DIRECTION_MASK +#define android_widget_Button_PFLAG2_LAYOUT_DIRECTION_MASK 12L +#undef android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL +#define android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 16L +#undef android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED +#define android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED 32L +#undef android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK +#define android_widget_Button_PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 48L +#undef android_widget_Button_STATUS_BAR_HIDDEN +#define android_widget_Button_STATUS_BAR_HIDDEN 1L +#undef android_widget_Button_STATUS_BAR_VISIBLE +#define android_widget_Button_STATUS_BAR_VISIBLE 0L +#undef android_widget_Button_SYSTEM_UI_FLAG_FULLSCREEN +#define android_widget_Button_SYSTEM_UI_FLAG_FULLSCREEN 4L +#undef android_widget_Button_SYSTEM_UI_FLAG_HIDE_NAVIGATION +#define android_widget_Button_SYSTEM_UI_FLAG_HIDE_NAVIGATION 2L +#undef android_widget_Button_SYSTEM_UI_FLAG_IMMERSIVE +#define android_widget_Button_SYSTEM_UI_FLAG_IMMERSIVE 2048L +#undef android_widget_Button_SYSTEM_UI_FLAG_IMMERSIVE_STICKY +#define android_widget_Button_SYSTEM_UI_FLAG_IMMERSIVE_STICKY 4096L +#undef android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN +#define android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 1024L +#undef android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION +#define android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 512L +#undef android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_STABLE +#define android_widget_Button_SYSTEM_UI_FLAG_LAYOUT_STABLE 256L +#undef android_widget_Button_SYSTEM_UI_FLAG_LOW_PROFILE +#define android_widget_Button_SYSTEM_UI_FLAG_LOW_PROFILE 1L +#undef android_widget_Button_SYSTEM_UI_FLAG_VISIBLE +#define android_widget_Button_SYSTEM_UI_FLAG_VISIBLE 0L +#undef android_widget_Button_SYSTEM_UI_LAYOUT_FLAGS +#define android_widget_Button_SYSTEM_UI_LAYOUT_FLAGS 1536L +#undef android_widget_Button_TEXT_ALIGNMENT_CENTER +#define android_widget_Button_TEXT_ALIGNMENT_CENTER 4L +#undef android_widget_Button_TEXT_ALIGNMENT_GRAVITY +#define android_widget_Button_TEXT_ALIGNMENT_GRAVITY 1L +#undef android_widget_Button_TEXT_ALIGNMENT_INHERIT +#define android_widget_Button_TEXT_ALIGNMENT_INHERIT 0L +#undef android_widget_Button_TEXT_ALIGNMENT_TEXT_END +#define android_widget_Button_TEXT_ALIGNMENT_TEXT_END 3L +#undef android_widget_Button_TEXT_ALIGNMENT_TEXT_START +#define android_widget_Button_TEXT_ALIGNMENT_TEXT_START 2L +#undef android_widget_Button_TEXT_ALIGNMENT_VIEW_END +#define android_widget_Button_TEXT_ALIGNMENT_VIEW_END 6L +#undef android_widget_Button_TEXT_ALIGNMENT_VIEW_START +#define android_widget_Button_TEXT_ALIGNMENT_VIEW_START 5L +#undef android_widget_Button_TEXT_DIRECTION_ANY_RTL +#define android_widget_Button_TEXT_DIRECTION_ANY_RTL 2L +#undef android_widget_Button_TEXT_DIRECTION_FIRST_STRONG +#define android_widget_Button_TEXT_DIRECTION_FIRST_STRONG 1L +#undef android_widget_Button_TEXT_DIRECTION_INHERIT +#define android_widget_Button_TEXT_DIRECTION_INHERIT 0L +#undef android_widget_Button_TEXT_DIRECTION_LOCALE +#define android_widget_Button_TEXT_DIRECTION_LOCALE 5L +#undef android_widget_Button_TEXT_DIRECTION_LTR +#define android_widget_Button_TEXT_DIRECTION_LTR 3L +#undef android_widget_Button_TEXT_DIRECTION_RTL +#define android_widget_Button_TEXT_DIRECTION_RTL 4L +/* + * Class: android_widget_Button + * Method: native_constructor + * Signature: (Landroid/content/Context;Landroid/util/AttributeSet;)J + */ +JNIEXPORT jlong JNICALL Java_android_widget_Button_native_1constructor + (JNIEnv *, jobject, jobject, jobject); + +/* + * Class: android_widget_Button + * Method: native_setText + * Signature: (JLjava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_android_widget_Button_native_1setText + (JNIEnv *, jobject, jlong, jstring); + +/* + * Class: android_widget_Button + * Method: native_setOnClickListener + * Signature: (JLandroid/view/View/OnClickListener;)V + */ +JNIEXPORT void JNICALL Java_android_widget_Button_native_1setOnClickListener + (JNIEnv *, jobject, jlong, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/widgets/android_widget_Button.c b/src/api-impl-jni/widgets/android_widget_Button.c new file mode 100644 index 00000000..1b3a0f9b --- /dev/null +++ b/src/api-impl-jni/widgets/android_widget_Button.c @@ -0,0 +1,62 @@ +#include + +#include "../defines.h" +#include "../util.h" + +#include "WrapperWidget.h" + +#include "../generated_headers/android_widget_Button.h" + +JNIEXPORT jlong JNICALL Java_android_widget_Button_native_1constructor(JNIEnv *env, jobject this, jobject context, jobject attrs) +{ + const char *text = attribute_set_get_string(env, attrs, "text", NULL) ?: "FIXME"; + + GtkWidget *wrapper = g_object_ref(wrapper_widget_new()); + GtkWidget *label = gtk_button_new_with_label(text); + wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), label); + return _INTPTR(label); +} + +JNIEXPORT void JNICALL Java_android_widget_Button_native_1setText(JNIEnv *env, jobject this, jlong widget_ptr, jobject text) +{ + GtkButton *button = GTK_BUTTON(_PTR(widget_ptr)); + + const char *nativeText = ((*env)->GetStringUTFChars(env, text, NULL)); + gtk_button_set_label(button, nativeText); + ((*env)->ReleaseStringUTFChars(env, text, nativeText)); +} + +struct touch_callback_data { + JavaVM *jvm; + jobject this; + jobject listener; + jmethodID listener_method; +}; + +static void clicked_cb(GtkWidget *button, struct touch_callback_data *d) { + JNIEnv *env; + (*d->jvm)->GetEnv(d->jvm, (void**)&env, JNI_VERSION_1_6); + + (*env)->CallBooleanMethod(env, d->listener, d->listener_method, d->this); + + if((*env)->ExceptionCheck(env)) + (*env)->ExceptionDescribe(env); +} + +JNIEXPORT void JNICALL Java_android_widget_Button_native_1setOnClickListener(JNIEnv *env, jobject this, jlong widget_ptr, jobject on_click_listener) +{ + GtkWidget *button = GTK_WIDGET(_PTR(widget_ptr)); + if (!on_click_listener) + return; + + JavaVM *jvm; + (*env)->GetJavaVM(env, &jvm); + + struct touch_callback_data *callback_data = malloc(sizeof(struct touch_callback_data)); + callback_data->jvm = jvm; + callback_data->this = _REF(this); + callback_data->listener = _REF(on_click_listener); + callback_data->listener_method = _METHOD(_CLASS(on_click_listener), "onClick", "(Landroid/view/View;)V"); + + g_signal_connect(button, "clicked", G_CALLBACK(clicked_cb), callback_data); +} diff --git a/src/api-impl/android/widget/Button.java b/src/api-impl/android/widget/Button.java index 8519f604..54ad69da 100644 --- a/src/api-impl/android/widget/Button.java +++ b/src/api-impl/android/widget/Button.java @@ -1,6 +1,7 @@ package android.widget; import android.content.Context; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; @@ -12,6 +13,26 @@ public class Button extends View { public Button(Context context, AttributeSet attributeSet) { super(context, attributeSet); + + TypedArray a = context.obtainStyledAttributes(attributeSet, com.android.internal.R.styleable.TextView, 0, 0); + if (a.hasValue(com.android.internal.R.styleable.TextView_text)) { + setText(a.getText(com.android.internal.R.styleable.TextView_text)); + } + a.recycle(); + } + + @Override + protected native long native_constructor(Context context, AttributeSet attrs); + public native final void native_setText(long widget, String text); + protected native void native_setOnClickListener(long widget, OnClickListener l); + + public final void setText(CharSequence text) { + native_setText(widget, String.valueOf(text)); + } + + @Override + public void setOnClickListener(final OnClickListener l) { + native_setOnClickListener(widget, l); } }