diff options
| -rw-r--r-- | java/org/gnu/emacs/EmacsClipboard.java | 3 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsContextMenu.java | 4 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsOpenActivity.java | 39 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsSdk11Clipboard.java | 50 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsSdk8Clipboard.java | 11 | ||||
| -rw-r--r-- | src/android.h | 16 | ||||
| -rw-r--r-- | src/androidselect.c | 216 | ||||
| -rw-r--r-- | src/androidvfs.c | 26 |
8 files changed, 251 insertions, 114 deletions
diff --git a/java/org/gnu/emacs/EmacsClipboard.java b/java/org/gnu/emacs/EmacsClipboard.java index 9db436ca1e2..f27d96129ef 100644 --- a/java/org/gnu/emacs/EmacsClipboard.java +++ b/java/org/gnu/emacs/EmacsClipboard.java | |||
| @@ -19,6 +19,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | 19 | ||
| 20 | package org.gnu.emacs; | 20 | package org.gnu.emacs; |
| 21 | 21 | ||
| 22 | import android.content.res.AssetFileDescriptor; | ||
| 22 | import android.os.Build; | 23 | import android.os.Build; |
| 23 | 24 | ||
| 24 | /* This class provides helper code for accessing the clipboard, | 25 | /* This class provides helper code for accessing the clipboard, |
| @@ -32,7 +33,7 @@ public abstract class EmacsClipboard | |||
| 32 | public abstract byte[] getClipboard (); | 33 | public abstract byte[] getClipboard (); |
| 33 | 34 | ||
| 34 | public abstract byte[][] getClipboardTargets (); | 35 | public abstract byte[][] getClipboardTargets (); |
| 35 | public abstract long[] getClipboardData (byte[] target); | 36 | public abstract AssetFileDescriptor getClipboardData (byte[] target); |
| 36 | 37 | ||
| 37 | /* Create the correct kind of clipboard for this system. */ | 38 | /* Create the correct kind of clipboard for this system. */ |
| 38 | 39 | ||
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 2bbf2a313d6..0f52d45455f 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java | |||
| @@ -108,8 +108,8 @@ public final class EmacsContextMenu | |||
| 108 | will normally confuse Emacs into thinking that the | 108 | will normally confuse Emacs into thinking that the |
| 109 | context menu has been dismissed. Wrong! | 109 | context menu has been dismissed. Wrong! |
| 110 | 110 | ||
| 111 | Setting this flag makes EmacsActivity to only handle | 111 | Setting this flag prompts EmacsActivity to only handle |
| 112 | SubMenuBuilder being closed, which always means the menu | 112 | SubMenuBuilders being closed, which always means the menu |
| 113 | has actually been dismissed. | 113 | has actually been dismissed. |
| 114 | 114 | ||
| 115 | However, these extraneous events aren't sent on devices | 115 | However, these extraneous events aren't sent on devices |
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java index 327a53bc417..cdc68aea2bf 100644 --- a/java/org/gnu/emacs/EmacsOpenActivity.java +++ b/java/org/gnu/emacs/EmacsOpenActivity.java | |||
| @@ -19,29 +19,23 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 19 | 19 | ||
| 20 | package org.gnu.emacs; | 20 | package org.gnu.emacs; |
| 21 | 21 | ||
| 22 | /* This class makes the Emacs server work reasonably on Android. | 22 | /* Opening external documents on Android. |
| 23 | 23 | ||
| 24 | There is no way to make the Unix socket publicly available on | 24 | This activity is registered as an application capable of opening text |
| 25 | Android. | 25 | files and files in several other formats that Emacs understands, and |
| 26 | assumes responsibility for deriving file names from the files | ||
| 27 | provided to `onCreate', potentially copying them to temporary | ||
| 28 | directories in the process, and invoking `emacsclient' with suitable | ||
| 29 | arguments to open the same. In this respect, it fills the role of | ||
| 30 | `etc/emacs.desktop' on XDG systems. | ||
| 26 | 31 | ||
| 27 | Instead, this activity tries to connect to the Emacs server, to | 32 | It is also registered as a handler for mailto URIs, in which capacity |
| 28 | make it open files the system asks Emacs to open, and to emulate | 33 | it constructs invocations of `emacsclient' so as to start |
| 29 | some reasonable behavior when Emacs has not yet started. | 34 | `message-mailto' with their contents and attachments, much like |
| 35 | `etc/emacs-mail.desktop'. | ||
| 30 | 36 | ||
| 31 | First, Emacs registers itself as an application that can open text | 37 | As with all other activities, it is registered in the package |
| 32 | and image files. | 38 | manifest file. */ |
| 33 | |||
| 34 | Then, when the user is asked to open a file and selects ``Emacs'' | ||
| 35 | as the application that will open the file, the system pops up a | ||
| 36 | window, this activity, and calls the `onCreate' function. | ||
| 37 | |||
| 38 | `onCreate' then tries very to find the file name of the file that | ||
| 39 | was selected, and give it to emacsclient. | ||
| 40 | |||
| 41 | If emacsclient successfully opens the file, then this activity | ||
| 42 | starts EmacsActivity (to bring it on to the screen); otherwise, it | ||
| 43 | displays the output of emacsclient or any error message that occurs | ||
| 44 | and exits. */ | ||
| 45 | 39 | ||
| 46 | import android.app.AlertDialog; | 40 | import android.app.AlertDialog; |
| 47 | import android.app.Activity; | 41 | import android.app.Activity; |
| @@ -628,11 +622,12 @@ public final class EmacsOpenActivity extends Activity | |||
| 628 | 622 | ||
| 629 | if (scheme.equals ("content") | 623 | if (scheme.equals ("content") |
| 630 | /* Retrieving the native file descriptor of a | 624 | /* Retrieving the native file descriptor of a |
| 631 | ParcelFileDescriptor requires Honeycomb, and | 625 | ParcelFileDescriptor requires Honeycomb MR1, and |
| 632 | proceeding without this capability is pointless on | 626 | proceeding without this capability is pointless on |
| 633 | systems before KitKat, since Emacs doesn't support | 627 | systems before KitKat, since Emacs doesn't support |
| 634 | opening content files on those. */ | 628 | opening content files on those. */ |
| 635 | && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) | 629 | && (Build.VERSION.SDK_INT |
| 630 | >= Build.VERSION_CODES.HONEYCOMB_MR1)) | ||
| 636 | { | 631 | { |
| 637 | /* This is one of the annoying Android ``content'' | 632 | /* This is one of the annoying Android ``content'' |
| 638 | URIs. Most of the time, there is actually an | 633 | URIs. Most of the time, there is actually an |
diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java b/java/org/gnu/emacs/EmacsSdk11Clipboard.java index 850bb6c8deb..71381b0f114 100644 --- a/java/org/gnu/emacs/EmacsSdk11Clipboard.java +++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java | |||
| @@ -207,8 +207,9 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard | |||
| 207 | /* Return the clipboard data for the given target, or NULL if it | 207 | /* Return the clipboard data for the given target, or NULL if it |
| 208 | does not exist. | 208 | does not exist. |
| 209 | 209 | ||
| 210 | Value is normally an array of three longs: the file descriptor, | 210 | Value is normally an asset file descriptor, which in turn holds |
| 211 | the start offset of the data, and its length; length may be | 211 | three important values: the file descriptor, the start offset of |
| 212 | the data, and its length; length may be | ||
| 212 | AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends | 213 | AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends |
| 213 | from that offset to the end of the file. | 214 | from that offset to the end of the file. |
| 214 | 215 | ||
| @@ -217,15 +218,13 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard | |||
| 217 | solely of a URI. */ | 218 | solely of a URI. */ |
| 218 | 219 | ||
| 219 | @Override | 220 | @Override |
| 220 | public long[] | 221 | public AssetFileDescriptor |
| 221 | getClipboardData (byte[] target) | 222 | getClipboardData (byte[] target) |
| 222 | { | 223 | { |
| 223 | ClipData data; | 224 | ClipData data; |
| 224 | String mimeType; | 225 | String mimeType; |
| 225 | int fd; | ||
| 226 | AssetFileDescriptor assetFd; | 226 | AssetFileDescriptor assetFd; |
| 227 | Uri uri; | 227 | Uri uri; |
| 228 | long[] value; | ||
| 229 | 228 | ||
| 230 | /* Decode the target given by Emacs. */ | 229 | /* Decode the target given by Emacs. */ |
| 231 | try | 230 | try |
| @@ -245,8 +244,6 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard | |||
| 245 | if (data == null || data.getItemCount () < 1) | 244 | if (data == null || data.getItemCount () < 1) |
| 246 | return null; | 245 | return null; |
| 247 | 246 | ||
| 248 | fd = -1; | ||
| 249 | |||
| 250 | try | 247 | try |
| 251 | { | 248 | { |
| 252 | uri = data.getItemAt (0).getUri (); | 249 | uri = data.getItemAt (0).getUri (); |
| @@ -257,52 +254,15 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard | |||
| 257 | /* Now open the file descriptor. */ | 254 | /* Now open the file descriptor. */ |
| 258 | assetFd = resolver.openTypedAssetFileDescriptor (uri, mimeType, | 255 | assetFd = resolver.openTypedAssetFileDescriptor (uri, mimeType, |
| 259 | null); | 256 | null); |
| 260 | 257 | return assetFd; | |
| 261 | /* Duplicate the file descriptor. */ | ||
| 262 | fd = assetFd.getParcelFileDescriptor ().getFd (); | ||
| 263 | fd = EmacsNative.dup (fd); | ||
| 264 | |||
| 265 | /* Return the relevant information. */ | ||
| 266 | value = new long[] { fd, assetFd.getStartOffset (), | ||
| 267 | assetFd.getLength (), }; | ||
| 268 | |||
| 269 | /* Close the original offset. */ | ||
| 270 | assetFd.close (); | ||
| 271 | } | 258 | } |
| 272 | catch (SecurityException e) | 259 | catch (SecurityException e) |
| 273 | { | 260 | { |
| 274 | /* Guarantee a file descriptor duplicated or detached is | ||
| 275 | ultimately closed if an error arises. */ | ||
| 276 | |||
| 277 | if (fd != -1) | ||
| 278 | EmacsNative.close (fd); | ||
| 279 | |||
| 280 | return null; | 261 | return null; |
| 281 | } | 262 | } |
| 282 | catch (FileNotFoundException e) | 263 | catch (FileNotFoundException e) |
| 283 | { | 264 | { |
| 284 | /* Guarantee a file descriptor duplicated or detached is | ||
| 285 | ultimately closed if an error arises. */ | ||
| 286 | |||
| 287 | if (fd != -1) | ||
| 288 | EmacsNative.close (fd); | ||
| 289 | |||
| 290 | return null; | 265 | return null; |
| 291 | } | 266 | } |
| 292 | catch (IOException e) | ||
| 293 | { | ||
| 294 | /* Guarantee a file descriptor duplicated or detached is | ||
| 295 | ultimately closed if an error arises. */ | ||
| 296 | |||
| 297 | if (fd != -1) | ||
| 298 | EmacsNative.close (fd); | ||
| 299 | |||
| 300 | return null; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* Don't return value if the file descriptor couldn't be | ||
| 304 | created. */ | ||
| 305 | |||
| 306 | return fd != -1 ? value : null; | ||
| 307 | } | 267 | } |
| 308 | }; | 268 | }; |
diff --git a/java/org/gnu/emacs/EmacsSdk8Clipboard.java b/java/org/gnu/emacs/EmacsSdk8Clipboard.java index 418f55c12c1..3d0504b1924 100644 --- a/java/org/gnu/emacs/EmacsSdk8Clipboard.java +++ b/java/org/gnu/emacs/EmacsSdk8Clipboard.java | |||
| @@ -25,6 +25,8 @@ package org.gnu.emacs; | |||
| 25 | import android.text.*; | 25 | import android.text.*; |
| 26 | 26 | ||
| 27 | import android.content.Context; | 27 | import android.content.Context; |
| 28 | import android.content.res.AssetFileDescriptor; | ||
| 29 | |||
| 28 | import android.util.Log; | 30 | import android.util.Log; |
| 29 | 31 | ||
| 30 | import java.io.UnsupportedEncodingException; | 32 | import java.io.UnsupportedEncodingException; |
| @@ -129,9 +131,10 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard | |||
| 129 | /* Return the clipboard data for the given target, or NULL if it | 131 | /* Return the clipboard data for the given target, or NULL if it |
| 130 | does not exist. | 132 | does not exist. |
| 131 | 133 | ||
| 132 | Value is normally an array of three longs: the file descriptor, | 134 | Value is normally an asset file descriptor, which in turn holds |
| 133 | the start offset of the data, and its length; length may be | 135 | three important values: the file descriptor, the start offset of |
| 134 | AssetFileDescriptor.UNKOWN_LENGTH, meaning that the data extends | 136 | the data, and its length; length may be |
| 137 | AssetFileDescriptor.UNKNOWN_LENGTH, meaning that the data extends | ||
| 135 | from that offset to the end of the file. | 138 | from that offset to the end of the file. |
| 136 | 139 | ||
| 137 | Do not use this function to open text targets; use `getClipboard' | 140 | Do not use this function to open text targets; use `getClipboard' |
| @@ -139,7 +142,7 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard | |||
| 139 | solely of a URI. */ | 142 | solely of a URI. */ |
| 140 | 143 | ||
| 141 | @Override | 144 | @Override |
| 142 | public long[] | 145 | public AssetFileDescriptor |
| 143 | getClipboardData (byte[] target) | 146 | getClipboardData (byte[] target) |
| 144 | { | 147 | { |
| 145 | return null; | 148 | return null; |
diff --git a/src/android.h b/src/android.h index 19adfa38087..7074ca2630c 100644 --- a/src/android.h +++ b/src/android.h | |||
| @@ -53,6 +53,22 @@ extern char *android_user_full_name (struct passwd *); | |||
| 53 | 53 | ||
| 54 | 54 | ||
| 55 | 55 | ||
| 56 | /* Structure describing the android.os.ParcelFileDescriptor class used | ||
| 57 | to wrap file descriptors sent over IPC. */ | ||
| 58 | |||
| 59 | struct android_parcel_file_descriptor_class | ||
| 60 | { | ||
| 61 | jclass class; | ||
| 62 | jmethodID close; | ||
| 63 | jmethodID get_fd; | ||
| 64 | jmethodID detach_fd; | ||
| 65 | }; | ||
| 66 | |||
| 67 | /* The ParcelFileDescriptor class. */ | ||
| 68 | extern struct android_parcel_file_descriptor_class fd_class; | ||
| 69 | |||
| 70 | extern void android_init_fd_class (JNIEnv *); | ||
| 71 | |||
| 56 | /* File I/O operations. Many of these are defined in | 72 | /* File I/O operations. Many of these are defined in |
| 57 | androidvfs.c. */ | 73 | androidvfs.c. */ |
| 58 | 74 | ||
diff --git a/src/androidselect.c b/src/androidselect.c index 2f6114d0fcb..04d04d326d9 100644 --- a/src/androidselect.c +++ b/src/androidselect.c | |||
| @@ -21,6 +21,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 21 | #include <assert.h> | 21 | #include <assert.h> |
| 22 | #include <minmax.h> | 22 | #include <minmax.h> |
| 23 | #include <unistd.h> | 23 | #include <unistd.h> |
| 24 | #include <dlfcn.h> | ||
| 24 | 25 | ||
| 25 | #include <boot-time.h> | 26 | #include <boot-time.h> |
| 26 | #include <sys/types.h> | 27 | #include <sys/types.h> |
| @@ -100,7 +101,7 @@ android_init_emacs_clipboard (void) | |||
| 100 | FIND_METHOD (get_clipboard_targets, "getClipboardTargets", | 101 | FIND_METHOD (get_clipboard_targets, "getClipboardTargets", |
| 101 | "()[[B"); | 102 | "()[[B"); |
| 102 | FIND_METHOD (get_clipboard_data, "getClipboardData", | 103 | FIND_METHOD (get_clipboard_data, "getClipboardData", |
| 103 | "([B)[J"); | 104 | "([B)Landroid/content/res/AssetFileDescriptor;"); |
| 104 | 105 | ||
| 105 | clipboard_class.make_clipboard | 106 | clipboard_class.make_clipboard |
| 106 | = (*android_java_env)->GetStaticMethodID (android_java_env, | 107 | = (*android_java_env)->GetStaticMethodID (android_java_env, |
| @@ -340,6 +341,62 @@ data type available from the clipboard. */) | |||
| 340 | return Qnil; | 341 | return Qnil; |
| 341 | } | 342 | } |
| 342 | 343 | ||
| 344 | |||
| 345 | |||
| 346 | struct android_asset_file_descriptor | ||
| 347 | { | ||
| 348 | jclass class; | ||
| 349 | jmethodID close; | ||
| 350 | jmethodID get_length; | ||
| 351 | jmethodID get_start_offset; | ||
| 352 | jmethodID get_file_descriptor; | ||
| 353 | jmethodID get_parcel_file_descriptor; | ||
| 354 | jmethodID get_fd; | ||
| 355 | }; | ||
| 356 | |||
| 357 | /* Methods associated with the AssetFileDescriptor class. */ | ||
| 358 | static struct android_asset_file_descriptor asset_fd_class; | ||
| 359 | |||
| 360 | /* Initialize virtual function IDs and class pointers in connection with | ||
| 361 | the AssetFileDescriptor class. */ | ||
| 362 | |||
| 363 | static void | ||
| 364 | android_init_asset_file_descriptor (void) | ||
| 365 | { | ||
| 366 | jclass old; | ||
| 367 | |||
| 368 | asset_fd_class.class | ||
| 369 | = (*android_java_env)->FindClass (android_java_env, | ||
| 370 | "android/content/res/" | ||
| 371 | "AssetFileDescriptor"); | ||
| 372 | eassert (asset_fd_class.class); | ||
| 373 | |||
| 374 | old = asset_fd_class.class; | ||
| 375 | asset_fd_class.class | ||
| 376 | = (jclass) (*android_java_env)->NewGlobalRef (android_java_env, | ||
| 377 | old); | ||
| 378 | ANDROID_DELETE_LOCAL_REF (old); | ||
| 379 | |||
| 380 | if (!asset_fd_class.class) | ||
| 381 | emacs_abort (); | ||
| 382 | |||
| 383 | #define FIND_METHOD(c_name, name, signature) \ | ||
| 384 | asset_fd_class.c_name \ | ||
| 385 | = (*android_java_env)->GetMethodID (android_java_env, \ | ||
| 386 | asset_fd_class.class, \ | ||
| 387 | name, signature); \ | ||
| 388 | eassert (asset_fd_class.c_name); | ||
| 389 | |||
| 390 | FIND_METHOD (close, "close", "()V"); | ||
| 391 | FIND_METHOD (get_length, "getLength", "()J"); | ||
| 392 | FIND_METHOD (get_start_offset, "getStartOffset", "()J"); | ||
| 393 | FIND_METHOD (get_file_descriptor, "getFileDescriptor", | ||
| 394 | "()Ljava/io/FileDescriptor;"); | ||
| 395 | FIND_METHOD (get_parcel_file_descriptor, "getParcelFileDescriptor", | ||
| 396 | "()Landroid/os/ParcelFileDescriptor;"); | ||
| 397 | #undef FIND_METHOD | ||
| 398 | } | ||
| 399 | |||
| 343 | /* Free the memory inside PTR, a pointer to a char pointer. */ | 400 | /* Free the memory inside PTR, a pointer to a char pointer. */ |
| 344 | 401 | ||
| 345 | static void | 402 | static void |
| @@ -348,6 +405,125 @@ android_xfree_inside (void *ptr) | |||
| 348 | xfree (*(char **) ptr); | 405 | xfree (*(char **) ptr); |
| 349 | } | 406 | } |
| 350 | 407 | ||
| 408 | /* Close the referent of, then delete, the local reference to an asset | ||
| 409 | file descriptor referenced by AFD. */ | ||
| 410 | |||
| 411 | static void | ||
| 412 | close_asset_fd (void *afd) | ||
| 413 | { | ||
| 414 | jobject *afd_1; | ||
| 415 | |||
| 416 | afd_1 = afd; | ||
| 417 | (*android_java_env)->CallVoidMethod (android_java_env, *afd_1, | ||
| 418 | asset_fd_class.close); | ||
| 419 | (*android_java_env)->ExceptionClear (android_java_env); | ||
| 420 | ANDROID_DELETE_LOCAL_REF (*afd_1); | ||
| 421 | } | ||
| 422 | |||
| 423 | /* Return the offset, file descriptor and length of the data contained | ||
| 424 | in the asset file descriptor AFD, in *FD, *OFFSET, and *LENGTH. | ||
| 425 | Value is 0 upon success, 1 otherwise. */ | ||
| 426 | |||
| 427 | static int | ||
| 428 | extract_fd_offsets (jobject afd, int *fd, jlong *offset, jlong *length) | ||
| 429 | { | ||
| 430 | jobject java_fd; | ||
| 431 | void *handle; | ||
| 432 | #if __ANDROID_API__ <= 11 | ||
| 433 | static int (*jniGetFDFromFileDescriptor) (JNIEnv *, jobject); | ||
| 434 | #endif /* __ANDROID_API__ <= 11 */ | ||
| 435 | static int (*AFileDescriptor_getFd) (JNIEnv *, jobject);; | ||
| 436 | jmethodID method; | ||
| 437 | |||
| 438 | method = asset_fd_class.get_start_offset; | ||
| 439 | *offset = (*android_java_env)->CallLongMethod (android_java_env, | ||
| 440 | afd, method); | ||
| 441 | android_exception_check (); | ||
| 442 | method = asset_fd_class.get_length; | ||
| 443 | *length = (*android_java_env)->CallLongMethod (android_java_env, | ||
| 444 | afd, method); | ||
| 445 | android_exception_check (); | ||
| 446 | |||
| 447 | #if __ANDROID_API__ <= 11 | ||
| 448 | if (android_get_current_api_level () <= 11) | ||
| 449 | { | ||
| 450 | /* Load libnativehelper and link to a private interface that is | ||
| 451 | the only means of retrieving the file descriptor from an asset | ||
| 452 | file descriptor on these systems. */ | ||
| 453 | |||
| 454 | if (!jniGetFDFromFileDescriptor) | ||
| 455 | { | ||
| 456 | handle = dlopen ("libnativehelper.so", | ||
| 457 | RTLD_LAZY | RTLD_GLOBAL); | ||
| 458 | if (!handle) | ||
| 459 | goto failure; | ||
| 460 | jniGetFdFromFileDescriptor = dlsym (handle, | ||
| 461 | "jniGetFDFromFileDescriptor"); | ||
| 462 | if (!jniGetFdFromFileDescriptor) | ||
| 463 | goto failure; | ||
| 464 | } | ||
| 465 | |||
| 466 | method = asset_fd_class.get_file_descriptor; | ||
| 467 | java_fd = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 468 | afd, method); | ||
| 469 | android_exception_check (); | ||
| 470 | *fd = (*jniGetFDFromFileDescriptor) (android_java_env, java_fd); | ||
| 471 | ANDROID_DELETE_LOCAL_REF (java_fd); | ||
| 472 | |||
| 473 | if (*fd >= 0) | ||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | else | ||
| 477 | #endif /* __ANDROID_API__ <= 11 */ | ||
| 478 | #if __ANDROID_API__ <= 30 | ||
| 479 | if (android_get_current_api_level () <= 30) | ||
| 480 | { | ||
| 481 | /* Convert this AssetFileDescriptor into a ParcelFileDescriptor, | ||
| 482 | whose getFd method will return its native file descriptor. */ | ||
| 483 | method = asset_fd_class.get_parcel_file_descriptor; | ||
| 484 | java_fd = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 485 | afd, method); | ||
| 486 | android_exception_check (); | ||
| 487 | |||
| 488 | /* Initialize fd_class if not already complete. */ | ||
| 489 | android_init_fd_class (android_java_env); | ||
| 490 | *fd = (*android_java_env)->CallIntMethod (android_java_env, | ||
| 491 | java_fd, | ||
| 492 | fd_class.get_fd); | ||
| 493 | if (*fd >= 0) | ||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | else | ||
| 497 | #endif /* __ANDROID_API__ <= 30 */ | ||
| 498 | { | ||
| 499 | /* Load libnativehelper (now a public interface) and link to | ||
| 500 | AFileDescriptor_getFd. */ | ||
| 501 | if (!AFileDescriptor_getFd) | ||
| 502 | { | ||
| 503 | handle = dlopen ("libnativehelper.so", | ||
| 504 | RTLD_LAZY | RTLD_GLOBAL); | ||
| 505 | if (!handle) | ||
| 506 | goto failure; | ||
| 507 | AFileDescriptor_getFd = dlsym (handle, "AFileDescriptor_getFd"); | ||
| 508 | if (!AFileDescriptor_getFd) | ||
| 509 | goto failure; | ||
| 510 | } | ||
| 511 | |||
| 512 | method = asset_fd_class.get_file_descriptor; | ||
| 513 | java_fd = (*android_java_env)->CallObjectMethod (android_java_env, | ||
| 514 | afd, method); | ||
| 515 | android_exception_check (); | ||
| 516 | *fd = (*AFileDescriptor_getFd) (android_java_env, java_fd); | ||
| 517 | ANDROID_DELETE_LOCAL_REF (java_fd); | ||
| 518 | |||
| 519 | if (*fd >= 0) | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | failure: | ||
| 524 | return 1; | ||
| 525 | } | ||
| 526 | |||
| 351 | DEFUN ("android-get-clipboard-data", Fandroid_get_clipboard_data, | 527 | DEFUN ("android-get-clipboard-data", Fandroid_get_clipboard_data, |
| 352 | Sandroid_get_clipboard_data, 1, 1, 0, | 528 | Sandroid_get_clipboard_data, 1, 1, 0, |
| 353 | doc: /* Return the clipboard data of the given MIME TYPE. | 529 | doc: /* Return the clipboard data of the given MIME TYPE. |
| @@ -361,12 +537,12 @@ does not have any corresponding data. In that case, use | |||
| 361 | `android-get-clipboard' instead. */) | 537 | `android-get-clipboard' instead. */) |
| 362 | (Lisp_Object type) | 538 | (Lisp_Object type) |
| 363 | { | 539 | { |
| 364 | jlongArray array; | 540 | jobject afd; |
| 365 | jbyteArray bytes; | 541 | jbyteArray bytes; |
| 366 | jmethodID method; | 542 | jmethodID method; |
| 367 | int fd; | 543 | int fd; |
| 368 | ptrdiff_t rc; | 544 | ptrdiff_t rc; |
| 369 | jlong offset, length, *longs; | 545 | jlong offset, length; |
| 370 | specpdl_ref ref; | 546 | specpdl_ref ref; |
| 371 | char *buffer, *start; | 547 | char *buffer, *start; |
| 372 | 548 | ||
| @@ -387,36 +563,25 @@ does not have any corresponding data. In that case, use | |||
| 387 | android_exception_check (); | 563 | android_exception_check (); |
| 388 | 564 | ||
| 389 | method = clipboard_class.get_clipboard_data; | 565 | method = clipboard_class.get_clipboard_data; |
| 390 | array = (*android_java_env)->CallObjectMethod (android_java_env, | 566 | afd = (*android_java_env)->CallObjectMethod (android_java_env, |
| 391 | clipboard, method, | 567 | clipboard, method, |
| 392 | bytes); | 568 | bytes); |
| 393 | android_exception_check_1 (bytes); | 569 | android_exception_check_1 (bytes); |
| 394 | ANDROID_DELETE_LOCAL_REF (bytes); | 570 | ANDROID_DELETE_LOCAL_REF (bytes); |
| 395 | 571 | ||
| 396 | if (!array) | 572 | if (!afd) |
| 397 | goto fail; | 573 | goto fail; |
| 398 | 574 | ||
| 399 | longs = (*android_java_env)->GetLongArrayElements (android_java_env, | 575 | /* Extract the file descriptor from the AssetFileDescriptor |
| 400 | array, NULL); | 576 | object. */ |
| 401 | android_exception_check_nonnull (longs, array); | 577 | ref = SPECPDL_INDEX (); |
| 402 | 578 | record_unwind_protect_ptr (close_asset_fd, &afd); | |
| 403 | /* longs[0] is the file descriptor. | ||
| 404 | longs[1] is an offset to apply to the file. | ||
| 405 | longs[2] is either -1, or the number of bytes to read from the | ||
| 406 | file. */ | ||
| 407 | fd = longs[0]; | ||
| 408 | offset = longs[1]; | ||
| 409 | length = longs[2]; | ||
| 410 | 579 | ||
| 411 | (*android_java_env)->ReleaseLongArrayElements (android_java_env, | 580 | if (extract_fd_offsets (afd, &fd, &offset, &length)) |
| 412 | array, longs, | 581 | return unbind_to (ref, Qnil); |
| 413 | JNI_ABORT); | ||
| 414 | ANDROID_DELETE_LOCAL_REF (array); | ||
| 415 | unblock_input (); | 582 | unblock_input (); |
| 416 | 583 | ||
| 417 | /* Now begin reading from longs[0]. */ | 584 | /* Now begin reading from fd. */ |
| 418 | ref = SPECPDL_INDEX (); | ||
| 419 | record_unwind_protect_int (close_file_unwind, fd); | ||
| 420 | 585 | ||
| 421 | if (length != -1) | 586 | if (length != -1) |
| 422 | { | 587 | { |
| @@ -1004,6 +1169,7 @@ init_androidselect (void) | |||
| 1004 | return; | 1169 | return; |
| 1005 | 1170 | ||
| 1006 | android_init_emacs_clipboard (); | 1171 | android_init_emacs_clipboard (); |
| 1172 | android_init_asset_file_descriptor (); | ||
| 1007 | android_init_emacs_desktop_notification (); | 1173 | android_init_emacs_desktop_notification (); |
| 1008 | 1174 | ||
| 1009 | make_clipboard = clipboard_class.make_clipboard; | 1175 | make_clipboard = clipboard_class.make_clipboard; |
diff --git a/src/androidvfs.c b/src/androidvfs.c index c4b3dba4af0..38bec7d349a 100644 --- a/src/androidvfs.c +++ b/src/androidvfs.c | |||
| @@ -290,17 +290,6 @@ struct emacs_directory_entry_class | |||
| 290 | jfieldID d_name; | 290 | jfieldID d_name; |
| 291 | }; | 291 | }; |
| 292 | 292 | ||
| 293 | /* Structure describing the android.os.ParcelFileDescriptor class used | ||
| 294 | to wrap file descriptors sent over IPC. */ | ||
| 295 | |||
| 296 | struct android_parcel_file_descriptor_class | ||
| 297 | { | ||
| 298 | jclass class; | ||
| 299 | jmethodID close; | ||
| 300 | jmethodID get_fd; | ||
| 301 | jmethodID detach_fd; | ||
| 302 | }; | ||
| 303 | |||
| 304 | /* The java.lang.String class. */ | 293 | /* The java.lang.String class. */ |
| 305 | jclass java_string_class; | 294 | jclass java_string_class; |
| 306 | 295 | ||
| @@ -313,7 +302,7 @@ static struct emacs_directory_entry_class entry_class; | |||
| 313 | 302 | ||
| 314 | /* Fields and methods associated with the ParcelFileDescriptor | 303 | /* Fields and methods associated with the ParcelFileDescriptor |
| 315 | class. */ | 304 | class. */ |
| 316 | static struct android_parcel_file_descriptor_class fd_class; | 305 | struct android_parcel_file_descriptor_class fd_class; |
| 317 | 306 | ||
| 318 | /* Global references to several exception classes. */ | 307 | /* Global references to several exception classes. */ |
| 319 | static jclass file_not_found_exception, security_exception; | 308 | static jclass file_not_found_exception, security_exception; |
| @@ -380,13 +369,18 @@ android_init_entry_class (JNIEnv *env) | |||
| 380 | } | 369 | } |
| 381 | 370 | ||
| 382 | 371 | ||
| 383 | /* Initialize `fd_class' using the given JNI environment ENV. Calling | 372 | /* Initialize `fd_class' using the given JNI environment ENV. Called on |
| 384 | this function is not necessary on Android 4.4 and earlier. */ | 373 | API 12 (Android 3.1) and later by androidselect.c and on 5.0 and |
| 374 | later in this file. */ | ||
| 385 | 375 | ||
| 386 | static void | 376 | void |
| 387 | android_init_fd_class (JNIEnv *env) | 377 | android_init_fd_class (JNIEnv *env) |
| 388 | { | 378 | { |
| 389 | jclass old; | 379 | jclass old; |
| 380 | static bool fd_class_initialized; | ||
| 381 | |||
| 382 | if (fd_class_initialized) | ||
| 383 | return; | ||
| 390 | 384 | ||
| 391 | fd_class.class | 385 | fd_class.class |
| 392 | = (*env)->FindClass (env, "android/os/ParcelFileDescriptor"); | 386 | = (*env)->FindClass (env, "android/os/ParcelFileDescriptor"); |
| @@ -409,6 +403,8 @@ android_init_fd_class (JNIEnv *env) | |||
| 409 | FIND_METHOD (get_fd, "getFd", "()I"); | 403 | FIND_METHOD (get_fd, "getFd", "()I"); |
| 410 | FIND_METHOD (detach_fd, "detachFd", "()I"); | 404 | FIND_METHOD (detach_fd, "detachFd", "()I"); |
| 411 | #undef FIND_METHOD | 405 | #undef FIND_METHOD |
| 406 | |||
| 407 | fd_class_initialized = true; | ||
| 412 | } | 408 | } |
| 413 | 409 | ||
| 414 | 410 | ||