changeset 2494:b3e28eed0e50

Android: Fix the basics of notebook control... return actual page IDs. Also need to ensure the box packed in notebookPagePack is MATCH_PARENT. Also prevent multiple calls to dwindowsInit() from spawning multiple instances of dwmain().
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sun, 02 May 2021 10:46:21 +0000
parents bca7e0ab0ccc
children 5664c91d03fb
files android/DWindows.kt android/dw.cpp
diffstat 2 files changed, 120 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Sun May 02 01:05:20 2021 +0000
+++ b/android/DWindows.kt	Sun May 02 10:46:21 2021 +0000
@@ -32,6 +32,8 @@
 
 class DWTabViewPagerAdapter : RecyclerView.Adapter<DWTabViewPagerAdapter.EventViewHolder>() {
     public val viewList = mutableListOf<LinearLayout>()
+    public val pageList = mutableListOf<Long>()
+    public var currentPageID = 0L
 
     override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
             EventViewHolder(viewList.get(0))
@@ -362,27 +364,31 @@
 
         notebook.tag = dataArrayMap
         notebook.id = cid
+        tabs.id = View.generateViewId()
+        pager.id = View.generateViewId()
         pager.adapter = DWTabViewPagerAdapter()
         TabLayoutMediator(tabs, pager) { tab, position ->
-            tab.text = "OBJECT ${(position + 1)}"
+            //tab.text = "OBJECT ${(position + 1)}"
         }.attach()
 
         var params: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams(w, h)
-        tabs.layoutParams = params
-        notebook.addView(tabs)
-        if (top != 0) {
-            notebook.addView(pager, 0)
+        if(top != 0) {
+            params.addRule(RelativeLayout.ABOVE, pager.id)
         } else {
-            notebook.addView(pager)
+            params.addRule(RelativeLayout.BELOW, pager.id)
         }
+        tabs.tabGravity = TabLayout.GRAVITY_FILL
+        tabs.tabMode = TabLayout.MODE_FIXED
+        notebook.addView(tabs, params)
+        notebook.addView(pager, RelativeLayout.LayoutParams(w, w))
         return notebook
     }
 
-    fun notebookPageNew(notebook: RelativeLayout, flags: Long, front: Int): Any?
+    fun notebookPageNew(notebook: RelativeLayout, flags: Long, front: Int): Long
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
-        var tab: Any? = null
+        var pageID = 0L
 
         if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
             pager = notebook.getChildAt(0) as ViewPager2
@@ -394,21 +400,29 @@
 
         if(pager != null && tabs != null) {
             var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            var tab = tabs.newTab()
 
-            tab = tabs.newTab()
+            // Increment our page ID... making sure no duplicates exist
+            do {
+                adapter.currentPageID += 1
+            }
+            while(adapter.currentPageID == 0L || adapter.pageList.contains(adapter.currentPageID))
+            pageID = adapter.currentPageID
             // Temporarily add a black tab with an empty layout/box
             if(front != 0) {
                 adapter.viewList.add(0, LinearLayout(this))
+                adapter.pageList.add(0, pageID)
                 tabs.addTab(tab, 0)
             } else {
                 adapter.viewList.add(LinearLayout(this))
+                adapter.pageList.add(pageID)
                 tabs.addTab(tab)
             }
         }
-        return tab
+        return pageID
     }
 
-    fun notebookPageDestroy(notebook: RelativeLayout, tab: TabLayout.Tab)
+    fun notebookPageDestroy(notebook: RelativeLayout, pageID: Long)
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
@@ -423,13 +437,18 @@
 
         if(pager != null && tabs != null) {
             var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            val index = adapter.pageList.indexOf(pageID)
+            val tab = tabs.getTabAt(index)
 
-            adapter.viewList.removeAt(tab.position)
-            tabs.removeTab(tab)
+            if (tab != null) {
+                adapter.viewList.removeAt(index)
+                adapter.pageList.removeAt(index)
+                tabs.removeTab(tab)
+            }
         }
     }
 
-    fun notebookPageSetText(notebook: RelativeLayout, tab: TabLayout.Tab, text: String)
+    fun notebookPageSetText(notebook: RelativeLayout, pageID: Long, text: String)
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
@@ -443,11 +462,17 @@
         }
 
         if(pager != null && tabs != null) {
-            tab.text = text
+            val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            val index = adapter.pageList.indexOf(pageID)
+            val tab = tabs.getTabAt(index)
+
+            if (tab != null) {
+                tab.text = text
+            }
         }
     }
 
-    fun notebookPack(notebook: RelativeLayout, tab: TabLayout.Tab, box: LinearLayout)
+    fun notebookPagePack(notebook: RelativeLayout, pageID: Long, box: LinearLayout)
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
@@ -462,12 +487,17 @@
 
         if(pager != null && tabs != null) {
             var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            val index = adapter.pageList.indexOf(pageID)
 
-            adapter.viewList[tab.position] = box
+            // Make sure the box is MATCH_PARENT
+            box.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
+                                                         LinearLayout.LayoutParams.MATCH_PARENT);
+
+            adapter.viewList[index] = box
         }
     }
 
-    fun notebookPageGet(notebook: RelativeLayout): TabLayout.Tab?
+    fun notebookPageGet(notebook: RelativeLayout): Long
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
@@ -481,12 +511,13 @@
         }
 
         if(pager != null && tabs != null) {
-            return tabs.getTabAt(tabs.selectedTabPosition)
+            var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            return adapter.pageList.get(tabs.selectedTabPosition)
         }
-        return null
+        return 0L
     }
 
-    fun notebookPageSet(notebook: RelativeLayout, tab: TabLayout.Tab)
+    fun notebookPageSet(notebook: RelativeLayout, pageID: Long)
     {
         var pager: ViewPager2? = null
         var tabs: TabLayout? = null
@@ -500,6 +531,10 @@
         }
 
         if(pager != null && tabs != null) {
+            val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
+            val index = adapter.pageList.indexOf(pageID)
+            val tab = tabs.getTabAt(index)
+
             tabs.selectTab(tab)
         }
     }
@@ -632,14 +667,20 @@
 
     fun dwindowsExit(exitcode: Int)
     {
-        this.finishActivity(exitcode)
+        this.finishAffinity()
+        System.exit(exitcode)
+    }
+
+    fun dwindowsShutdown()
+    {
+        this.finishAffinity()
     }
 
     /*
      * Native methods that are implemented by the 'dwindows' native library,
      * which is packaged with this application.
      */
-    external fun dwindowsInit(dataDir: String): String
+    external fun dwindowsInit(dataDir: String)
     external fun eventHandler(obj1: View, obj2: View?, message: Int, str1: String?, str2: String?, int1: Int, int2: Int, int3: Int, int4: Int): Int
     external fun eventHandlerSimple(obj1: View, message: Int)
     external fun eventHandlerTimer(sigfunc: Long, data: Long): Int
--- a/android/dw.cpp	Sun May 02 01:05:20 2021 +0000
+++ b/android/dw.cpp	Sun May 02 10:46:21 2021 +0000
@@ -84,27 +84,33 @@
  * Parameters:
  *      path: The path to the Android app.
  */
-JNIEXPORT jstring JNICALL
+JNIEXPORT void JNICALL
 Java_org_dbsoft_dwindows_DWindows_dwindowsInit(JNIEnv* env, jobject obj, jstring path)
 {
-    char *arg = strdup(env->GetStringUTFChars((jstring) path, NULL));
-
-    /* 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 */
-    _dw_main_event = dw_event_new();
-
-    /* Launch the new thread to execute dwmain() */
-    dw_thread_new((void *)_dw_main_launch, arg, 0);
-
-    /* Wait until dwmain() calls dw_main() then return */
-    dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
-    return env->NewStringUTF("Hello from JNI!");
+    static int runcount = 0;
+
+    /* Safety check to prevent multiple initializations */
+    if(runcount == 1)
+    {
+        char *arg = strdup(env->GetStringUTFChars((jstring) path, NULL));
+
+        /* 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 */
+        _dw_main_event = dw_event_new();
+
+        /* Launch the new thread to execute dwmain() */
+        dw_thread_new((void *) _dw_main_launch, arg, 0);
+
+        /* Wait until dwmain() calls dw_main() then return */
+        dw_event_wait(_dw_main_event, DW_TIMEOUT_INFINITE);
+    }
+    runcount++;
 }
 
 typedef struct _sighandler
@@ -484,6 +490,7 @@
         // Call the method on the object
         env->CallVoidMethod(_dw_obj, dwindowsExit, exitcode);
     }
+    // We shouldn't get here, but in case JNI can't call dwindowsExit...
     exit(exitcode);
 }
 
@@ -2969,9 +2976,9 @@
         jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID notebookPageNew = env->GetMethodID(clazz, "notebookPageNew",
-                                                     "(Landroid/widget/RelativeLayout;JI)Ljava/lang/Object;");
+                                                     "(Landroid/widget/RelativeLayout;JI)J");
         // Call the method on the object
-        result = DW_POINTER_TO_INT(env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, notebookPageNew, handle, (jlong)flags, front)));
+        result = (unsigned long)env->CallLongMethod(_dw_obj, notebookPageNew, handle, (jlong)flags, front);
     }
     return result;
 }
@@ -2988,18 +2995,13 @@
 
     if(handle && pageid && (env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
-        jobject tab = (jobject)DW_INT_TO_POINTER(pageid);
-
         // 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 notebookPageDestroy = env->GetMethodID(clazz, "notebookPageDestroy",
-                                                         "(Landroid/widget/RelativeLayout;Lcom/google/android/material/tabs/TabLayout/Tab;)V");
+                                                         "(Landroid/widget/RelativeLayout;J)V");
         // Call the method on the object
-        env->CallVoidMethod(_dw_obj, notebookPageDestroy, handle, tab);
-
-        // Release the global reference
-        env->DeleteWeakGlobalRef(tab);
+        env->CallVoidMethod(_dw_obj, notebookPageDestroy, handle, (jlong)pageid);
     }
 }
 
@@ -3020,9 +3022,9 @@
         jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID notebookPageGet = env->GetMethodID(clazz, "notebookPageGet",
-                                                     "(Landroid/widget/RelativeLayout;)Lcom/google/android/material/tabs/TabLayout/Tab;");
+                                                     "(Landroid/widget/RelativeLayout;)J");
         // Call the method on the object
-        result = DW_POINTER_TO_INT(env->CallObjectMethod(_dw_obj, notebookPageGet, handle));
+        result = (unsigned long)env->CallLongMethod(_dw_obj, notebookPageGet, handle);
     }
     return result;
 }
@@ -3038,15 +3040,13 @@
     JNIEnv *env;
 
     if(handle && pageid && (env = (JNIEnv *)pthread_getspecific(_dw_env_key))) {
-        jobject tab = (jobject) DW_INT_TO_POINTER(pageid);
-
         // 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 notebookPageSet = env->GetMethodID(clazz, "notebookPageSet",
-                                                         "(Landroid/widget/RelativeLayout;Lcom/google/android/material/tabs/TabLayout/Tab;)V");
+                                                     "(Landroid/widget/RelativeLayout;J)V");
         // Call the method on the object
-        env->CallVoidMethod(_dw_obj, notebookPageSet, handle, tab);
+        env->CallVoidMethod(_dw_obj, notebookPageSet, handle, (jlong)pageid);
     }
 }
 
@@ -3063,17 +3063,15 @@
 
     if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
-        jobject tab = (jobject)DW_INT_TO_POINTER(pageid);
-
         // Construct a String
         jstring jstr = env->NewStringUTF(text);
         // 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 notebookPageSetText = env->GetMethodID(clazz, "notebookPageSetText",
-                                                         "(Landroid/widget/RelativeLayout;Lcom/google/android/material/tabs/TabLayout/Tab;Ljava/lang/String;)V");
+                                                         "(Landroid/widget/RelativeLayout;JLjava/lang/String;)V");
         // Call the method on the object
-        env->CallVoidMethod(_dw_obj, notebookPageSetText, handle, tab, jstr);
+        env->CallVoidMethod(_dw_obj, notebookPageSetText, handle, (jlong)pageid, jstr);
     }
 }
 
@@ -3101,15 +3099,13 @@
 
     if(handle && pageid && (env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
-        jobject tab = (jobject)DW_INT_TO_POINTER(pageid);
-
         // 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 notebookPack = env->GetMethodID(clazz, "notebookPack",
-                                                  "(Landroid/widget/RelativeLayout;Lcom/google/android/material/tabs/TabLayout/Tab;Landroid/widget/LinearLayout;)V");
+        jmethodID notebookPagePack = env->GetMethodID(clazz, "notebookPagePack",
+                                                      "(Landroid/widget/RelativeLayout;JLandroid/widget/LinearLayout;)V");
         // Call the method on the object
-        env->CallVoidMethod(_dw_obj, notebookPack, handle, tab, page);
+        env->CallVoidMethod(_dw_obj, notebookPagePack, handle, (jlong)pageid, page);
     }
 }
 
@@ -3787,7 +3783,7 @@
 
     if(timerid && (env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
     {
-        // Use a long paramater
+        // Use a long parameter
         jobject timer = (jobject)timerid;
         // First get the class that contains the method you need to call
         jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
@@ -4802,6 +4798,18 @@
  */
 void API dw_shutdown(void)
 {
+    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 dwindowsShutdown = env->GetMethodID(clazz, "dwindowsShutdown",
+                                                      "()V");
+        // Call the method on the object
+        env->CallVoidMethod(_dw_obj, dwindowsShutdown);
+    }
 }
 
 /*
@@ -4949,24 +4957,15 @@
 {
     switch(feature)
     {
-#if 0
         case DW_FEATURE_HTML:                    /* Supports the HTML Widget */
         case DW_FEATURE_HTML_RESULT:             /* Supports the DW_SIGNAL_HTML_RESULT callback */
-        case DW_FEATURE_WINDOW_BORDER:           /* Supports custom window border sizes */
-        case DW_FEATURE_WINDOW_TRANSPARENCY:     /* Supports window frame transparency */
         case DW_FEATURE_DARK_MODE:               /* Supports Dark Mode user interface */
+        case DW_FEATURE_NOTIFICATION:            /* Supports sending system notifications */
+        case DW_FEATURE_UTF8_UNICODE:            /* Supports UTF8 encoded Unicode text */
         case DW_FEATURE_MLE_AUTO_COMPLETE:       /* Supports auto completion in Multi-line Edit boxes */
         case DW_FEATURE_MLE_WORD_WRAP:           /* Supports word wrapping in Multi-line Edit boxes */
         case DW_FEATURE_CONTAINER_STRIPE:        /* Supports striped line display in container widgets */
-        case DW_FEATURE_MDI:                     /* Supports Multiple Document Interface window frame */
-        case DW_FEATURE_NOTEBOOK_STATUS_TEXT:    /* Supports status text area on notebook/tabbed controls */
-        case DW_FEATURE_NOTIFICATION:            /* Supports sending system notifications */
-        case DW_FEATURE_UTF8_UNICODE:            /* Supports UTF8 encoded Unicode text */
-        case DW_FEATURE_MLE_RICH_EDIT:           /* Supports Rich Edit based MLE control (Windows) */
-        case DW_FEATURE_TASK_BAR:                /* Supports icons in the taskbar or similar system widget */
-        case DW_FEATURE_TREE:                    .* Supports the Tree Widget */
             return DW_FEATURE_ENABLED;
-#endif
         default:
             return DW_FEATURE_UNSUPPORTED;
     }
@@ -4990,24 +4989,15 @@
     switch(feature)
     {
         /* These features are supported but not configurable */
-#if 0
         case DW_FEATURE_HTML:                    /* Supports the HTML Widget */
         case DW_FEATURE_HTML_RESULT:             /* Supports the DW_SIGNAL_HTML_RESULT callback */
-        case DW_FEATURE_WINDOW_BORDER:           /* Supports custom window border sizes */
-        case DW_FEATURE_WINDOW_TRANSPARENCY:     /* Supports window frame transparency */
         case DW_FEATURE_DARK_MODE:               /* Supports Dark Mode user interface */
+        case DW_FEATURE_NOTIFICATION:            /* Supports sending system notifications */
+        case DW_FEATURE_UTF8_UNICODE:            /* Supports UTF8 encoded Unicode text */
         case DW_FEATURE_MLE_AUTO_COMPLETE:       /* Supports auto completion in Multi-line Edit boxes */
         case DW_FEATURE_MLE_WORD_WRAP:           /* Supports word wrapping in Multi-line Edit boxes */
         case DW_FEATURE_CONTAINER_STRIPE:        /* Supports striped line display in container widgets */
-        case DW_FEATURE_MDI:                     /* Supports Multiple Document Interface window frame */
-        case DW_FEATURE_NOTEBOOK_STATUS_TEXT:    /* Supports status text area on notebook/tabbed controls */
-        case DW_FEATURE_NOTIFICATION:            /* Supports sending system notifications */
-        case DW_FEATURE_UTF8_UNICODE:            /* Supports UTF8 encoded Unicode text */
-        case DW_FEATURE_MLE_RICH_EDIT:           /* Supports Rich Edit based MLE control (Windows) */
-        case DW_FEATURE_TASK_BAR:                /* Supports icons in the taskbar or similar system widget */
-        case DW_FEATURE_TREE:                    .* Supports the Tree Widget */
             return DW_ERROR_GENERAL;
-#endif
         /* These features are supported and configurable */
         default:
             return DW_FEATURE_UNSUPPORTED;