changeset 2477:3fbf8783122d

Android: First functional version. Notebook-less first page of dwtest works. FindClass failed on any created threads.. using a modified version of this: https://stackoverflow.com/questions/13263340/findclass-from-any-thread-in-android-jni Implemented dw_box_unpack(). Had to do this to fix an exception when repacking a widget in dwtest's archive_add().
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 22 Apr 2021 17:49:20 +0000
parents 20c9e83cba2a
children b0230e378667
files android/DWindows.kt android/dw.cpp
diffstat 2 files changed, 64 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Thu Apr 22 00:04:01 2021 +0000
+++ b/android/DWindows.kt	Thu Apr 22 17:49:20 2021 +0000
@@ -9,12 +9,9 @@
 
 class DWindows : AppCompatActivity()
 {
-    public var windowLayout: LinearLayout = LinearLayout(this)
-
     override fun onCreate(savedInstanceState: Bundle?)
     {
         super.onCreate(savedInstanceState)
-        setContentView(windowLayout)
 
         val m = packageManager
         var s = packageName
@@ -31,6 +28,8 @@
      */
     fun windowNew(title: String, style: Int): LinearLayout
     {
+        var windowLayout: LinearLayout = LinearLayout(this)
+        setContentView(windowLayout)
         // For now we just return our DWindows' main activity layout...
         // in the future, later calls should create new activities
         return windowLayout
@@ -68,6 +67,12 @@
         box.addView(item)
     }
 
+    fun boxUnpack(item: View)
+    {
+        var box: LinearLayout = item.parent as LinearLayout
+        box.removeView(item)
+    }
+
     fun buttonNew(text: String, cid: Int): Button
     {
         val button = Button(this)
--- a/android/dw.cpp	Thu Apr 22 00:04:01 2021 +0000
+++ b/android/dw.cpp	Thu Apr 22 17:49:20 2021 +0000
@@ -40,6 +40,36 @@
 static HEV _dw_main_event;
 static JavaVM *_dw_jvm;
 static jobject _dw_obj;
+static jobject _dw_class_loader;
+static jmethodID _dw_class_method;
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved)
+{
+    JNIEnv *env;
+    jclass randomClass, classClass, classLoaderClass;
+    jmethodID getClassLoaderMethod;
+
+    /* Initialize the handle to the Java Virtual Machine */
+    _dw_jvm = pjvm;
+    _dw_jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
+
+    randomClass = env->FindClass(DW_CLASS_NAME);
+    classClass = env->GetObjectClass(randomClass);
+    classLoaderClass = env->FindClass("java/lang/ClassLoader");
+    getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
+                                                 "()Ljava/lang/ClassLoader;");
+    _dw_class_loader = env->NewGlobalRef(env->CallObjectMethod(randomClass, getClassLoaderMethod));
+    _dw_class_method = env->GetMethodID(classLoaderClass, "findClass",
+                                        "(Ljava/lang/String;)Ljava/lang/Class;");
+
+    return JNI_VERSION_1_6;
+}
+
+jclass _dw_find_class(JNIEnv *env, const char* name)
+{
+    return static_cast<jclass>(env->CallObjectMethod(_dw_class_loader, _dw_class_method, env->NewStringUTF(name)));
+}
+
 
 /* Call the dwmain entry point, Android has no args, so just pass the app path */
 void _dw_main_launch(char *arg)
@@ -55,15 +85,15 @@
  *      path: The path to the Android app.
  */
 JNIEXPORT jstring JNICALL
-Java_org_dbsoft_dwindows_dwtest_DWindows_dwindowsInit(
-        JNIEnv* env, jobject obj, jstring path) {
+Java_org_dbsoft_dwindows_dwtest_DWindows_dwindowsInit(JNIEnv* env, jobject obj, jstring path)
+{
     char *arg = strdup(env->GetStringUTFChars((jstring) path, NULL));
 
-    /* Initialize the handle to the Java Virtual Machine */
-    env->GetJavaVM(&_dw_jvm);
-    _dw_obj = obj;
+    /* Save our class object pointer for later */
+    _dw_obj = env->NewGlobalRef(obj);
 
     /* Save the JNIEnv for the main thread */
+    pthread_key_create(&_dw_env_key, NULL);
     pthread_setspecific(_dw_env_key, env);
 
     /* Create the dwmain event */
@@ -367,7 +397,7 @@
     if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID boxNew = env->GetMethodID(clazz, "boxNew", "(II)Landroid/widget/LinearLayout;");
         // Call the method on the object
@@ -431,14 +461,14 @@
 }
 
 /* Internal box packing function called by the other 3 functions */
-void _dw_box_pack(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad, char *funcname)
+void _dw_box_pack(HWND box, HWND item, int index, int width, int height, int hsize, int vsize, int pad, const char *funcname)
 {
     JNIEnv *env;
 
     if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID boxPack = env->GetMethodID(clazz, "boxPack", "(Landroid/widget/LinearLayout;Landroid/view/View;IIIIII)V");
         // Call the method on the object
@@ -455,6 +485,18 @@
  */
 int API dw_box_unpack(HWND handle)
 {
+    JNIEnv *env;
+
+    if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
+    {
+        // 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 boxUnpack = env->GetMethodID(clazz, "boxUnpack", "(Landroid/view/View;)V");
+        // Call the method on the object
+        env->CallVoidMethod(_dw_obj, boxUnpack, handle);
+        return DW_ERROR_NONE;
+    }
     return DW_ERROR_GENERAL;
 }
 
@@ -540,7 +582,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID buttonNew = env->GetMethodID(clazz, "buttonNew",
                                                "(Ljava/lang/String;I)Landroid/widget/Button;");
@@ -560,7 +602,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID entryfieldNew = env->GetMethodID(clazz, "entryfieldNew",
                                                    "(Ljava/lang/String;II)Landroid/widget/EditText;");
@@ -714,7 +756,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID radioButtonNew = env->GetMethodID(clazz, "radioButtonNew",
                                                     "(Ljava/lang/String;I)Landroid/widget/RadioButton;");
@@ -846,7 +888,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID checkboxNew = env->GetMethodID(clazz, "checkboxNew",
                                                  "(Ljava/lang/String;I)Landroid/widget/CheckBox;");
@@ -1202,7 +1244,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID textNew = env->GetMethodID(clazz, "textNew",
                                              "(Ljava/lang/String;II)Landroid/widget/TextView;");
@@ -2500,7 +2542,7 @@
         // Construct a String
         jstring jstr = env->NewStringUTF(title);
         // First get the class that contains the method you need to call
-        jclass clazz = env->FindClass(DW_CLASS_NAME);
+        jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID windowNew = env->GetMethodID(clazz, "windowNew",
                                                "(Ljava/lang/String;I)Landroid/widget/LinearLayout;");