[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 93104cff532: Correctly receive files through Android DND
From: |
Po Lu |
Subject: |
master 93104cff532: Correctly receive files through Android DND |
Date: |
Sun, 15 Oct 2023 01:11:47 -0400 (EDT) |
branch: master
commit 93104cff532f932bcea65d02a59c916767a31645
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Correctly receive files through Android DND
* java/org/gnu/emacs/EmacsService.java (getUsefulContentResolver)
(getContentResolverContext): New functions which return a
content resolver from an EmacsActivity, if at all possible.
(openContentUri, checkContentUri): Probe or open URIs through
such content resolvers. Probe URIs by opening them if merely
testing permissions fails, for DND URIs do not make
checkCallingUriPermission return true.
* java/org/gnu/emacs/EmacsWindow.java (onDragEvent): Address
potential crash.
* src/androidvfs.c (android_check_content_access): Circumvent
JNI dynamic method dispatch.
(android_authority_name): Guarantee NAME is never a directory.
---
java/org/gnu/emacs/EmacsService.java | 89 +++++++++++++++++++++++++++++++++++-
java/org/gnu/emacs/EmacsWindow.java | 9 ++--
src/androidvfs.c | 20 ++++++--
3 files changed, 109 insertions(+), 9 deletions(-)
diff --git a/java/org/gnu/emacs/EmacsService.java
b/java/org/gnu/emacs/EmacsService.java
index 6fa2ebb3fdb..1325cd85e9b 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -921,6 +921,48 @@ public final class EmacsService extends Service
/* Content provider functions. */
+ /* Return a ContentResolver capable of accessing as many files as
+ possible, namely the content resolver of the last selected
+ activity if available: only they posses the rights to access drag
+ and drop files. */
+
+ public ContentResolver
+ getUsefulContentResolver ()
+ {
+ EmacsActivity activity;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
+ /* Since the system predates drag and drop, return this resolver
+ to avoid any unforseen difficulties. */
+ return resolver;
+
+ activity = EmacsActivity.lastFocusedActivity;
+ if (activity == null)
+ return resolver;
+
+ return activity.getContentResolver ();
+ }
+
+ /* Return a context whose ContentResolver is granted access to most
+ files, as in `getUsefulContentResolver'. */
+
+ public Context
+ getContentResolverContext ()
+ {
+ EmacsActivity activity;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
+ /* Since the system predates drag and drop, return this resolver
+ to avoid any unforseen difficulties. */
+ return this;
+
+ activity = EmacsActivity.lastFocusedActivity;
+ if (activity == null)
+ return this;
+
+ return activity;
+ }
+
/* Open a content URI described by the bytes BYTES, a non-terminated
string; make it writable if WRITABLE, and readable if READABLE.
Truncate the file if TRUNCATE.
@@ -934,6 +976,9 @@ public final class EmacsService extends Service
String name, mode;
ParcelFileDescriptor fd;
int i;
+ ContentResolver resolver;
+
+ resolver = getUsefulContentResolver ();
/* Figure out the file access mode. */
@@ -978,6 +1023,7 @@ public final class EmacsService extends Service
}
catch (Exception exception)
{
+ exception.printStackTrace ();
return -1;
}
}
@@ -994,6 +1040,11 @@ public final class EmacsService extends Service
ParcelFileDescriptor fd;
Uri uri;
int rc, flags;
+ Context context;
+ ContentResolver resolver;
+ ParcelFileDescriptor descriptor;
+
+ context = getContentResolverContext ();
uri = Uri.parse (name);
flags = 0;
@@ -1004,8 +1055,42 @@ public final class EmacsService extends Service
if (writable)
flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
- rc = checkCallingUriPermission (uri, flags);
- return rc == PackageManager.PERMISSION_GRANTED;
+ rc = context.checkCallingUriPermission (uri, flags);
+
+ if (rc == PackageManager.PERMISSION_GRANTED)
+ return true;
+
+ /* In the event checkCallingUriPermission fails and only read
+ permissions are being verified, attempt to query the URI. This
+ enables ascertaining whether drag and drop URIs can be
+ accessed, something otherwise not provided for. */
+
+ descriptor = null;
+
+ try
+ {
+ resolver = context.getContentResolver ();
+ descriptor = resolver.openFileDescriptor (uri, "r");
+ return true;
+ }
+ catch (Exception exception)
+ {
+ /* Ignored. */
+ }
+ finally
+ {
+ try
+ {
+ if (descriptor != null)
+ descriptor.close ();
+ }
+ catch (IOException exception)
+ {
+ /* Ignored. */
+ }
+ }
+
+ return false;
}
/* Build a content file name for URI.
diff --git a/java/org/gnu/emacs/EmacsWindow.java
b/java/org/gnu/emacs/EmacsWindow.java
index 3d2d86624a7..386eaca8c41 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -1601,7 +1601,7 @@ public final class EmacsWindow extends EmacsHandleObject
{
ClipData data;
ClipDescription description;
- int i, x, y;
+ int i, j, x, y, itemCount;
String type;
Uri uri;
EmacsActivity activity;
@@ -1626,11 +1626,12 @@ public final class EmacsWindow extends EmacsHandleObject
data = event.getClipData ();
description = data.getDescription ();
+ itemCount = data.getItemCount ();
/* If there are insufficient items within the clip data,
return false. */
- if (data.getItemCount () < 1)
+ if (itemCount < 1)
return false;
/* Search for plain text data within the clipboard. */
@@ -1662,12 +1663,14 @@ public final class EmacsWindow extends EmacsHandleObject
{
/* If the item dropped is a URI, send it to the main
thread. */
+
uri = data.getItemAt (0).getUri ();
/* Attempt to acquire permissions for this URI;
failing which, insert it as text instead. */
- if (uri.getScheme () != null
+ if (uri != null
+ && uri.getScheme () != null
&& uri.getScheme ().equals ("content")
&& (activity = EmacsActivity.lastFocusedActivity) != null)
{
diff --git a/src/androidvfs.c b/src/androidvfs.c
index 94c5d35ed2c..f89a82cfcc6 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -2898,6 +2898,7 @@ android_check_content_access (const char *uri, int mode)
{
jobject string;
jboolean rc, read, write;
+ jmethodID method;
string = (*android_java_env)->NewStringUTF (android_java_env, uri);
android_exception_check ();
@@ -2907,11 +2908,13 @@ android_check_content_access (const char *uri, int mode)
read = (bool) (mode & R_OK || (mode == F_OK));
write = (bool) (mode & W_OK);
+ method = service_class.check_content_uri;
- rc = (*android_java_env)->CallBooleanMethod (android_java_env,
- emacs_service,
- service_class.check_content_uri,
- string, read, write);
+ rc = (*android_java_env)->CallNonvirtualBooleanMethod (android_java_env,
+ emacs_service,
+ service_class.class,
+ method, string, read,
+ write);
android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
@@ -3013,6 +3016,15 @@ android_authority_name (struct android_vnode *vnode,
char *name,
if (*name == '/')
name++, length -= 1;
+ /* If the provided URI is a directory, return NULL and set errno
+ to ENOTDIR. Content files are never directories. */
+
+ if (name[length - 1] == '/')
+ {
+ errno = ENOTDIR;
+ return NULL;
+ }
+
/* NAME must be a valid JNI string, so that it can be encoded
properly. */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 93104cff532: Correctly receive files through Android DND,
Po Lu <=