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.
This commit is contained in:
parent
5bd38905ac
commit
198b8160cf
8 changed files with 123 additions and 16 deletions
|
@ -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
|
||||
|
|
|
@ -52,6 +52,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
|
|||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.CAMERA" />
|
||||
|
||||
<!-- This is required on Android 11 or later to access /sdcard. -->
|
||||
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@"
|
||||
android:targetSdkVersion="33"/>
|
||||
|
||||
|
|
63
java/README
63
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.
|
||||
|
|
|
@ -56,7 +56,7 @@ private class Item implements MenuItem.OnMenuItemClickListener
|
|||
public int itemID;
|
||||
public String itemName;
|
||||
public EmacsContextMenu subMenu;
|
||||
public boolean isEnabled;
|
||||
public boolean isEnabled, isCheckable, isChecked;
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
|
@ -108,10 +108,15 @@ private class Item implements MenuItem.OnMenuItemClickListener
|
|||
|
||||
/* 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 @@ private class Item implements MenuItem.OnMenuItemClickListener
|
|||
item.itemID = itemID;
|
||||
item.itemName = itemName;
|
||||
item.isEnabled = isEnabled;
|
||||
item.isCheckable = isCheckable;
|
||||
item.isChecked = isChecked;
|
||||
|
||||
menuItems.add (item);
|
||||
}
|
||||
|
@ -198,6 +205,15 @@ private class Item implements MenuItem.OnMenuItemClickListener
|
|||
/* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue