From: Po Lu Date: Sat, 28 Jan 2023 08:29:22 +0000 (+0800) Subject: Update Android port X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=198b8160cfeeb178d3b2073c8d03afdafe338908;p=emacs.git Update Android port * doc/emacs/android.texi (Android File System): Describe an easier way to disable scoped storage. * java/AndroidManifest.xml.in: Add new permission to allow that. * java/README: Add more text describing Java. * java/org/gnu/emacs/EmacsContextMenu.java (Item): New fields `isCheckable' and `isChecked'. (EmacsContextMenu, addItem): New arguments. (inflateMenuItems): Set checked status as appropriate. * java/org/gnu/emacs/EmacsCopyArea.java (perform): Disallow operations where width and height are less than or equal to zero. * lisp/menu-bar.el (menu-bar-edit-menu): Make execute-extended-command available as a menu item. * src/androidmenu.c (android_init_emacs_context_menu) (android_menu_show): * src/menu.c (have_boxes): Implement menu check boxes. --- diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi index 98d7f1e1d9e..ae4080994b8 100644 --- a/doc/emacs/android.texi +++ b/doc/emacs/android.texi @@ -177,17 +177,27 @@ makes the system more secure. Unfortunately, it also means that Emacs cannot access files in those directories, despite holding the necessary permissions. Thankfully, the Open Handset Alliance's version of Android allows this restriction to be disabled on a -per-program basis; the corresponding option in the system settings -panel is: +per-program basis; on Android 10, the corresponding option in the +system settings panel is: @indentedblock System -> Developer Options -> App Compatibility Changes -> Emacs -> DEFAULT_SCOPED_STORAGE @end indentedblock - After you disable this setting and grant Emacs the ``Files and -Media'' permission, it will be able to access files under -@file{/sdcard} as usual. + And on Android 11 and later, the corresponding option in the systems +settings panel is: + +@indentedblock +System -> Apps -> Special App Access -> All files access -> Emacs +@end indentedblock + + After you disable or enable this setting as appropriate and grant +Emacs the ``Files and Media'' permission, it will be able to access +files under @file{/sdcard} as usual. + + These settings are not present on many proprietary versions of +Android. @node Android Environment @section Running Emacs under Android diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in index 527ce74c474..09e4e788e0b 100644 --- a/java/AndroidManifest.xml.in +++ b/java/AndroidManifest.xml.in @@ -52,6 +52,10 @@ along with GNU Emacs. If not, see . --> + + + + diff --git a/java/README b/java/README index 44f5a415162..3bce2556403 100644 --- a/java/README +++ b/java/README @@ -292,15 +292,15 @@ public class EmacsFrobinicator } } -Java arrays are similar to C arrays in that they can not grow. But +Java arrays are similar to C arrays in that they can not grow. But they are very much unlike C arrays in that they are always references -(as opposed to decaying into pointers in various situations), and +(as opposed to decaying into pointers in only some situations), and contain information about their length. If another function named ``frobinicate1'' takes an array as an argument, then it need not take the length of the array. -Instead, it simply iterates over the array like so: +Instead, it may simply iterate over the array like so: int i, k; @@ -339,10 +339,65 @@ struct emacs_array_container or, possibly even better, -typedef int my_array[10]; +typedef int emacs_array_container[10]; Alas, Java has no equivalent of `typedef'. +Like in C, Java string literals are delimited by double quotes. +Unlike C, however, strings are not NULL-terminated arrays of +characters, but a distinct type named ``String''. They store their +own length, characters in Java's 16-bit ``char'' type, and are capable +of holding NULL bytes. + +Instead of writing: + +wchar_t character; +extern char *s; +size_t s; + + for (/* determine n, s in a loop. */) + s += mbstowc (&character, s, n); + +or: + +const char *byte; + +for (byte = my_string; *byte; ++byte) + /* do something with *byte. */; + +or perhaps even: + +size_t length, i; +char foo; + +length = strlen (my_string); + +for (i = 0; i < length; ++i) + foo = my_string[i]; + +you write: + +char foo; +int i; + +for (i = 0; i < myString.length (); ++i) + foo = myString.charAt (0); + +Java also has stricter rules on what can be used as a truth value in a +conditional. While in C, any non-zero value is true, Java requires +that every truth value be of the boolean type ``boolean''. + +What this means is that instead of simply writing: + + if (foo || bar) + +where foo can either be 1 or 0, and bar can either be NULL or a +pointer to something, you must explicitly write: + + if (foo != 0 || bar != null) + +in Java. + JAVA NATIVE INTERFACE Java also provides an interface for C code to interface with Java. diff --git a/java/org/gnu/emacs/EmacsContextMenu.java b/java/org/gnu/emacs/EmacsContextMenu.java index 056d8fb692c..92429410d03 100644 --- a/java/org/gnu/emacs/EmacsContextMenu.java +++ b/java/org/gnu/emacs/EmacsContextMenu.java @@ -56,7 +56,7 @@ public class EmacsContextMenu public int itemID; public String itemName; public EmacsContextMenu subMenu; - public boolean isEnabled; + public boolean isEnabled, isCheckable, isChecked; @Override public boolean @@ -108,10 +108,15 @@ public class EmacsContextMenu /* Add a normal menu item to the context menu with the id ITEMID and the name ITEMNAME. Enable it if ISENABLED, else keep it - disabled. */ + disabled. + + If this is not a submenu and ISCHECKABLE is set, make the item + checkable. Likewise, if ISCHECKED is set, make the item + checked. */ public void - addItem (int itemID, String itemName, boolean isEnabled) + addItem (int itemID, String itemName, boolean isEnabled, + boolean isCheckable, boolean isChecked) { Item item; @@ -119,6 +124,8 @@ public class EmacsContextMenu item.itemID = itemID; item.itemName = itemName; item.isEnabled = isEnabled; + item.isCheckable = isCheckable; + item.isChecked = isChecked; menuItems.add (item); } @@ -198,6 +205,15 @@ public class EmacsContextMenu /* If the item ID is zero, then disable the item. */ if (item.itemID == 0 || !item.isEnabled) menuItem.setEnabled (false); + + /* Now make the menu item display a checkmark as + appropriate. */ + + if (item.isCheckable) + menuItem.setCheckable (true); + + if (item.isChecked) + menuItem.setChecked (true); } } } diff --git a/java/org/gnu/emacs/EmacsCopyArea.java b/java/org/gnu/emacs/EmacsCopyArea.java index 7a97d706794..f8974e17c2e 100644 --- a/java/org/gnu/emacs/EmacsCopyArea.java +++ b/java/org/gnu/emacs/EmacsCopyArea.java @@ -99,6 +99,12 @@ public class EmacsCopyArea if (src_y + height > srcBitmap.getHeight ()) height = srcBitmap.getHeight () - src_y; + /* If width and height are empty or negative, then skip the entire + CopyArea operation lest createBitmap throw an exception. */ + + if (width <= 0 || height <= 0) + return; + rect = new Rect (dest_x, dest_y, dest_x + width, dest_y + height); diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index d020cf6e90a..2d907fb3827 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -472,6 +472,11 @@ (defvar menu-bar-edit-menu (let ((menu (make-sparse-keymap "Edit"))) + (bindings--define-key menu [execute-extended-command] + '(menu-item "Execute Command" execute-extended-command + :enable t + :help "Read a command name, its arguments, then call it.")) + ;; ns-win.el said: Add spell for platform consistency. (if (featurep 'ns) (bindings--define-key menu [spell] diff --git a/src/androidmenu.c b/src/androidmenu.c index 7b27825ad60..acad775f26a 100644 --- a/src/androidmenu.c +++ b/src/androidmenu.c @@ -98,7 +98,7 @@ android_init_emacs_context_menu (void) FIND_METHOD_STATIC (create_context_menu, "createContextMenu", "(Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;"); - FIND_METHOD (add_item, "addItem", "(ILjava/lang/String;Z)V"); + FIND_METHOD (add_item, "addItem", "(ILjava/lang/String;ZZZ)V"); FIND_METHOD (add_submenu, "addSubmenu", "(Ljava/lang/String;" "Ljava/lang/String;)Lorg/gnu/emacs/EmacsContextMenu;"); FIND_METHOD (add_pane, "addPane", "(Ljava/lang/String;)V"); @@ -241,7 +241,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, Lisp_Object pane_name, prefix; const char *pane_string; specpdl_ref count, count1; - Lisp_Object item_name, enable, def, tem, entry; + Lisp_Object item_name, enable, def, tem, entry, type, selected; jmethodID method; jobject store; bool rc; @@ -250,6 +250,7 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, struct android_dismiss_menu_data data; struct android_menu_subprefix *subprefix, *temp_subprefix; struct android_menu_subprefix *subprefix_1; + bool checkmark; count = SPECPDL_INDEX (); @@ -351,6 +352,8 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, item_name = AREF (menu_items, i + MENU_ITEMS_ITEM_NAME); enable = AREF (menu_items, i + MENU_ITEMS_ITEM_ENABLE); def = AREF (menu_items, i + MENU_ITEMS_ITEM_DEFINITION); + type = AREF (menu_items, i + MENU_ITEMS_ITEM_TYPE); + selected = AREF (menu_items, i + MENU_ITEMS_ITEM_SELECTED); /* This is an actual menu item (or submenu). Add it to the menu. */ @@ -392,12 +395,20 @@ android_menu_show (struct frame *f, int x, int y, int menuflags, title_string = (!NILP (item_name) ? android_build_string (item_name) : NULL); + + /* Determine whether or not to display a check box. */ + + checkmark = (EQ (type, QCtoggle) + || EQ (type, QCradio)); + (*android_java_env)->CallVoidMethod (android_java_env, current_context_menu, menu_class.add_item, (jint) item_id, title_string, - (jboolean) !NILP (enable)); + (jboolean) !NILP (enable), + (jboolean) checkmark, + (jboolean) !NILP (selected)); android_exception_check (); if (title_string) diff --git a/src/menu.c b/src/menu.c index e02ee880119..6ab34a16996 100644 --- a/src/menu.c +++ b/src/menu.c @@ -48,7 +48,7 @@ static bool have_boxes (void) { #if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NTGUI) || defined (HAVE_NS) \ - || defined (HAVE_HAIKU) + || defined (HAVE_HAIKU) || defined (HAVE_ANDROID) if (FRAME_WINDOW_P (XFRAME (Vmenu_updating_frame))) return 1; #endif