diff options
| author | Po Lu | 2023-09-22 09:36:40 +0800 |
|---|---|---|
| committer | Po Lu | 2023-09-22 09:36:40 +0800 |
| commit | d71b9673a07da93cd7651540cd015636b8f66fda (patch) | |
| tree | 50b19e900b61f71eafb0d6071d67fc0fc05221bb /java | |
| parent | 9db3fbd369121ddd34e7f4febe8688d758a5dbb7 (diff) | |
| download | emacs-d71b9673a07da93cd7651540cd015636b8f66fda.tar.gz emacs-d71b9673a07da93cd7651540cd015636b8f66fda.zip | |
Enable opening mailto URLs under Android
* doc/emacs/android.texi (Android Startup): Mention how mailto
URLs are treated by the emacsclient wrapper.
* java/AndroidManifest.xml.in: Register `mailto' scheme filters
for EmacsOpenActivity.
* java/org/gnu/emacs/EmacsOpenActivity.java (startEmacsClient):
Extract code that starts Emacs when it isn't already running,
and take a list of arguments rather than a single file name.
(onCreate): If the scheme is `mailto', escape the URI and call
`message-mailto'.
Diffstat (limited to 'java')
| -rw-r--r-- | java/AndroidManifest.xml.in | 15 | ||||
| -rw-r--r-- | java/org/gnu/emacs/EmacsOpenActivity.java | 74 |
2 files changed, 66 insertions, 23 deletions
diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 9044725640d..d4017a055dd 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in | |||
| @@ -122,6 +122,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. --> | |||
| 122 | <category android:name="android.intent.category.BROWSABLE"/> | 122 | <category android:name="android.intent.category.BROWSABLE"/> |
| 123 | <data android:scheme="org-protocol"/> | 123 | <data android:scheme="org-protocol"/> |
| 124 | </intent-filter> | 124 | </intent-filter> |
| 125 | |||
| 126 | <!-- And also mailto links. --> | ||
| 127 | |||
| 128 | <intent-filter> | ||
| 129 | <action android:name="android.intent.action.VIEW"/> | ||
| 130 | <category android:name="android.intent.category.DEFAULT"/> | ||
| 131 | <category android:name="android.intent.category.BROWSABLE"/> | ||
| 132 | <data android:scheme="mailto"/> | ||
| 133 | </intent-filter> | ||
| 134 | |||
| 135 | <intent-filter> | ||
| 136 | <action android:name="android.intent.action.SENDTO"/> | ||
| 137 | <data android:scheme="mailto"/> | ||
| 138 | <category android:name="android.intent.category.DEFAULT"/> | ||
| 139 | </intent-filter> | ||
| 125 | </activity> | 140 | </activity> |
| 126 | 141 | ||
| 127 | <activity android:name="org.gnu.emacs.EmacsMultitaskActivity" | 142 | <activity android:name="org.gnu.emacs.EmacsMultitaskActivity" |
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java b/java/org/gnu/emacs/EmacsOpenActivity.java index 00503b6cbcc..d27139e98bc 100644 --- a/java/org/gnu/emacs/EmacsOpenActivity.java +++ b/java/org/gnu/emacs/EmacsOpenActivity.java | |||
| @@ -342,8 +342,14 @@ public final class EmacsOpenActivity extends Activity | |||
| 342 | }); | 342 | }); |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | /* Start `emacsclient' with the provided list of ARGUMENTS, after | ||
| 346 | ARGUMENTS[0] is replaced with the name of the emacsclient binary. | ||
| 347 | |||
| 348 | Create a new thread to await its completion, subsequently | ||
| 349 | reporting any errors that arise to the user. */ | ||
| 350 | |||
| 345 | public void | 351 | public void |
| 346 | startEmacsClient (String fileName) | 352 | startEmacsClient (String[] arguments) |
| 347 | { | 353 | { |
| 348 | String libDir; | 354 | String libDir; |
| 349 | ProcessBuilder builder; | 355 | ProcessBuilder builder; |
| @@ -352,23 +358,10 @@ public final class EmacsOpenActivity extends Activity | |||
| 352 | File file; | 358 | File file; |
| 353 | Intent intent; | 359 | Intent intent; |
| 354 | 360 | ||
| 355 | /* If the Emacs service is not running, then start Emacs and make | ||
| 356 | it open this file. */ | ||
| 357 | |||
| 358 | if (EmacsService.SERVICE == null) | ||
| 359 | { | ||
| 360 | fileToOpen = fileName; | ||
| 361 | intent = new Intent (EmacsOpenActivity.this, | ||
| 362 | EmacsActivity.class); | ||
| 363 | finish (); | ||
| 364 | startActivity (intent); | ||
| 365 | return; | ||
| 366 | } | ||
| 367 | |||
| 368 | libDir = EmacsService.getLibraryDirectory (this); | 361 | libDir = EmacsService.getLibraryDirectory (this); |
| 369 | builder = new ProcessBuilder (libDir + "/libemacsclient.so", | 362 | arguments[0] = libDir + "/libemacsclient.so"; |
| 370 | fileName, "--reuse-frame", | 363 | |
| 371 | "--timeout=10", "--no-wait"); | 364 | builder = new ProcessBuilder (arguments); |
| 372 | 365 | ||
| 373 | /* Redirection is unfortunately not possible in Android 7 and | 366 | /* Redirection is unfortunately not possible in Android 7 and |
| 374 | earlier. */ | 367 | earlier. */ |
| @@ -413,7 +406,7 @@ public final class EmacsOpenActivity extends Activity | |||
| 413 | ContentResolver resolver; | 406 | ContentResolver resolver; |
| 414 | ParcelFileDescriptor fd; | 407 | ParcelFileDescriptor fd; |
| 415 | byte[] names; | 408 | byte[] names; |
| 416 | String errorBlurb; | 409 | String errorBlurb, scheme; |
| 417 | 410 | ||
| 418 | super.onCreate (savedInstanceState); | 411 | super.onCreate (savedInstanceState); |
| 419 | 412 | ||
| @@ -431,7 +424,8 @@ public final class EmacsOpenActivity extends Activity | |||
| 431 | 424 | ||
| 432 | if (action.equals ("android.intent.action.VIEW") | 425 | if (action.equals ("android.intent.action.VIEW") |
| 433 | || action.equals ("android.intent.action.EDIT") | 426 | || action.equals ("android.intent.action.EDIT") |
| 434 | || action.equals ("android.intent.action.PICK")) | 427 | || action.equals ("android.intent.action.PICK") |
| 428 | || action.equals ("android.intent.action.SENDTO")) | ||
| 435 | { | 429 | { |
| 436 | /* Obtain the URI of the action. */ | 430 | /* Obtain the URI of the action. */ |
| 437 | uri = intent.getData (); | 431 | uri = intent.getData (); |
| @@ -442,15 +436,35 @@ public final class EmacsOpenActivity extends Activity | |||
| 442 | return; | 436 | return; |
| 443 | } | 437 | } |
| 444 | 438 | ||
| 439 | scheme = uri.getScheme (); | ||
| 440 | |||
| 441 | /* If URL is a mailto URI, call `message-mailto' much the same | ||
| 442 | way emacsclient-mail.desktop does. */ | ||
| 443 | |||
| 444 | if (scheme.equals ("mailto")) | ||
| 445 | { | ||
| 446 | /* Escape the special characters $ and " before enclosing | ||
| 447 | the string within the `message-mailto' wrapper. */ | ||
| 448 | fileName = uri.toString (); | ||
| 449 | fileName.replace ("\"", "\\\"").replace ("$", "\\$"); | ||
| 450 | fileName = "(message-mailto \"" + fileName + "\")"; | ||
| 451 | |||
| 452 | /* Execute emacsclient in order to execute this code. */ | ||
| 453 | currentActivity = this; | ||
| 454 | startEmacsClient (new String[] { "--timeout=10", "--no-wait", | ||
| 455 | "--eval", fileName, }); | ||
| 456 | return; | ||
| 457 | } | ||
| 458 | |||
| 445 | /* Now, try to get the file name. */ | 459 | /* Now, try to get the file name. */ |
| 446 | 460 | ||
| 447 | if (uri.getScheme ().equals ("file")) | 461 | if (scheme.equals ("file")) |
| 448 | fileName = uri.getPath (); | 462 | fileName = uri.getPath (); |
| 449 | else | 463 | else |
| 450 | { | 464 | { |
| 451 | fileName = null; | 465 | fileName = null; |
| 452 | 466 | ||
| 453 | if (uri.getScheme ().equals ("content")) | 467 | if (scheme.equals ("content")) |
| 454 | { | 468 | { |
| 455 | /* This is one of the annoying Android ``content'' | 469 | /* This is one of the annoying Android ``content'' |
| 456 | URIs. Most of the time, there is actually an | 470 | URIs. Most of the time, there is actually an |
| @@ -501,7 +515,7 @@ public final class EmacsOpenActivity extends Activity | |||
| 501 | } | 515 | } |
| 502 | } | 516 | } |
| 503 | } | 517 | } |
| 504 | else if (uri.getScheme ().equals ("org-protocol")) | 518 | else if (scheme.equals ("org-protocol")) |
| 505 | /* URL is an org-protocol:// link, which is meant to be | 519 | /* URL is an org-protocol:// link, which is meant to be |
| 506 | directly relayed to emacsclient. */ | 520 | directly relayed to emacsclient. */ |
| 507 | fileName = uri.toString (); | 521 | fileName = uri.toString (); |
| @@ -516,11 +530,25 @@ public final class EmacsOpenActivity extends Activity | |||
| 516 | } | 530 | } |
| 517 | } | 531 | } |
| 518 | 532 | ||
| 533 | /* If the Emacs service is not running, then start Emacs and make | ||
| 534 | it open this file. */ | ||
| 535 | |||
| 536 | if (EmacsService.SERVICE == null) | ||
| 537 | { | ||
| 538 | fileToOpen = fileName; | ||
| 539 | intent = new Intent (EmacsOpenActivity.this, | ||
| 540 | EmacsActivity.class); | ||
| 541 | finish (); | ||
| 542 | startActivity (intent); | ||
| 543 | return; | ||
| 544 | } | ||
| 545 | |||
| 519 | /* And start emacsclient. Set `currentActivity' to this now. | 546 | /* And start emacsclient. Set `currentActivity' to this now. |
| 520 | Presumably, it will shortly become capable of displaying | 547 | Presumably, it will shortly become capable of displaying |
| 521 | dialogs. */ | 548 | dialogs. */ |
| 522 | currentActivity = this; | 549 | currentActivity = this; |
| 523 | startEmacsClient (fileName); | 550 | startEmacsClient (new String[] { "--timeout=10", "--no-wait", |
| 551 | "--reuse-frame", fileName, }); | ||
| 524 | } | 552 | } |
| 525 | else | 553 | else |
| 526 | finish (); | 554 | finish (); |