changeset 382:c7f1176cd2a9

android: handle Android specific content (wich `content:` scheme) in intent manager: when an Android content is received, it is dumped to a temporary file, and a friendly filename is used when possible.
author Goffi <goffi@goffi.org>
date Tue, 04 Feb 2020 20:47:17 +0100
parents eb3f622d8791
children a90f26e89a4a
files cagou/core/platform_/android.py
diffstat 1 files changed, 49 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/cagou/core/platform_/android.py	Tue Feb 04 20:47:17 2020 +0100
+++ b/cagou/core/platform_/android.py	Tue Feb 04 20:47:17 2020 +0100
@@ -24,6 +24,7 @@
 from urllib.parse import urlparse
 from pathlib import Path
 import shutil
+import mimetypes
 from jnius import autoclass, cast
 from android import activity
 from sat.core.i18n import _
@@ -48,6 +49,7 @@
 AudioMedia = autoclass('android.provider.MediaStore$Audio$Media')
 VideoMedia = autoclass('android.provider.MediaStore$Video$Media')
 
+DISPLAY_NAME = '_display_name'
 DATA = '_data'
 
 
@@ -186,19 +188,36 @@
             }
         )
 
-    def getPathFromUri(self, uri):
+    def getColDataFromUri(self, uri, col_name):
         cursor = mActivity.getContentResolver().query(uri, None, None, None, None)
         if cursor is None:
-            return uri.getPath()
-        else:
+            return None
+        try:
             cursor.moveToFirst()
-            # FIXME: using DATA is not recommended (and DATA is deprecated)
-            # we should read directly the file with
-            # ContentResolver#openFileDescriptor(Uri, String)
-            col_idx = cursor.getColumnIndex(DATA);
+            col_idx = cursor.getColumnIndex(col_name);
             if col_idx == -1:
-                return uri.getPath()
+                return None
             return cursor.getString(col_idx)
+        finally:
+            cursor.close()
+
+    def getFilenameFromUri(self, uri, media_type):
+        filename = self.getColDataFromUri(uri, DISPLAY_NAME)
+        if filename is None:
+            uri_p = Path(uri.toString())
+            filename = uri_p.name or "unnamed"
+            if not uri_p.suffix and media_type:
+                suffix = mimetypes.guess_extension(media_type, strict=False)
+                if suffix:
+                    filename = filename + suffix
+        return filename
+
+    def getPathFromUri(self, uri):
+        # FIXME: using DATA is not recommended (and DATA is deprecated)
+        # we should read directly the file with
+        # ContentResolver#openFileDescriptor(Uri, String)
+        path = self.getColDataFromUri(uri, DATA)
+        return uri.getPath() if path is None else path
 
     def on_new_intent(self, intent):
         log.debug("on_new_intent")
@@ -235,17 +254,35 @@
             text = intent.getStringExtra(Intent.EXTRA_TEXT)
             if text is not None:
                 data['text'] = text
+
             item = intent.getParcelableExtra(Intent.EXTRA_STREAM)
             if item is not None:
                 uri = cast('android.net.Uri', item)
-                data['uri'] = uri.toString()
-                path = self.getPathFromUri(uri)
-                if path is not None:
-                    data['path'] = path
+                if uri.getScheme() == 'content':
+                    # Android content, we'll dump it to a temporary file
+                    filename = self.getFilenameFromUri(uri, intent_type)
+                    filepath = self.tmp_dir / filename
+                    input_stream = mActivity.getContentResolver().openInputStream(uri)
+                    buff = bytearray(4096)
+                    with open(filepath, 'wb') as f:
+                        while True:
+                            ret = input_stream.read(buff, 0, 4096)
+                            if ret != -1:
+                                f.write(buff[:ret])
+                            else:
+                                break
+                    input_stream.close()
+                    data['path'] = path = str(filepath)
+                else:
+                    data['uri'] = uri.toString()
+                    path = self.getPathFromUri(uri)
+                    if path is not None and path not in data:
+                        data['path'] = path
             else:
                 uri = None
                 path = None
 
+
             Clock.schedule_once(lambda *args: G.host.share(intent_type, data), 0)
         else:
             text = None