changeset 2795:5c61aba17b69

Android: Change dw_file_browse() to return URIs or paths on Android. Paths will be returned if either DW_DIRECTORY_OPEN or DW_FILE_PATH flags are specified. Otherwise a URI may be returned. The double string method of returning both path and URI has been removed. DW_FILE_PATH and DW_FILE_MASK have been added, but are really only used on Android. __DW_MOBILE__ will be defined on Mobile platforms such as iOS and Android. __DW_DESKTOP__ will be defined on most other desktop operating systems.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Fri, 15 Jul 2022 11:50:09 +0000
parents 7ce51a7e8009
children 0c534743b7a9
files android/DWindows.kt android/dw.cpp dw.h
diffstat 3 files changed, 90 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/android/DWindows.kt	Fri Jul 15 08:15:11 2022 +0000
+++ b/android/DWindows.kt	Fri Jul 15 11:50:09 2022 +0000
@@ -6126,7 +6126,6 @@
     fun fileBrowseNew(title: String, defpath: String?, ext: String?, flags: Int): String?
     {
         var retval: String? = null
-        var uristr: String? = null
         var permission = Manifest.permission.WRITE_EXTERNAL_STORAGE
         var permissions: Int = -1
 
@@ -6161,57 +6160,61 @@
                 fileLock.unlock()
 
                 // Save the URI string for later use
-                uristr = fileURI.toString()
-
-                if (DocumentsContract.isDocumentUri(this, fileURI)) {
-                    // ExternalStorageProvider
-                    if (fileURI?.authority == "com.android.externalstorage.documents") {
-                        val docId = DocumentsContract.getDocumentId(fileURI)
-                        val split = docId.split(":").toTypedArray()
-                        retval = Environment.getExternalStorageDirectory().toString() + "/" + split[1]
-                    } else if (fileURI?.authority == "com.android.providers.downloads.documents") {
-                        val id = DocumentsContract.getDocumentId(fileURI)
-                        val contentUri = ContentUris.withAppendedId(
-                            Uri.parse("content://downloads/public_downloads"),
-                            java.lang.Long.valueOf(id)
-                        )
-                        retval = getDataColumn(this, contentUri, null, null)
-                    } else if (fileURI?.authority == "com.android.providers.media.documents") {
-                        val docId = DocumentsContract.getDocumentId(fileURI)
-                        val split = docId.split(":").toTypedArray()
-                        val type = split[0]
-                        var contentUri: Uri? = null
-                        if ("image" == type) {
-                            contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
-                        } else if ("video" == type) {
-                            contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
-                        } else if ("audio" == type) {
-                            contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+                retval = fileURI.toString()
+
+                // If DW_DIRECTORY_OPEN or DW_FILE_PATH ... use the path not URI
+                if((flags and 65535) == 2 || ((flags shr 16) and 1) == 1) {
+                    if (DocumentsContract.isDocumentUri(this, fileURI)) {
+                        // ExternalStorageProvider
+                        if (fileURI?.authority == "com.android.externalstorage.documents") {
+                            val docId = DocumentsContract.getDocumentId(fileURI)
+                            val split = docId.split(":").toTypedArray()
+                            retval = Environment.getExternalStorageDirectory()
+                                .toString() + "/" + split[1]
+                        } else if (fileURI?.authority == "com.android.providers.downloads.documents") {
+                            val id = DocumentsContract.getDocumentId(fileURI)
+                            val contentUri = ContentUris.withAppendedId(
+                                Uri.parse("content://downloads/public_downloads"),
+                                java.lang.Long.valueOf(id)
+                            )
+                            retval = getDataColumn(this, contentUri, null, null)
+                        } else if (fileURI?.authority == "com.android.providers.media.documents") {
+                            val docId = DocumentsContract.getDocumentId(fileURI)
+                            val split = docId.split(":").toTypedArray()
+                            val type = split[0]
+                            var contentUri: Uri? = null
+                            if ("image" == type) {
+                                contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
+                            } else if ("video" == type) {
+                                contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
+                            } else if ("audio" == type) {
+                                contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
+                            }
+                            val selection = "_id=?"
+                            val selectionArgs = arrayOf<String?>(
+                                split[1]
+                            )
+                            retval = getDataColumn(this, contentUri, selection, selectionArgs)
                         }
-                        val selection = "_id=?"
-                        val selectionArgs = arrayOf<String?>(
-                            split[1]
-                        )
-                        retval = getDataColumn(this, contentUri, selection, selectionArgs)
+                    } else if (fileURI?.scheme == "content") {
+                        retval = getDataColumn(this, fileURI, null, null)
+                    }
+                    // File
+                    else if (fileURI?.scheme == "file") {
+                        retval = fileURI?.path
                     }
-                } else if (fileURI?.scheme == "content") {
-                    retval = getDataColumn(this, fileURI, null, null)
-                }
-                // File
-                else if (fileURI?.scheme == "file") {
-                    retval = fileURI?.path
-                }
-
-                // If we are opening a directory DW_DIRECTORY_OPEN
-                if(retval != null && flags == 2) {
-                    val split = retval.split("/")
-                    val filename = split.last()
-
-                    if(filename != null) {
-                        val pathlen = retval.length
-                        val filelen = filename.length
-
-                        retval = retval.substring(0, pathlen - filelen - 1)
+
+                    // If we are opening a directory DW_DIRECTORY_OPEN
+                    if (retval != null && (flags and 65535) == 2) {
+                        val split = retval.split("/")
+                        val filename = split.last()
+
+                        if (filename != null) {
+                            val pathlen = retval.length
+                            val filelen = filename.length
+
+                            retval = retval.substring(0, pathlen - filelen - 1)
+                        }
                     }
                 }
             } else {
@@ -6220,9 +6223,6 @@
                 retval = fileBrowse(title, defpath, ext, flags)
             }
         }
-        if(retval != null && uristr != null) {
-            return retval + "\n\n" + uristr
-        }
         return retval
     }
 
--- a/android/dw.cpp	Fri Jul 15 08:15:11 2022 +0000
+++ b/android/dw.cpp	Fri Jul 15 11:50:09 2022 +0000
@@ -1281,24 +1281,7 @@
         {
             const char *str = env->GetStringUTFChars(jresult, nullptr);
             if(str)
-            {
-                size_t len = strlen(str);
-
-                // Allocate a string with an extra two bytes... so we can
-                // check for the trailing \n in dw_file_open() without a
-                // memory violation.
-                if((retval = (char *)calloc(1, len + 2)))
-                {
-                    char *tmp;
-
-                    strncpy(retval, str, len);
-                    // If we have a URI encoded, find the double \n and replace the
-                    // first \n with NULL so the string still looks like a normal path.
-                    tmp = strstr(retval, "\n\n");
-                    if (tmp)
-                        *tmp = 0;
-                }
-            }
+                retval = strdup(str);
         }
     }
     return retval;
@@ -1306,24 +1289,31 @@
 
 int API dw_file_open(const char *path, int mode)
 {
-    JNIEnv *env;
     int retval = -1;
 
-    if((env = (JNIEnv *)pthread_getspecific(_dw_env_key)))
-    {
-        // dw_file_browse saves a second string with the URI after the path
-        // So find the end of the string and check for a trailing \n
-        // The URI will be after that if found.
-        const char *uri = strchr(path, 0);
-        jstring jstr = env->NewStringUTF((uri && *(uri+1) == '\n') ? (uri+2) : path);
-        // 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 fileOpen = env->GetMethodID(clazz, "fileOpen",
-                                              "(Ljava/lang/String;I)I");
-        // Call the method on the object
-        retval = (int)env->CallIntMethod(_dw_obj, fileOpen, jstr, (jint)mode);
-        _dw_jni_check_exception(env);
+    if(path)
+    {
+        JNIEnv *env;
+
+        // If we have no URI we can use the normal open call
+        if(!strstr(path, "://"))
+            return open(path, mode);
+        // If we have a URI, use Android calls to get the URI file descriptor
+        if ((env = (JNIEnv *) pthread_getspecific(_dw_env_key)))
+        {
+            // dw_file_browse saves a second string with the URI after the path
+            // So find the end of the string and check for a trailing \n
+            // The URI will be after that if found.
+            jstring jstr = env->NewStringUTF(path);
+            // 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 fileOpen = env->GetMethodID(clazz, "fileOpen",
+                                                  "(Ljava/lang/String;I)I");
+            // Call the method on the object
+            retval = (int) env->CallIntMethod(_dw_obj, fileOpen, jstr, (jint) mode);
+            _dw_jni_check_exception(env);
+        }
     }
     return retval;
 }
--- a/dw.h	Fri Jul 15 08:15:11 2022 +0000
+++ b/dw.h	Fri Jul 15 11:50:09 2022 +0000
@@ -12,6 +12,13 @@
 #define DW_MINOR_VERSION 3
 #define DW_SUB_VERSION 0
 
+/* General application type defines */
+#if defined(__IOS__) || defined(__ANDROID__)
+#define __DW_MOBILE__ 1
+#else
+#define __DW_DESKTOP__ 1
+#endif
+
 #define DW_HOME_URL "http://dwindows.netlabs.org"
 
 /* Support for API deprecation in supported compilers */
@@ -1701,6 +1708,12 @@
 #define DW_FILE_OPEN      0
 #define DW_FILE_SAVE      1
 #define DW_DIRECTORY_OPEN 2
+#ifdef __ANDROID__
+#define DW_FILE_PATH      (1 << 16)
+#else
+#define DW_FILE_PATH      0
+#endif
+#define DW_FILE_MASK      (0x0000FFFF)
 
 #define DW_HORZ 0
 #define DW_VERT 1