diff options
author | Anish Mishra <mishragames@gmail.com> | 2024-10-27 16:29:55 +0530 |
---|---|---|
committer | Anish Mishra <mishragames@gmail.com> | 2024-10-29 20:02:08 +0530 |
commit | be5d7f757d70596f628c9ac8a3cba8412cc34fa7 (patch) | |
tree | 7de9efdc93d15884106470b0b134db6836fd2ddb | |
parent | 08f9cba0fbf27f171dea55de6f8274928b9f0d84 (diff) | |
download | redot-engine-be5d7f757d70596f628c9ac8a3cba8412cc34fa7.tar.gz |
[Android] Implement native input dialog support
-rw-r--r-- | doc/classes/DisplayServer.xml | 2 | ||||
-rw-r--r-- | platform/android/display_server_android.cpp | 15 | ||||
-rw-r--r-- | platform/android/display_server_android.h | 5 | ||||
-rw-r--r-- | platform/android/java/lib/res/values/dimens.xml | 2 | ||||
-rw-r--r-- | platform/android/java/lib/res/values/strings.xml | 3 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/Godot.kt | 29 | ||||
-rw-r--r-- | platform/android/java/lib/src/org/godotengine/godot/GodotLib.java | 5 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.cpp | 8 | ||||
-rw-r--r-- | platform/android/java_godot_lib_jni.h | 1 | ||||
-rw-r--r-- | platform/android/java_godot_wrapper.cpp | 18 | ||||
-rw-r--r-- | platform/android/java_godot_wrapper.h | 2 |
11 files changed, 87 insertions, 3 deletions
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index 45e802519e..f6ff6da0c3 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -105,7 +105,7 @@ <param index="3" name="callback" type="Callable" /> <description> Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [String] parameter which contains the text field's contents. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_INPUT] feature. Supported platforms include macOS and Windows. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_INPUT] feature. Supported platforms include macOS, Windows, and Android. </description> </method> <method name="dialog_show"> diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index e3ee1dd631..00fde9a891 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -71,7 +71,7 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const { case FEATURE_MOUSE: //case FEATURE_MOUSE_WARP: //case FEATURE_NATIVE_DIALOG: - //case FEATURE_NATIVE_DIALOG_INPUT: + case FEATURE_NATIVE_DIALOG_INPUT: //case FEATURE_NATIVE_DIALOG_FILE: //case FEATURE_NATIVE_ICON: //case FEATURE_WINDOW_TRANSPARENCY: @@ -176,6 +176,19 @@ bool DisplayServerAndroid::clipboard_has() const { } } +Error DisplayServerAndroid::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { + GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java(); + ERR_FAIL_NULL_V(godot_java, FAILED); + input_dialog_callback = p_callback; + return godot_java->show_input_dialog(p_title, p_description, p_partial); +} + +void DisplayServerAndroid::emit_input_dialog_callback(String p_text) { + if (input_dialog_callback.is_valid()) { + input_dialog_callback.call_deferred(p_text); + } +} + TypedArray<Rect2> DisplayServerAndroid::get_display_cutouts() const { GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java(); ERR_FAIL_NULL_V(godot_io_java, Array()); diff --git a/platform/android/display_server_android.h b/platform/android/display_server_android.h index 65c6a53446..c44a265750 100644 --- a/platform/android/display_server_android.h +++ b/platform/android/display_server_android.h @@ -87,6 +87,8 @@ class DisplayServerAndroid : public DisplayServer { Callable system_theme_changed; + Callable input_dialog_callback; + void _window_callback(const Callable &p_callable, const Variant &p_arg, bool p_deferred = false) const; static void _dispatch_input_events(const Ref<InputEvent> &p_event); @@ -116,6 +118,9 @@ public: virtual String clipboard_get() const override; virtual bool clipboard_has() const override; + virtual Error dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) override; + void emit_input_dialog_callback(String p_text); + virtual TypedArray<Rect2> get_display_cutouts() const override; virtual Rect2i get_display_safe_area() const override; diff --git a/platform/android/java/lib/res/values/dimens.xml b/platform/android/java/lib/res/values/dimens.xml index 9034dbbcc1..287d1c8920 100644 --- a/platform/android/java/lib/res/values/dimens.xml +++ b/platform/android/java/lib/res/values/dimens.xml @@ -1,4 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="text_edit_height">48dp</dimen> + <dimen name="input_dialog_padding_horizontal">10dp</dimen> + <dimen name="input_dialog_padding_vertical">5dp</dimen> </resources> diff --git a/platform/android/java/lib/res/values/strings.xml b/platform/android/java/lib/res/values/strings.xml index 03752e092e..e44addadd0 100644 --- a/platform/android/java/lib/res/values/strings.xml +++ b/platform/android/java/lib/res/values/strings.xml @@ -55,4 +55,7 @@ <string name="kilobytes_per_second">%1$s KB/s</string> <string name="time_remaining">Time remaining: %1$s</string> <string name="time_remaining_notification">%1$s left</string> + + <!-- Labels for the dialog action buttons --> + <string name="dialog_ok">OK</string> </resources> diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt index 567b134234..f4b9771128 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt @@ -44,6 +44,7 @@ import android.os.* import android.util.Log import android.util.TypedValue import android.view.* +import android.widget.EditText import android.widget.FrameLayout import androidx.annotation.Keep import androidx.annotation.StringRes @@ -81,6 +82,7 @@ import java.util.* import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicReference + /** * Core component used to interface with the native layer of the engine. * @@ -772,7 +774,7 @@ class Godot(private val context: Context) { val builder = AlertDialog.Builder(activity) builder.setMessage(message).setTitle(title) builder.setPositiveButton( - "OK" + R.string.dialog_ok ) { dialog: DialogInterface, id: Int -> okCallback?.run() dialog.cancel() @@ -877,6 +879,31 @@ class Godot(private val context: Context) { } /** + * Popup a dialog to input text. + */ + @Keep + private fun showInputDialog(title: String, message: String, existingText: String) { + val activity: Activity = getActivity() ?: return + val inputField = EditText(activity) + val paddingHorizontal = activity.resources.getDimensionPixelSize(R.dimen.input_dialog_padding_horizontal) + val paddingVertical = activity.resources.getDimensionPixelSize(R.dimen.input_dialog_padding_vertical) + inputField.setPadding(paddingHorizontal, paddingVertical, paddingHorizontal, paddingVertical) + inputField.setText(existingText) + runOnUiThread { + val builder = AlertDialog.Builder(activity) + builder.setMessage(message).setTitle(title).setView(inputField) + builder.setPositiveButton(R.string.dialog_ok) { + dialog: DialogInterface, id: Int -> + GodotLib.inputDialogCallback(inputField.text.toString()) + dialog.dismiss() + } + val dialog = builder.create() + dialog.show() + } + } + + + /** * Destroys the Godot Engine and kill the process it's running in. */ @JvmOverloads diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 295a4a6340..3c58e05dda 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -225,6 +225,11 @@ public class GodotLib { public static native void onNightModeChanged(); /** + * Invoked on the input dialog submitted. + */ + public static native void inputDialogCallback(String p_text); + + /** * Invoked on the GL thread to configure the height of the virtual keyboard. */ public static native void setVirtualKeyboardHeight(int p_height); diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 1a256959cd..997534ada3 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -540,6 +540,14 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JN } } +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_inputDialogCallback(JNIEnv *env, jclass clazz, jstring p_text) { + DisplayServerAndroid *ds = (DisplayServerAndroid *)DisplayServer::get_singleton(); + if (ds) { + String text = jstring_to_string(p_text, env); + ds->emit_input_dialog_callback(text); + } +} + JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result) { String permission = jstring_to_string(p_permission, env); if (permission == "android.permission.RECORD_AUDIO" && p_result) { diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index 2165ce264b..65ba1b2953 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -67,6 +67,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_requestPermissionResult(JNIEnv *env, jclass clazz, jstring p_permission, jboolean p_result); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onNightModeChanged(JNIEnv *env, jclass clazz); +JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_inputDialogCallback(JNIEnv *env, jclass clazz, jstring p_text); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererResumed(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_onRendererPaused(JNIEnv *env, jclass clazz); JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInputToRenderThread(JNIEnv *env, jclass clazz); diff --git a/platform/android/java_godot_wrapper.cpp b/platform/android/java_godot_wrapper.cpp index d3b30e4589..aae6ff23da 100644 --- a/platform/android/java_godot_wrapper.cpp +++ b/platform/android/java_godot_wrapper.cpp @@ -67,6 +67,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_ _get_clipboard = p_env->GetMethodID(godot_class, "getClipboard", "()Ljava/lang/String;"); _set_clipboard = p_env->GetMethodID(godot_class, "setClipboard", "(Ljava/lang/String;)V"); _has_clipboard = p_env->GetMethodID(godot_class, "hasClipboard", "()Z"); + _show_input_dialog = p_env->GetMethodID(godot_class, "showInputDialog", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); _request_permission = p_env->GetMethodID(godot_class, "requestPermission", "(Ljava/lang/String;)Z"); _request_permissions = p_env->GetMethodID(godot_class, "requestPermissions", "()Z"); _get_granted_permissions = p_env->GetMethodID(godot_class, "getGrantedPermissions", "()[Ljava/lang/String;"); @@ -268,6 +269,23 @@ bool GodotJavaWrapper::has_clipboard() { } } +Error GodotJavaWrapper::show_input_dialog(const String &p_title, const String &p_message, const String &p_existing_text) { + if (_show_input_dialog) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED); + jstring jStrTitle = env->NewStringUTF(p_title.utf8().get_data()); + jstring jStrMessage = env->NewStringUTF(p_message.utf8().get_data()); + jstring jStrExistingText = env->NewStringUTF(p_existing_text.utf8().get_data()); + env->CallVoidMethod(godot_instance, _show_input_dialog, jStrTitle, jStrMessage, jStrExistingText); + env->DeleteLocalRef(jStrTitle); + env->DeleteLocalRef(jStrMessage); + env->DeleteLocalRef(jStrExistingText); + return OK; + } else { + return ERR_UNCONFIGURED; + } +} + bool GodotJavaWrapper::request_permission(const String &p_name) { if (_request_permission) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_wrapper.h b/platform/android/java_godot_wrapper.h index 51d7f98541..4fa3098397 100644 --- a/platform/android/java_godot_wrapper.h +++ b/platform/android/java_godot_wrapper.h @@ -58,6 +58,7 @@ private: jmethodID _get_clipboard = nullptr; jmethodID _set_clipboard = nullptr; jmethodID _has_clipboard = nullptr; + jmethodID _show_input_dialog = nullptr; jmethodID _request_permission = nullptr; jmethodID _request_permissions = nullptr; jmethodID _get_granted_permissions = nullptr; @@ -103,6 +104,7 @@ public: void set_clipboard(const String &p_text); bool has_has_clipboard(); bool has_clipboard(); + Error show_input_dialog(const String &p_title, const String &p_message, const String &p_existing_text); bool request_permission(const String &p_name); bool request_permissions(); Vector<String> get_granted_permissions() const; |