changeset 2982:e6fb2558e29e

Android: Support for dw_html_javascript_add() and DW_SIGNAL_HTML_MESSAGE. Have to bump Android minimum API version to 26 (Oreo) for this to work. Not completely functional but I need change locations, it builds.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Mon, 27 Mar 2023 00:40:17 +0000
parents 0058ab32e1bd
children 81611e54ff1d
files android/DWindows.kt android/dw.cpp
diffstat 2 files changed, 103 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Sun Mar 26 22:10:10 2023 +0000
+++ b/android/DWindows.kt	Mon Mar 27 00:40:17 2023 +0000
@@ -40,11 +40,13 @@
 import android.view.*
 import android.view.View.OnTouchListener
 import android.view.inputmethod.EditorInfo
+import android.webkit.JavascriptInterface
 import android.webkit.WebView
 import android.webkit.WebViewClient
 import android.widget.*
 import android.widget.AdapterView.OnItemClickListener
 import android.widget.SeekBar.OnSeekBarChangeListener
+import androidx.annotation.RequiresApi
 import androidx.appcompat.app.AlertDialog
 import androidx.appcompat.app.AppCompatActivity
 import androidx.appcompat.widget.AppCompatEditText
@@ -1495,6 +1497,7 @@
     const val COLUMN_CLICK = 17
     const val HTML_RESULT = 18
     const val HTML_CHANGED = 19
+    const val HTML_MESSAGE = 20
 }
 
 val DWImageExts = arrayOf("", ".png", ".webp", ".jpg", ".jpeg", ".gif")
@@ -1524,6 +1527,8 @@
 }
 
 private class DWWebViewClient : WebViewClient() {
+    val HTMLAdds = mutableListOf<String>()
+
     //Implement shouldOverrideUrlLoading//
     @Deprecated("Deprecated in Java")
     override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
@@ -1537,6 +1542,9 @@
     }
 
     override fun onPageFinished(view: WebView, url: String) {
+        // Inject the functions on the page on complete
+        HTMLAdds.forEach { e -> view.loadUrl("javascript:function $e(body) { DWindows.postMessage($e, body) }") }
+
         // Handle the DW_HTML_CHANGE_COMPLETE event
         eventHandlerHTMLChanged(view, DWEvent.HTML_CHANGED, url, 4)
     }
@@ -1544,6 +1552,17 @@
     external fun eventHandlerHTMLChanged(obj1: View, message: Int, URI: String, status: Int)
 }
 
+class DWWebViewInterface internal constructor(var view: View) {
+    /* Show a toast from the web page  */
+    @JavascriptInterface
+    fun postMessage(name: String?, body: String?) {
+        // Handle the DW_HTML_CHANGE_COMPLETE event
+        eventHandlerHTMLMessage(view, DWEvent.HTML_CHANGED, name, body)
+    }
+
+    external fun eventHandlerHTMLMessage(obj1: View, message: Int, hmltName: String?, htmlBody: String?)
+}
+
 class DWPrintDocumentAdapter : PrintDocumentAdapter()
 {
     var context: Context? = null
@@ -4740,6 +4759,7 @@
             // Configure a few settings to make it behave as we expect
             html!!.webViewClient = DWWebViewClient()
             html!!.settings.javaScriptEnabled = true
+            html!!.addJavascriptInterface(DWWebViewInterface(html!!), "DWindows");
         }
         return html
     }
@@ -4769,6 +4789,14 @@
         }
     }
 
+    fun htmlJavascriptAdd(html: WebView, name: String)
+    {
+        waitOnUiThread {
+            val client = html.webViewClient as DWWebViewClient
+            client.HTMLAdds += name
+        }
+    }
+
     fun htmlAction(html: WebView, action: Int)
     {
         waitOnUiThread {
--- a/android/dw.cpp	Sun Mar 26 22:10:10 2023 +0000
+++ b/android/dw.cpp	Mon Mar 27 00:40:17 2023 +0000
@@ -5,7 +5,7 @@
  * (C) 2011-2023 Brian Smith <brian@dbsoft.org>
  * (C) 2011-2022 Mark Hessling <mark@rexx.org>
  *
- * Requires Android API 23 (Marshmallow) or higher.
+ * Requires Android API 26 (Oreo) or higher.
  *
  */
 
@@ -251,9 +251,7 @@
 } DWSignalList;
 
 /* List of signals */
-#define SIGNALMAX 19
-
-static DWSignalList DWSignalTranslate[SIGNALMAX] = {
+static DWSignalList DWSignalTranslate[] = {
         { _DW_EVENT_CONFIGURE,      DW_SIGNAL_CONFIGURE },
         { _DW_EVENT_KEY_PRESS,      DW_SIGNAL_KEY_PRESS },
         { _DW_EVENT_BUTTON_PRESS,   DW_SIGNAL_BUTTON_PRESS },
@@ -272,7 +270,9 @@
         { _DW_EVENT_TREE_EXPAND,    DW_SIGNAL_TREE_EXPAND },
         { _DW_EVENT_COLUMN_CLICK,   DW_SIGNAL_COLUMN_CLICK },
         { _DW_EVENT_HTML_RESULT,    DW_SIGNAL_HTML_RESULT },
-        { _DW_EVENT_HTML_CHANGED,   DW_SIGNAL_HTML_CHANGED }
+        { _DW_EVENT_HTML_CHANGED,   DW_SIGNAL_HTML_CHANGED },
+        { _DW_EVENT_HTML_MESSAGE,   DW_SIGNAL_HTML_MESSAGE },
+        { 0,                                    "" }
 };
 
 #define _DW_EVENT_PARAM_SIZE 10
@@ -475,6 +475,20 @@
                     free(uri);
                 break;
             }
+                /* HTML message event */
+            case _DW_EVENT_HTML_MESSAGE:
+            {
+                int (* API htmlmessagefunc)(HWND, char *, char *, void *) = (int (* API)(HWND, char *, char *, void *))handler->signalfunction;
+                char *name = (char *)params[1];
+                char *body = (char *)params[2];
+
+                retval = htmlmessagefunc(handler->window, name, body, handler->data);
+                if(name)
+                    free(name);
+                if(body)
+                    free(body);
+                break;
+            }
         }
     }
     return retval;
@@ -666,6 +680,25 @@
         env->ReleaseStringUTFChars(URI, uri);
 }
 
+JNIEXPORT void JNICALL
+Java_org_dbsoft_dwindows_DWWebViewInterface_eventHandlerHTMLMessage(JNIEnv *env, jobject thiz,
+                                                                    jobject obj1, jint message,
+                                                                    jstring htmlName, jstring htmlBody) {
+    const char *name = env->GetStringUTFChars(htmlName, nullptr);
+    const char *body = env->GetStringUTFChars(htmlBody, nullptr);
+    void *params[_DW_EVENT_PARAM_SIZE] = { nullptr, DW_POINTER(name ? strdup(name) : nullptr),
+                                           DW_POINTER(body ? strdup(body) : nullptr),
+                                           nullptr, nullptr, nullptr, nullptr, nullptr,
+                                           DW_INT_TO_POINTER(message), nullptr };
+
+    _dw_event_handler(obj1, params);
+    if(name)
+        env->ReleaseStringUTFChars(htmlName, name);
+    if(body)
+        env->ReleaseStringUTFChars(htmlBody, body);
+}
+
+
 typedef struct _dwprint
 {
     int (*drawfunc)(HPRINT, HPIXMAP, int, void *);
@@ -885,12 +918,13 @@
 /* Finds the message number for a given signal name */
 ULONG _dw_findsigmessage(const char *signame)
 {
-    int z;
-
-    for(z=0;z<SIGNALMAX;z++)
+    int z = 0;
+
+    while(DWSignalTranslate[z].message)
     {
         if(strcasecmp(signame, DWSignalTranslate[z].name) == 0)
             return DWSignalTranslate[z].message;
+        z++;
     }
     return 0L;
 }
@@ -5277,6 +5311,38 @@
 }
 
 /*
+ * Install a javascript function with name that can call native code.
+ * Parameters:
+ *       handle: Handle to the HTML window.
+ *       name: Javascript function name.
+ * Notes: A DW_SIGNAL_HTML_MESSAGE event will be raised with scriptdata.
+ * Returns:
+ *       DW_ERROR_NONE (0) on success.
+ */
+int API dw_html_javascript_add(HWND handle, const char *name)
+{
+    JNIEnv *env;
+    int retval = DW_ERROR_UNKNOWN;
+
+    if(handle && name && (env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
+    {
+        // Construct a String
+        jstring jstr = env->NewStringUTF(name);
+        // First get the class that contains the method you need to call
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
+        // Get the method that you want to call
+        jmethodID htmlJavascriptAdd = env->GetMethodID(clazz, "htmlJavascriptAdd",
+                                                       "(Landroid/webkit/WebView;Ljava/lang/String;)V");
+        // Call the method on the object
+        env->CallVoidMethod(_dw_obj, htmlJavascriptAdd, handle, jstr);
+        if(!_dw_jni_check_exception(env))
+            retval = DW_ERROR_NONE;
+        env->DeleteLocalRef(jstr);
+    }
+    return retval;
+}
+
+/*
  * Create a new HTML window (widget) to be packed.
  * Parameters:
  *       id: An ID to be used with dw_window_from_id() or 0L.
@@ -8222,4 +8288,4 @@
 
 #ifdef __cplusplus
 }
-#endif
\ No newline at end of file
+#endif