aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorPo Lu2023-10-14 10:15:20 +0800
committerPo Lu2023-10-14 10:15:42 +0800
commit03f5a06a052ee0b4b8b77b4460ead717b87c4798 (patch)
treec047e2c53e56e6c6e20b5475a6e33fd1b25ece96 /java
parent0dd7e6e3aeac1ab0a03f2ed2ad108deecde82447 (diff)
downloademacs-03f5a06a052ee0b4b8b77b4460ead717b87c4798.tar.gz
emacs-03f5a06a052ee0b4b8b77b4460ead717b87c4798.zip
Implement multi-window drag-and-drop under Android
* java/org/gnu/emacs/EmacsNative.java (sendDndDrag, sendDndUri) (sendDndText): Declare new event-sending functions. * java/org/gnu/emacs/EmacsView.java (onDragEvent): New function. * java/org/gnu/emacs/EmacsWindow.java (onDragEvent): New function; respond to each drag and drop event, request permissions if necessary and transfer dropped data to Lisp. * lisp/dnd.el (dnd-unescape-file-uris): New variable. (dnd-get-local-file-name): If that variable is nil, refrain from unescaping URLs provided. * lisp/term/android-win.el (android-handle-dnd-event): New function. (special-event-map): Bind drag-n-drop-event. * src/android.c (sendDndDrag, sendDndUri, sendDndText): New functions. * src/androidgui.h (enum android_event_type): New event types ANDROID_DND_DRAG_EVENT, ANDROID_DND_URI_EVENT, ANDROID_DND_TEXT_EVENT. (struct android_dnd_event): New structure. (union android_event) <dnd>: New field. * src/androidterm.c (handle_one_android_event) <ANDROID_DND_..._EVENT>: Generate drag-n-drop events for each of these types. (syms_of_androidterm) <Quri, Qtext>: New defsyms.
Diffstat (limited to 'java')
-rw-r--r--java/org/gnu/emacs/EmacsNative.java11
-rw-r--r--java/org/gnu/emacs/EmacsView.java14
-rw-r--r--java/org/gnu/emacs/EmacsWindow.java138
3 files changed, 160 insertions, 3 deletions
diff --git a/java/org/gnu/emacs/EmacsNative.java b/java/org/gnu/emacs/EmacsNative.java
index d8524d92130..7d7e1e5d831 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -175,6 +175,17 @@ public final class EmacsNative
175 public static native long sendExpose (short window, int x, int y, 175 public static native long sendExpose (short window, int x, int y,
176 int width, int height); 176 int width, int height);
177 177
178 /* Send an ANDROID_DND_DRAG event. */
179 public static native long sendDndDrag (short window, int x, int y);
180
181 /* Send an ANDROID_DND_URI event. */
182 public static native long sendDndUri (short window, int x, int y,
183 String text);
184
185 /* Send an ANDROID_DND_TEXT event. */
186 public static native long sendDndText (short window, int x, int y,
187 String text);
188
178 /* Return the file name associated with the specified file 189 /* Return the file name associated with the specified file
179 descriptor, or NULL if there is none. */ 190 descriptor, or NULL if there is none. */
180 public static native byte[] getProcName (int fd); 191 public static native byte[] getProcName (int fd);
diff --git a/java/org/gnu/emacs/EmacsView.java b/java/org/gnu/emacs/EmacsView.java
index 877b1ce2429..2d53231fbf9 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -24,6 +24,7 @@ import android.content.Context;
24import android.text.InputType; 24import android.text.InputType;
25 25
26import android.view.ContextMenu; 26import android.view.ContextMenu;
27import android.view.DragEvent;
27import android.view.View; 28import android.view.View;
28import android.view.KeyEvent; 29import android.view.KeyEvent;
29import android.view.MotionEvent; 30import android.view.MotionEvent;
@@ -566,6 +567,19 @@ public final class EmacsView extends ViewGroup
566 return window.onTouchEvent (motion); 567 return window.onTouchEvent (motion);
567 } 568 }
568 569
570 @Override
571 public boolean
572 onDragEvent (DragEvent drag)
573 {
574 /* Inter-program drag and drop isn't supported under Android 23
575 and earlier. */
576
577 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
578 return false;
579
580 return window.onDragEvent (drag);
581 }
582
569 583
570 584
571 private void 585 private void
diff --git a/java/org/gnu/emacs/EmacsWindow.java b/java/org/gnu/emacs/EmacsWindow.java
index 8d444aa27f5..3d2d86624a7 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -27,6 +27,8 @@ import java.util.HashMap;
27import java.util.LinkedHashMap; 27import java.util.LinkedHashMap;
28import java.util.Map; 28import java.util.Map;
29 29
30import android.content.ClipData;
31import android.content.ClipDescription;
30import android.content.Context; 32import android.content.Context;
31 33
32import android.graphics.Rect; 34import android.graphics.Rect;
@@ -34,12 +36,15 @@ import android.graphics.Canvas;
34import android.graphics.Bitmap; 36import android.graphics.Bitmap;
35import android.graphics.PixelFormat; 37import android.graphics.PixelFormat;
36 38
37import android.view.View; 39import android.net.Uri;
38import android.view.ViewManager; 40
41import android.view.DragEvent;
39import android.view.Gravity; 42import android.view.Gravity;
43import android.view.InputDevice;
40import android.view.KeyEvent; 44import android.view.KeyEvent;
41import android.view.MotionEvent; 45import android.view.MotionEvent;
42import android.view.InputDevice; 46import android.view.View;
47import android.view.ViewManager;
43import android.view.WindowManager; 48import android.view.WindowManager;
44 49
45import android.util.Log; 50import android.util.Log;
@@ -1560,4 +1565,131 @@ public final class EmacsWindow extends EmacsHandleObject
1560 rect.width (), rect.height ()); 1565 rect.width (), rect.height ());
1561 } 1566 }
1562 } 1567 }
1568
1569
1570
1571 /* Drag and drop.
1572
1573 Android 7.0 and later permit multiple windows to be juxtaposed
1574 on-screen, consequently enabling items selected from one window
1575 to be dragged onto another. Data is transferred across program
1576 boundaries using ClipData items, much the same way clipboard data
1577 is transferred.
1578
1579 When an item is dropped, Emacs must ascertain whether the clip
1580 data represents plain text, a content URI incorporating a file,
1581 or some other data. This is implemented by examining the clip
1582 data's ``description'', which enumerates each of the MIME data
1583 types the clip data is capable of providing data in.
1584
1585 If the clip data represents plain text, then that text is copied
1586 into a string and conveyed to Lisp code. Otherwise, Emacs must
1587 solicit rights to access the URI from the system, absent which it
1588 is accounted plain text and reinterpreted as such, to cue the
1589 user that something has gone awry.
1590
1591 Moreover, events are regularly sent as the item being dragged
1592 travels across the frame, even if it might not be dropped. This
1593 facilitates cursor motion and scrolling in response, as provided
1594 by the options dnd-indicate-insertion-point and
1595 dnd-scroll-margin. */
1596
1597 /* Register the drag and drop event EVENT. */
1598
1599 public boolean
1600 onDragEvent (DragEvent event)
1601 {
1602 ClipData data;
1603 ClipDescription description;
1604 int i, x, y;
1605 String type;
1606 Uri uri;
1607 EmacsActivity activity;
1608
1609 x = (int) event.getX ();
1610 y = (int) event.getY ();
1611
1612 switch (event.getAction ())
1613 {
1614 case DragEvent.ACTION_DRAG_STARTED:
1615 /* Return true to continue the drag and drop operation. */
1616 return true;
1617
1618 case DragEvent.ACTION_DRAG_LOCATION:
1619 /* Send this drag motion event to Emacs. */
1620 EmacsNative.sendDndDrag (handle, x, y);
1621 return true;
1622
1623 case DragEvent.ACTION_DROP:
1624 /* Judge whether this is plain text, or if it's a file URI for
1625 which permissions must be requested. */
1626
1627 data = event.getClipData ();
1628 description = data.getDescription ();
1629
1630 /* If there are insufficient items within the clip data,
1631 return false. */
1632
1633 if (data.getItemCount () < 1)
1634 return false;
1635
1636 /* Search for plain text data within the clipboard. */
1637
1638 for (i = 0; i < description.getMimeTypeCount (); ++i)
1639 {
1640 type = description.getMimeType (i);
1641
1642 if (type.equals (ClipDescription.MIMETYPE_TEXT_PLAIN)
1643 || type.equals (ClipDescription.MIMETYPE_TEXT_HTML))
1644 {
1645 /* The data being dropped is plain text; encode it
1646 suitably and send it to the main thread. */
1647 type = (data.getItemAt (0).coerceToText (EmacsService.SERVICE)
1648 .toString ());
1649 EmacsNative.sendDndText (handle, x, y, type);
1650 return true;
1651 }
1652 else if (type.equals (ClipDescription.MIMETYPE_TEXT_URILIST))
1653 {
1654 /* The data being dropped is a list of URIs; encode it
1655 suitably and send it to the main thread. */
1656 type = (data.getItemAt (0).coerceToText (EmacsService.SERVICE)
1657 .toString ());
1658 EmacsNative.sendDndUri (handle, x, y, type);
1659 return true;
1660 }
1661 else
1662 {
1663 /* If the item dropped is a URI, send it to the main
1664 thread. */
1665 uri = data.getItemAt (0).getUri ();
1666
1667 /* Attempt to acquire permissions for this URI;
1668 failing which, insert it as text instead. */
1669
1670 if (uri.getScheme () != null
1671 && uri.getScheme ().equals ("content")
1672 && (activity = EmacsActivity.lastFocusedActivity) != null)
1673 {
1674 if (activity.requestDragAndDropPermissions (event) == null)
1675 uri = null;
1676 }
1677
1678 if (uri != null)
1679 EmacsNative.sendDndUri (handle, x, y, uri.toString ());
1680 else
1681 {
1682 type = (data.getItemAt (0)
1683 .coerceToText (EmacsService.SERVICE)
1684 .toString ());
1685 EmacsNative.sendDndText (handle, x, y, type);
1686 }
1687
1688 return true;
1689 }
1690 }
1691 }
1692
1693 return true;
1694 }
1563}; 1695};