diff options
| author | Po Lu | 2023-10-15 13:10:34 +0800 |
|---|---|---|
| committer | Po Lu | 2023-10-15 13:11:37 +0800 |
| commit | 93104cff532f932bcea65d02a59c916767a31645 (patch) | |
| tree | 20070ee4cb8500824fceef285bd4b104ada3748b /java | |
| parent | a3fd382f3fe803e0b61c5353e9b5bdaf4d1e564e (diff) | |
| download | emacs-93104cff532f932bcea65d02a59c916767a31645.tar.gz emacs-93104cff532f932bcea65d02a59c916767a31645.zip | |
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.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsService.java | 89 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsWindow.java | 9 |
2 files changed, 93 insertions, 5 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 | |||
| 921 | 921 | ||
| 922 | /* Content provider functions. */ | 922 | /* Content provider functions. */ |
| 923 | 923 | ||
| 924 | /* Return a ContentResolver capable of accessing as many files as | ||
| 925 | possible, namely the content resolver of the last selected | ||
| 926 | activity if available: only they posses the rights to access drag | ||
| 927 | and drop files. */ | ||
| 928 | |||
| 929 | public ContentResolver | ||
| 930 | getUsefulContentResolver () | ||
| 931 | { | ||
| 932 | EmacsActivity activity; | ||
| 933 | |||
| 934 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) | ||
| 935 | /* Since the system predates drag and drop, return this resolver | ||
| 936 | to avoid any unforseen difficulties. */ | ||
| 937 | return resolver; | ||
| 938 | |||
| 939 | activity = EmacsActivity.lastFocusedActivity; | ||
| 940 | if (activity == null) | ||
| 941 | return resolver; | ||
| 942 | |||
| 943 | return activity.getContentResolver (); | ||
| 944 | } | ||
| 945 | |||
| 946 | /* Return a context whose ContentResolver is granted access to most | ||
| 947 | files, as in `getUsefulContentResolver'. */ | ||
| 948 | |||
| 949 | public Context | ||
| 950 | getContentResolverContext () | ||
| 951 | { | ||
| 952 | EmacsActivity activity; | ||
| 953 | |||
| 954 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) | ||
| 955 | /* Since the system predates drag and drop, return this resolver | ||
| 956 | to avoid any unforseen difficulties. */ | ||
| 957 | return this; | ||
| 958 | |||
| 959 | activity = EmacsActivity.lastFocusedActivity; | ||
| 960 | if (activity == null) | ||
| 961 | return this; | ||
| 962 | |||
| 963 | return activity; | ||
| 964 | } | ||
| 965 | |||
| 924 | /* Open a content URI described by the bytes BYTES, a non-terminated | 966 | /* Open a content URI described by the bytes BYTES, a non-terminated |
| 925 | string; make it writable if WRITABLE, and readable if READABLE. | 967 | string; make it writable if WRITABLE, and readable if READABLE. |
| 926 | Truncate the file if TRUNCATE. | 968 | Truncate the file if TRUNCATE. |
| @@ -934,6 +976,9 @@ public final class EmacsService extends Service | |||
| 934 | String name, mode; | 976 | String name, mode; |
| 935 | ParcelFileDescriptor fd; | 977 | ParcelFileDescriptor fd; |
| 936 | int i; | 978 | int i; |
| 979 | ContentResolver resolver; | ||
| 980 | |||
| 981 | resolver = getUsefulContentResolver (); | ||
| 937 | 982 | ||
| 938 | /* Figure out the file access mode. */ | 983 | /* Figure out the file access mode. */ |
| 939 | 984 | ||
| @@ -978,6 +1023,7 @@ public final class EmacsService extends Service | |||
| 978 | } | 1023 | } |
| 979 | catch (Exception exception) | 1024 | catch (Exception exception) |
| 980 | { | 1025 | { |
| 1026 | exception.printStackTrace (); | ||
| 981 | return -1; | 1027 | return -1; |
| 982 | } | 1028 | } |
| 983 | } | 1029 | } |
| @@ -994,6 +1040,11 @@ public final class EmacsService extends Service | |||
| 994 | ParcelFileDescriptor fd; | 1040 | ParcelFileDescriptor fd; |
| 995 | Uri uri; | 1041 | Uri uri; |
| 996 | int rc, flags; | 1042 | int rc, flags; |
| 1043 | Context context; | ||
| 1044 | ContentResolver resolver; | ||
| 1045 | ParcelFileDescriptor descriptor; | ||
| 1046 | |||
| 1047 | context = getContentResolverContext (); | ||
| 997 | 1048 | ||
| 998 | uri = Uri.parse (name); | 1049 | uri = Uri.parse (name); |
| 999 | flags = 0; | 1050 | flags = 0; |
| @@ -1004,8 +1055,42 @@ public final class EmacsService extends Service | |||
| 1004 | if (writable) | 1055 | if (writable) |
| 1005 | flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; | 1056 | flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; |
| 1006 | 1057 | ||
| 1007 | rc = checkCallingUriPermission (uri, flags); | 1058 | rc = context.checkCallingUriPermission (uri, flags); |
| 1008 | return rc == PackageManager.PERMISSION_GRANTED; | 1059 | |
| 1060 | if (rc == PackageManager.PERMISSION_GRANTED) | ||
| 1061 | return true; | ||
| 1062 | |||
| 1063 | /* In the event checkCallingUriPermission fails and only read | ||
| 1064 | permissions are being verified, attempt to query the URI. This | ||
| 1065 | enables ascertaining whether drag and drop URIs can be | ||
| 1066 | accessed, something otherwise not provided for. */ | ||
| 1067 | |||
| 1068 | descriptor = null; | ||
| 1069 | |||
| 1070 | try | ||
| 1071 | { | ||
| 1072 | resolver = context.getContentResolver (); | ||
| 1073 | descriptor = resolver.openFileDescriptor (uri, "r"); | ||
| 1074 | return true; | ||
| 1075 | } | ||
| 1076 | catch (Exception exception) | ||
| 1077 | { | ||
| 1078 | /* Ignored. */ | ||
| 1079 | } | ||
| 1080 | finally | ||
| 1081 | { | ||
| 1082 | try | ||
| 1083 | { | ||
| 1084 | if (descriptor != null) | ||
| 1085 | descriptor.close (); | ||
| 1086 | } | ||
| 1087 | catch (IOException exception) | ||
| 1088 | { | ||
| 1089 | /* Ignored. */ | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | return false; | ||
| 1009 | } | 1094 | } |
| 1010 | 1095 | ||
| 1011 | /* Build a content file name for URI. | 1096 | /* 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 | |||
| 1601 | { | 1601 | { |
| 1602 | ClipData data; | 1602 | ClipData data; |
| 1603 | ClipDescription description; | 1603 | ClipDescription description; |
| 1604 | int i, x, y; | 1604 | int i, j, x, y, itemCount; |
| 1605 | String type; | 1605 | String type; |
| 1606 | Uri uri; | 1606 | Uri uri; |
| 1607 | EmacsActivity activity; | 1607 | EmacsActivity activity; |
| @@ -1626,11 +1626,12 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1626 | 1626 | ||
| 1627 | data = event.getClipData (); | 1627 | data = event.getClipData (); |
| 1628 | description = data.getDescription (); | 1628 | description = data.getDescription (); |
| 1629 | itemCount = data.getItemCount (); | ||
| 1629 | 1630 | ||
| 1630 | /* If there are insufficient items within the clip data, | 1631 | /* If there are insufficient items within the clip data, |
| 1631 | return false. */ | 1632 | return false. */ |
| 1632 | 1633 | ||
| 1633 | if (data.getItemCount () < 1) | 1634 | if (itemCount < 1) |
| 1634 | return false; | 1635 | return false; |
| 1635 | 1636 | ||
| 1636 | /* Search for plain text data within the clipboard. */ | 1637 | /* Search for plain text data within the clipboard. */ |
| @@ -1662,12 +1663,14 @@ public final class EmacsWindow extends EmacsHandleObject | |||
| 1662 | { | 1663 | { |
| 1663 | /* If the item dropped is a URI, send it to the main | 1664 | /* If the item dropped is a URI, send it to the main |
| 1664 | thread. */ | 1665 | thread. */ |
| 1666 | |||
| 1665 | uri = data.getItemAt (0).getUri (); | 1667 | uri = data.getItemAt (0).getUri (); |
| 1666 | 1668 | ||
| 1667 | /* Attempt to acquire permissions for this URI; | 1669 | /* Attempt to acquire permissions for this URI; |
| 1668 | failing which, insert it as text instead. */ | 1670 | failing which, insert it as text instead. */ |
| 1669 | 1671 | ||
| 1670 | if (uri.getScheme () != null | 1672 | if (uri != null |
| 1673 | && uri.getScheme () != null | ||
| 1671 | && uri.getScheme ().equals ("content") | 1674 | && uri.getScheme ().equals ("content") |
| 1672 | && (activity = EmacsActivity.lastFocusedActivity) != null) | 1675 | && (activity = EmacsActivity.lastFocusedActivity) != null) |
| 1673 | { | 1676 | { |