changeset 2521:5f92284e2b08

Android: Implement bitmap buttons, implement dw_listbox_selected_multi(). Added a number of safety checks to prevent java exceptions.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Sun, 09 May 2021 09:31:14 +0000
parents 167af4b0004b
children 66c490aa719d
files android/DWindows.kt android/dw.cpp dwtest.c
diffstat 3 files changed, 189 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Sat May 08 23:22:52 2021 +0000
+++ b/android/DWindows.kt	Sun May 09 09:31:14 2021 +0000
@@ -1,6 +1,6 @@
 package org.dbsoft.dwindows
 
-import android.app.Activity
+import android.R.attr
 import android.content.ClipData
 import android.content.ClipboardManager
 import android.content.Context
@@ -8,6 +8,7 @@
 import android.content.pm.ActivityInfo
 import android.content.res.Configuration
 import android.graphics.Bitmap
+import android.graphics.BitmapFactory
 import android.graphics.drawable.GradientDrawable
 import android.media.AudioManager
 import android.media.ToneGenerator
@@ -21,6 +22,7 @@
 import android.text.method.PasswordTransformationMethod
 import android.util.Base64
 import android.util.Log
+import android.util.SparseBooleanArray
 import android.view.Gravity
 import android.view.MotionEvent
 import android.view.View
@@ -41,6 +43,9 @@
 import com.google.android.material.tabs.TabLayout
 import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
 import com.google.android.material.tabs.TabLayoutMediator
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileNotFoundException
 import java.util.*
 import java.util.concurrent.locks.ReentrantLock
 
@@ -102,17 +107,35 @@
             if (event.x >= v.width - (v as EditText)
                     .compoundDrawables[DRAWABLE_RIGHT].bounds.width()
             ) {
-                value += 1
+                val newvalue = this.text.toString().toLong()
+
+                if(newvalue != null) {
+                    value = newvalue + 1
+                } else {
+                    value += 1
+                }
                 if(value > maximum) {
                     value = maximum
                 }
+                if(value < minimum) {
+                    value = minimum
+                }
                 setText(value.toString())
                 eventHandlerInt(14, value.toInt(), 0, 0, 0)
                 return true
             } else if (event.x <= (v as EditText)
                     .compoundDrawables[DRAWABLE_LEFT].bounds.width()
             ) {
-                value -= 1
+                val newvalue = this.text.toString().toLong()
+
+                if(newvalue != null) {
+                    value = newvalue - 1
+                } else {
+                    value -= 1
+                }
+                if(value > maximum) {
+                    value = maximum
+                }
                 if(value < minimum) {
                     value = minimum
                 }
@@ -559,6 +582,63 @@
         return button
     }
 
+    fun bitmapButtonNew(text: String, resid: Int): ImageButton? {
+        var button: ImageButton? = null
+        waitOnUiThread {
+            button = ImageButton(this)
+            var dataArrayMap = SimpleArrayMap<String, Long>()
+
+            button!!.tag = dataArrayMap
+            button!!.id = resid
+            button!!.setImageResource(resid)
+            button!!.setOnClickListener {
+                eventHandlerSimple(button!!, 8)
+            }
+        }
+        return button
+    }
+
+    fun bitmapButtonNewFromFile(text: String, cid: Int, filename: String): ImageButton? {
+        var button: ImageButton? = null
+        waitOnUiThread {
+            button = ImageButton(this)
+            var dataArrayMap = SimpleArrayMap<String, Long>()
+
+            button!!.tag = dataArrayMap
+            button!!.id = cid
+            button!!.setOnClickListener {
+                eventHandlerSimple(button!!, 8)
+            }
+            // Try to load the image, and protect against exceptions
+            try {
+                val f = File(filename)
+                val b = BitmapFactory.decodeStream(FileInputStream(f))
+                button!!.setImageBitmap(b)
+            }
+            catch (e: FileNotFoundException)
+            {
+            }
+        }
+        return button
+    }
+
+    fun bitmapButtonNewFromData(text: String, cid: Int, data: ByteArray, length: Int): ImageButton? {
+        var button: ImageButton? = null
+        waitOnUiThread {
+            button = ImageButton(this)
+            var dataArrayMap = SimpleArrayMap<String, Long>()
+            val b = BitmapFactory.decodeByteArray(data,0, length)
+
+            button!!.tag = dataArrayMap
+            button!!.id = cid
+            button!!.setOnClickListener {
+                eventHandlerSimple(button!!, 8)
+            }
+            button!!.setImageBitmap(b)
+        }
+        return button
+    }
+
     fun entryfieldNew(text: String, cid: Int, password: Int): EditText? {
         var entryfield: EditText? = null
 
@@ -1269,12 +1349,12 @@
             if(window is DWComboBox) {
                 val combobox = window
 
-                if(index < combobox.list.count())
+                if(index > -1 && index < combobox.list.count())
                     combobox.list[index] = text
             } else if(window is DWListBox) {
                 val listbox = window
 
-                if(index < listbox.list.count())
+                if(index > -1 && index < listbox.list.count())
                     listbox.list[index] = text
             }
         }
@@ -1288,12 +1368,12 @@
             if(window is DWComboBox) {
                 val combobox = window
 
-                if(index < combobox.list.count())
+                if(index > -1 && index < combobox.list.count())
                     retval = combobox.list[index]
             } else if(window is DWListBox) {
                 val listbox = window
 
-                if(index < listbox.list.count())
+                if(index > -1 && index < listbox.list.count())
                     retval = listbox.list[index]
             }
         }
@@ -1362,7 +1442,7 @@
         }
     }
 
-    fun listSetTop(window: View, top: Int)
+    fun listBoxSetTop(window: View, top: Int)
     {
         waitOnUiThread {
             if(window is DWListBox) {
@@ -1375,6 +1455,36 @@
         }
     }
 
+    fun listBoxSelectedMulti(window: View, where: Int): Int
+    {
+        var retval: Int = -1
+
+        waitOnUiThread {
+            if(window is DWListBox) {
+                val listbox = window
+                val checked: SparseBooleanArray = listbox.getCheckedItemPositions()
+
+                // If we are starting over....
+                if(where == -1 && checked.size() > 0) {
+                    retval = checked.keyAt(0)
+                } else {
+                    // Otherwise loop until we find our current place
+                    for (i in 0 until checked.size()) {
+                        // Item position in adapter
+                        val position: Int = checked.keyAt(i)
+                        // If we are at our current point... check to see
+                        // if there is another one, and return it...
+                        // otherwise we will return -1 to indicated we are done.
+                        if (where == position && (i+1) < checked.size()) {
+                            retval = checked.keyAt(i+1)
+                        }
+                    }
+                }
+            }
+        }
+        return retval
+    }
+
     fun timerConnect(interval: Long, sigfunc: Long, data: Long): Timer
     {
         // creating timer task, timer
--- a/android/dw.cpp	Sat May 08 23:22:52 2021 +0000
+++ b/android/dw.cpp	Sun May 09 09:31:14 2021 +0000
@@ -1177,6 +1177,21 @@
  */
 HWND API dw_bitmapbutton_new(const char *text, ULONG resid)
 {
+    JNIEnv *env;
+
+    if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
+    {
+        // 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 bitmapButtonNew = env->GetMethodID(clazz, "bitmapButtonNew",
+                                                     "(Ljava/lang/String;I)Landroid/widget/ImageButton;");
+        // Call the method on the object
+        jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, bitmapButtonNew, jstr, (int)resid));
+        return result;
+    }
     return 0;
 }
 
@@ -1193,6 +1208,22 @@
  */
 HWND API dw_bitmapbutton_new_from_file(const char *text, unsigned long cid, const char *filename)
 {
+    JNIEnv *env;
+
+    if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
+    {
+        // Construct a String
+        jstring jstr = env->NewStringUTF(text);
+        jstring path = 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 bitmapButtonNewFromFile = env->GetMethodID(clazz, "bitmapButtonNewFromFile",
+                                                             "(Ljava/lang/String;ILjava/lang/String;)Landroid/widget/ImageButton;");
+        // Call the method on the object
+        jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, bitmapButtonNewFromFile, jstr, (int)cid, path));
+        return result;
+    }
     return 0;
 }
 
@@ -1209,6 +1240,26 @@
  */
 HWND API dw_bitmapbutton_new_from_data(const char *text, unsigned long cid, const char *data, int len)
 {
+    JNIEnv *env;
+
+    if(data && len > 0 && (env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
+    {
+        // Construct a String
+        jstring jstr = env->NewStringUTF(text);
+        // Construct a byte array
+        jbyteArray bytearray = env->NewByteArray(len);
+        env->SetByteArrayRegion(bytearray, 0, len, reinterpret_cast<const jbyte *>(data));
+        // 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 bitmapButtonNewFromData = env->GetMethodID(clazz, "bitmapButtonNewFromData",
+                                                             "(Ljava/lang/String;I[BI)Landroid/widget/ImageButton;");
+        // Call the method on the object
+        jobject result = env->NewWeakGlobalRef(env->CallObjectMethod(_dw_obj, bitmapButtonNewFromData, jstr, (int)cid, bytearray, len));
+        // Clean up after the array now that we are finished
+        //env->ReleaseByteArrayElements(bytearray, (jbyte *) data, 0);
+        return result;
+    }
     return 0;
 }
 
@@ -1731,10 +1782,10 @@
         // 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 listSetTop = env->GetMethodID(clazz, "listSetTop",
+        jmethodID listBoxSetTop = env->GetMethodID(clazz, "listBoxSetTop",
                                                          "(Landroid/view/View;I)V");
         // Call the method on the object
-        env->CallVoidMethod(_dw_obj, listSetTop, handle, top);
+        env->CallVoidMethod(_dw_obj, listBoxSetTop, handle, top);
     }
 }
 
@@ -1756,7 +1807,7 @@
         jclass clazz = _dw_find_class(env, DW_CLASS_NAME);
         // Get the method that you want to call
         jmethodID listOrComboBoxGetText = env->GetMethodID(clazz, "listOrComboBoxGetText",
-                                                           "(Landroid/view/View;)ILjava/lang/String;");
+                                                           "(Landroid/view/View;I)Ljava/lang/String;");
         // Call the method on the object
         jstring result = (jstring)env->CallObjectMethod(_dw_obj, listOrComboBoxGetText, handle, index);
         // Get the UTF8 string result
@@ -1829,7 +1880,20 @@
  */
 int API dw_listbox_selected_multi(HWND handle, int where)
 {
-    return DW_ERROR_UNKNOWN;
+    JNIEnv *env;
+    int retval = DW_ERROR_UNKNOWN;
+
+    if(handle && (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 listBoxSelectedMulti = env->GetMethodID(clazz, "listBoxSelectedMulti",
+                                                          "(Landroid/view/View;I)I");
+        // Call the method on the object
+        retval = env->CallIntMethod(_dw_obj, listBoxSelectedMulti, handle, where);
+    }
+    return retval;
 }
 
 /*
--- a/dwtest.c	Sat May 08 23:22:52 2021 +0000
+++ b/dwtest.c	Sun May 09 09:31:14 2021 +0000
@@ -643,9 +643,9 @@
     unsigned int idx;
     int len;
     long spvalue;
-    char buf1[100];
-    char buf2[100];
-    char buf3[500];
+    char buf1[100] = {0};
+    char buf2[100] = {0};
+    char buf3[500] = {0};
 
     idx = dw_listbox_selected(combobox1);
     dw_listbox_get_text(combobox1, idx, buf1, 99);