aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2023-09-22 09:36:40 +0800
committerPo Lu2023-09-22 09:36:40 +0800
commitd71b9673a07da93cd7651540cd015636b8f66fda (patch)
tree50b19e900b61f71eafb0d6071d67fc0fc05221bb /java
parent9db3fbd369121ddd34e7f4febe8688d758a5dbb7 (diff)
downloademacs-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.in15
-rw-r--r--java/org/gnu/emacs/EmacsOpenActivity.java74
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 ();