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
<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"/>
}
}
-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;
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.
public int itemID;
public String itemName;
public EmacsContextMenu subMenu;
- public boolean isEnabled;
+ public boolean isEnabled, isCheckable, isChecked;
@Override
public boolean
/* 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;
item.itemID = itemID;
item.itemName = itemName;
item.isEnabled = isEnabled;
+ item.isCheckable = isCheckable;
+ item.isChecked = isChecked;
menuItems.add (item);
}
/* 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);
}
}
}
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);
(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]
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");
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;
struct android_dismiss_menu_data data;
struct android_menu_subprefix *subprefix, *temp_subprefix;
struct android_menu_subprefix *subprefix_1;
+ bool checkmark;
count = SPECPDL_INDEX ();
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. */
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)
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