1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-01 08:17:38 +00:00

Update Android port

* doc/emacs/android.texi (Android Startup, Android File System)
(Android Environment, Android Windowing, Android
Troubleshooting): Improve documentation; fix typos.
* doc/lispref/commands.texi (Misc Events): Likewise.
* java/org/gnu/emacs/EmacsService.java (queryBattery): New
function.
* lisp/battery.el (battery-status-function): Set appropriately
for Android.
(battery-android): New function.
* src/android.c (struct android_emacs_service): New method
`query_battery'.
(android_check_content_access): Improve exception checking.
(android_init_emacs_service): Look up new method.
(android_destroy_handle, android_create_window)
(android_init_android_rect_class, android_init_emacs_gc_class)
(android_set_clip_rectangles)
(android_create_pixmap_from_bitmap_data, android_fill_polygon)
(android_get_image, android_put_image, android_bell)
(android_set_input_focus, android_raise_window)
(android_lower_window, android_query_tree, android_get_geometry)
(android_translate_coordinates, android_wc_lookup_string)
(android_damage_window, android_build_string)
(android_build_jstring, android_exception_check_1)
(android_exception_check_2): New functions.
(android_browse_url): Improve exception handling.  Always use
android_exception_check and don't leak local refs.
(android_query_battery): New function.
* src/android.h (struct android_battery_state): New struct.
* src/androidfns.c (Fandroid_query_battery, syms_of_androidfns):
New function.
* src/androidfont.c (androidfont_from_lisp, DO_SYMBOL_FIELD)
(DO_CARDINAL_FIELD, androidfont_list, androidfont_match)
(androidfont_draw, androidfont_open_font)
(androidfont_close_font):
* src/androidselect.c (Fandroid_set_clipboard)
(Fandroid_get_clipboard):
* src/sfnt.c (sfnt_map_glyf_table):
* src/sfntfont.c (sfntfont_free_outline_cache)
(sfntfont_free_raster_cache, sfntfont_close): Allow font close
functions to be called twice.
This commit is contained in:
Po Lu 2023-02-25 19:11:07 +08:00
parent d5cccfdc56
commit 8e4c5db193
11 changed files with 414 additions and 166 deletions

View File

@ -93,6 +93,10 @@ Enable ``developer options'' on your device, by going to the ``About''
page in the system settings application and clicking on the ``build
version'' or ``kernel version'' items five to seven times.
@item
Open the ``developer options'' settings page, which should be under
the ``system'' page in the settings application.
@item
Turn on the switch ``USB debugging''.
@ -194,8 +198,10 @@ when the user grants the ``Files and Media'' permission to Emacs via
system settings.
@end itemize
The external storage directory is found at @file{/sdcard}; the other
directories are not found at any fixed location.
The external storage directory is found at @file{/sdcard}. The
other directories are not found at any fixed location, although the
app data directory is typically symlinked to
@file{/data/data/org.gnu.emacs}.
@cindex file system limitations, Android 11
On Android 11 and later, the Android system restricts applications
@ -242,7 +248,7 @@ they are packaged as libraries in the library directory, because
otherwise the system will not unpack them while Emacs is being
installed. This means, instead of specifying @code{ctags} or
@code{emacsclient} in a subprocess, Lisp code must specify
@code{libctags.so} or @code{libemacsclient.so} on the commnd line
@code{libctags.so} or @code{libemacsclient.so} on the command line
instead when starting either of those programs in a subprocess.
The @file{/assets} directory containing Emacs start-up files is
@ -274,7 +280,7 @@ unless the device is under memory stress.
such special treatment. However, Emacs applies a workaround: the
system considers applications that create a permanent notification to
be performing active work, and will avoid killing such applications.
Thus, on those systems, Emacs displays a permanant notification for as
Thus, on those systems, Emacs displays a permanent notification for as
long as it is running. Once the notification is displayed, it can be
safely hidden through the system settings without resulting in Emacs
being killed.
@ -393,8 +399,9 @@ tiled on the screen at any time.
are created. Instead, the system may choose to terminate windows that
are not on screen in order to save memory, with the assumption that
the program will save its contents to disk and restore them later,
when the user asks to open it again. As this is obviously not
possible with Emacs, Emacs separates a frame from a system window.
when the user asks for it to be opened again. As this is obviously
not possible with Emacs, Emacs separates the resources associated with
a frame from its system window.
Each system window created (including the initial window created
during Emacs startup) is appended to a list of windows that do not
@ -537,7 +544,7 @@ Emacs.
The next time that same copy of Emacs starts up, it simply loads the
data contained in that dump file, greatly improving start up time.
If by some unforseen circumstance the dump file is corrupted, Emacs
If by some unforeseen circumstance the dump file is corrupted, Emacs
can crash. If that happens, the dump file stored in the Emacs files
directory can be erased through the same preferences screen.

View File

@ -2221,7 +2221,7 @@ been made to them, use the variable
form:
@indentedblock
@w{@code{(@var{buffer} @var{beg} @var{end} @var{ephemeral})}}
@w{@code{((@var{buffer} @var{beg} @var{end} @var{ephemeral}) ...)}}
@end indentedblock
Where @var{ephemeral} is the buffer which was modified,

View File

@ -54,9 +54,9 @@
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Looper;
import android.os.IBinder;
@ -762,4 +762,59 @@ invocation of app_process (through android-emacs) can
return false;
}
}
/* Return the status of the battery. See struct
android_battery_status for the order of the elements
returned.
Value may be null upon failure. */
public long[]
queryBattery ()
{
Object tem;
BatteryManager manager;
long capacity, chargeCounter, currentAvg, currentNow;
long status, remaining;
int prop;
/* Android 4.4 or earlier require applications to listen to
changes to the battery instead of querying for its status. */
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return null;
tem = getSystemService (Context.BATTERY_SERVICE);
manager = (BatteryManager) tem;
remaining = -1;
prop = BatteryManager.BATTERY_PROPERTY_CAPACITY;
capacity = manager.getLongProperty (prop);
prop = BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER;
chargeCounter = manager.getLongProperty (prop);
prop = BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE;
currentAvg = manager.getLongProperty (prop);
prop = BatteryManager.BATTERY_PROPERTY_CURRENT_NOW;
currentNow = manager.getLongProperty (prop);
/* Return the battery status. N.B. that Android 7.1 and earlier
only return ``charging'' or ``discharging''. */
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
status = manager.getIntProperty (BatteryManager.BATTERY_PROPERTY_STATUS);
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
status = (manager.isCharging ()
? BatteryManager.BATTERY_STATUS_CHARGING
: BatteryManager.BATTERY_STATUS_DISCHARGING);
else
status = (currentNow > 0
? BatteryManager.BATTERY_STATUS_CHARGING
: BatteryManager.BATTERY_STATUS_DISCHARGING);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
remaining = manager.computeChargeTimeRemaining ();
return new long[] { capacity, chargeCounter, currentAvg,
currentNow, remaining, status, };
}
};

View File

@ -29,9 +29,11 @@
;; - The `/sys/class/power_supply/' files of Linux >= 2.6.39.
;; - The `/proc/acpi/' directory structure of Linux 2.4.20 and 2.6.
;; - The `/proc/apm' file format of Linux version 1.3.58 or newer.
;; - The Haiku ACPI battery driver.
;; - BSD by using the `apm' program.
;; - Darwin (macOS) by using the `pmset' program.
;; - Windows via the GetSystemPowerStatus API call.
;; - Android 5 or later via the BatteryManager APIs.
;;; Code:
@ -95,17 +97,22 @@ Value does not include \".\" or \"..\"."
(defcustom battery-status-function
(cond ((member battery-upower-service (dbus-list-activatable-names))
#'battery-upower)
((and (eq system-type 'gnu/linux)
;; Try to find the relevant devices in /sys and /proc on
;; Android as well, in case the system makes them available.
((and (memq system-type '(gnu/linux android))
(file-readable-p "/sys/")
(battery--find-linux-sysfs-batteries))
#'battery-linux-sysfs)
((and (eq system-type 'gnu/linux)
((and (memq system-type '(gnu/linux android))
(file-directory-p "/proc/acpi/battery"))
#'battery-linux-proc-acpi)
((and (eq system-type 'gnu/linux)
((and (memq system-type '(gnu/linux android))
(file-readable-p "/proc/")
(file-readable-p "/proc/apm"))
#'battery-linux-proc-apm)
;; Now try the Android battery status function.
((eq system-type 'android)
#'battery-android)
((and (eq system-type 'berkeley-unix)
(file-executable-p "/usr/sbin/apm"))
#'battery-bsd-apm)
@ -1071,6 +1078,69 @@ The following %-sequences are provided:
(cons ?m (or minutes "N/A"))
(cons ?t (or remaining-time "N/A")))))
;;; `BatteryManager' interface for Android.
(declare-function android-query-battery "androidfns.c")
(defun battery-android ()
"Get battery status information using Android.
The following %-sequences are provided:
%c Current capacity (mAh)
%r Current rate of charge or discharge (mA)
%B Battery status (verbose)
%b Battery status, empty means high, `-' means low,
`+' means charging and `?' means unknown.
%p Battery load percentage.
%m Remaining time (to charge) in minutes.
%h Remaining time (to charge) in hours.
%t Remaining time (to charge) in the form `h:min'."
(when-let* ((status (android-query-battery)))
(let* ((percentage nil)
(capacity nil)
(sym-status nil)
(symbol nil)
(rate nil)
(remaining nil)
(hours nil)
(minutes nil))
;; Figure out the percentage.
(setq percentage (number-to-string (car status)))
;; Figure out the capacity
(setq capacity (number-to-string (/ (cadr status) 1000)))
;; Figure out the battery status.
(let ((percentage (car status)))
(cl-ecase (nth 4 status)
(2 (setq sym-status "charging" symbol "+"))
(3 (setq sym-status "discharging"
symbol (if (< percentage 15) "-" " ")))
(5 (setq sym-status "full" symbol " "))
(4 (setq sym-status "not charging"
symbol (if (< percentage 15) "-" " ")))
(1 (setq sym-status "unknown" symbol "?"))))
;; Figure out the rate of charge.
(setq rate (/ (nth 3 status) 1000))
;; Figure out the remaining time.
(let* ((time (nth 5 status))
(mins (/ time (* 1000 60)))
(hours-left (/ mins 60))
(mins (mod mins 60)))
(unless (eq time -1)
(setq remaining (format "%d:%d" hours-left mins)
hours (number-to-string hours-left)
minutes (number-to-string mins))))
;; Return results.
(list (cons ?c capacity)
(cons ?p percentage)
(cons ?r rate)
(cons ?B sym-status)
(cons ?b symbol)
(cons ?m (or minutes "N/A"))
(cons ?h (or hours "N/A"))
(cons ?t (or remaining "N/A"))
(cons ?L "N/A")))))
;;; Private functions.

View File

@ -111,6 +111,7 @@ struct android_emacs_service
jmethodID reset_ic;
jmethodID open_content_uri;
jmethodID check_content_uri;
jmethodID query_battery;
};
struct android_emacs_pixmap
@ -1050,7 +1051,7 @@ android_check_content_access (const char *filename, int mode)
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
android_exception_check ();
android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
@ -1998,6 +1999,7 @@ android_init_emacs_service (void)
"([BZZZ)I");
FIND_METHOD (check_content_uri, "checkContentUri",
"([BZZ)Z");
FIND_METHOD (query_battery, "queryBattery", "()[J");
#undef FIND_METHOD
}
@ -2691,11 +2693,8 @@ android_destroy_handle (android_handle handle)
class
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
(jobject) class);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (old);
ANDROID_DELETE_LOCAL_REF (old);
if (!class)
memory_full (0);
}
(*android_java_env)->CallVoidMethod (android_java_env,
@ -2818,11 +2817,8 @@ android_create_window (android_window parent, int x, int y,
old = class;
class = (*android_java_env)->NewGlobalRef (android_java_env, class);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (old);
ANDROID_DELETE_LOCAL_REF (old);
if (!class)
memory_full (0);
}
/* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
@ -2904,11 +2900,8 @@ android_init_android_rect_class (void)
android_rect_class
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
(jobject) android_rect_class);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (old);
ANDROID_DELETE_LOCAL_REF (old);
if (!android_rect_class)
memory_full (0);
}
static void
@ -2941,10 +2934,8 @@ android_init_emacs_gc_class (void)
emacs_gc_class
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
(jobject) emacs_gc_class);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (old);
ANDROID_DELETE_LOCAL_REF (old);
if (!emacs_gc_class)
memory_full (0);
emacs_gc_foreground
= (*android_java_env)->GetFieldID (android_java_env,
@ -3188,12 +3179,7 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
n_clip_rects,
android_rect_class,
NULL);
if (!array)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
for (i = 0; i < n_clip_rects; ++i)
{
@ -3207,12 +3193,10 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
(jint) (clip_rects[i].y
+ clip_rects[i].height));
if (!rect)
{
(*android_java_env)->ExceptionClear (android_java_env);
ANDROID_DELETE_LOCAL_REF (array);
memory_full (0);
}
/* The meaning of this call is to check whether or not an
allocation error happened, and to delete ARRAY and signal an
out-of-memory error if that is the case. */
android_exception_check_1 (array);
(*android_java_env)->SetObjectArrayElement (android_java_env,
array, i, rect);
@ -3511,12 +3495,7 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width,
/* Create the color array holding the data. */
colors = (*android_java_env)->NewIntArray (android_java_env,
width * height);
if (!colors)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
SAFE_NALLOCA (region, sizeof *region, width);
@ -3666,12 +3645,7 @@ android_fill_polygon (android_drawable drawable, struct android_gc *gc,
npoints,
point_class.class,
NULL);
if (!array)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
for (i = 0; i < npoints; ++i)
{
@ -3680,13 +3654,7 @@ android_fill_polygon (android_drawable drawable, struct android_gc *gc,
point_class.constructor,
(jint) points[i].x,
(jint) points[i].y);
if (!point)
{
(*android_java_env)->ExceptionClear (android_java_env);
ANDROID_DELETE_LOCAL_REF (array);
memory_full (0);
}
android_exception_check_1 (array);
(*android_java_env)->SetObjectArrayElement (android_java_env,
array, i, point);
@ -3978,12 +3946,9 @@ android_get_image (android_drawable handle,
bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
drawable,
drawable_class.get_bitmap);
if (!bitmap)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* Clear the bitmap info structure. */
memset (&bitmap_info, 0, sizeof bitmap_info);
/* The NDK doc seems to imply this function can fail but doesn't say
@ -4115,12 +4080,9 @@ android_put_image (android_pixmap handle, struct android_image *image)
bitmap = (*android_java_env)->CallObjectMethod (android_java_env,
drawable,
drawable_class.get_bitmap);
if (!bitmap)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* Clear the bitmap info structure. */
memset (&bitmap_info, 0, sizeof bitmap_info);
/* The NDK doc seems to imply this function can fail but doesn't say
@ -4196,6 +4158,7 @@ android_bell (void)
(*android_java_env)->CallVoidMethod (android_java_env,
emacs_service,
service_class.ring_bell);
android_exception_check ();
}
void
@ -4210,6 +4173,7 @@ android_set_input_focus (android_window handle, unsigned long time)
(*android_java_env)->CallVoidMethod (android_java_env, window,
make_input_focus, (jlong) time);
android_exception_check ();
}
void
@ -4224,6 +4188,7 @@ android_raise_window (android_window handle)
(*android_java_env)->CallVoidMethod (android_java_env, window,
raise);
android_exception_check ();
}
void
@ -4238,6 +4203,7 @@ android_lower_window (android_window handle)
(*android_java_env)->CallVoidMethod (android_java_env, window,
lower);
android_exception_check ();
}
int
@ -4259,11 +4225,7 @@ android_query_tree (android_window handle, android_window *root_return,
emacs_service,
service_class.query_tree,
window);
if (!array)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* The first element of the array is the parent window. The rest
are the children. */
@ -4315,11 +4277,7 @@ android_get_geometry (android_window handle,
= (*android_java_env)->CallObjectMethod (android_java_env,
window,
get_geometry);
if (!window_geometry)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* window_geometry is an array containing x, y, width and
height. border_width is always 0 on Android. */
@ -4380,12 +4338,7 @@ android_translate_coordinates (android_window src, int x,
= (*android_java_env)->CallObjectMethod (android_java_env,
window, method,
(jint) x, (jint) y);
if (!coordinates)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* The array must contain two elements: X, Y translated to the root
window. */
@ -4396,6 +4349,8 @@ android_translate_coordinates (android_window src, int x,
/* Obtain the coordinates from the array. */
ints = (*android_java_env)->GetIntArrayElements (android_java_env,
coordinates, NULL);
android_exception_check_1 (coordinates);
*root_x = ints[0];
*root_y = ints[1];
@ -4492,7 +4447,7 @@ android_wc_lookup_string (android_key_pressed_event *event,
/* Now return this input method string. */
characters = (*android_java_env)->GetStringChars (android_java_env,
string, NULL);
android_exception_check ();
android_exception_check_1 (string);
/* Figure out how big the string is. */
size = (*android_java_env)->GetStringLength (android_java_env,
@ -4517,7 +4472,6 @@ android_wc_lookup_string (android_key_pressed_event *event,
(*android_java_env)->ReleaseStringChars (android_java_env, string,
characters);
android_exception_check ();
ANDROID_DELETE_LOCAL_REF (string);
}
}
@ -4604,17 +4558,14 @@ android_damage_window (android_drawable handle,
+ damage->width),
(jint) (damage->y
+ damage->height));
if (!rect)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
/* Post the damage to the drawable. */
(*android_java_env)->CallVoidMethod (android_java_env,
drawable,
drawable_class.damage_rect,
rect);
android_exception_check_1 (rect);
ANDROID_DELETE_LOCAL_REF (rect);
}
@ -5114,11 +5065,7 @@ android_build_string (Lisp_Object text)
not really of consequence. */
string = (*android_java_env)->NewStringUTF (android_java_env,
SSDATA (encoded));
if (!string)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
return string;
}
@ -5132,15 +5079,45 @@ android_build_jstring (const char *text)
string = (*android_java_env)->NewStringUTF (android_java_env,
text);
if (!string)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
return string;
}
/* Exception checking functions. Most JNI functions which allocate
memory return NULL upon failure; they also set the JNI
environment's pending exception to an OutOfMemoryError.
These functions check for such errors and call memory_full wherever
appropriate. Three variants are provided: one which releases no
local references, one which releases a single local reference
before calling memory_full, and one which releases two local
references.
Typically, you use these functions by calling them immediately
after a JNI function which allocates memory, passing it any local
references that are already valid but are not used after leaving
the current scope. For example, to allocate foo and then make
global_foo its global reference, and then release foo, you write:
jobject foo, global_foo;
foo = (*android_java_env)->New...;
android_exception_check ();
global_foo = (*android_java_env)->NewGlobalRef (..., foo);
android_exception_check_1 (foo);
ANDROID_DELETE_LOCAL_REF (foo);
where the first android_exception_check ensures that foo has been
allocated correctly, while the call to android_exception_check_1,
and the call to ANDROID_DELETE_LOCAL_REF afterwards, together
ensure the same of global_foo, and also that foo is released both
if global_foo cannot be allocated, and after the global reference
is created. */
/* Check for JNI exceptions and call memory_full in that
situation. */
@ -5159,6 +5136,47 @@ android_exception_check (void)
}
}
/* Check for JNI exceptions. If there is one such exception, clear
it, then delete the local reference to OBJECT and call
memory_full. */
void
android_exception_check_1 (jobject object)
{
if ((*android_java_env)->ExceptionCheck (android_java_env))
{
__android_log_print (ANDROID_LOG_WARN, __func__,
"Possible out of memory error."
" The Java exception follows: ");
/* Describe exactly what went wrong. */
(*android_java_env)->ExceptionDescribe (android_java_env);
(*android_java_env)->ExceptionClear (android_java_env);
ANDROID_DELETE_LOCAL_REF (object);
memory_full (0);
}
}
/* Like android_exception_check_one, except it takes more than one
local reference argument. */
void
android_exception_check_2 (jobject object, jobject object1)
{
if ((*android_java_env)->ExceptionCheck (android_java_env))
{
__android_log_print (ANDROID_LOG_WARN, __func__,
"Possible out of memory error."
" The Java exception follows: ");
/* Describe exactly what went wrong. */
(*android_java_env)->ExceptionDescribe (android_java_env);
(*android_java_env)->ExceptionClear (android_java_env);
ANDROID_DELETE_LOCAL_REF (object);
ANDROID_DELETE_LOCAL_REF (object1);
memory_full (0);
}
}
/* Native image transforms. */
@ -5446,7 +5464,7 @@ android_browse_url (Lisp_Object url)
buffer = (*android_java_env)->GetStringUTFChars (android_java_env,
(jstring) value,
NULL);
android_exception_check ();
android_exception_check_1 (string);
/* Otherwise, build the string describing the error. */
tem = build_string_from_utf8 (buffer);
@ -5490,6 +5508,45 @@ android_get_current_api_level (void)
return android_api_level;
}
/* Query the status of the battery, and place it in *STATUS.
Value is 1 if the system is too old, else 0. */
int
android_query_battery (struct android_battery_state *status)
{
jlongArray array;
jlong *longs;
array = (*android_java_env)->CallObjectMethod (android_java_env,
emacs_service,
service_class.query_battery);
android_exception_check ();
/* A NULL return with no exception means that battery information
could not be obtained. */
if (!array)
return 1;
longs = (*android_java_env)->GetLongArrayElements (android_java_env,
array, NULL);
android_exception_check_1 (array);
status->capacity = longs[0];
status->charge_counter = longs[1];
status->current_average = longs[2];
status->current_now = longs[3];
status->remaining = longs[4];
status->status = longs[5];
(*android_java_env)->ReleaseLongArrayElements (android_java_env,
array, longs,
JNI_ABORT);
ANDROID_DELETE_LOCAL_REF (array);
return 0;
}
/* Whether or not a query is currently being made. */

View File

@ -84,6 +84,8 @@ extern void android_set_dont_accept_focus (android_window, bool);
extern jstring android_build_string (Lisp_Object);
extern jstring android_build_jstring (const char *);
extern void android_exception_check (void);
extern void android_exception_check_1 (jobject);
extern void android_exception_check_2 (jobject, jobject);
extern void android_get_keysym_name (int, char *, size_t);
extern void android_wait_event (void);
@ -106,7 +108,37 @@ extern void android_closedir (struct android_dir *);
/* Very miscellaneous functions. */
struct android_battery_state
{
/* Battery charge level in integer percentage. */
intmax_t capacity;
/* Battery charge level in microampere-hours. */
intmax_t charge_counter;
/* Battery current in microampere-hours. */
intmax_t current_average;
/* Instantaneous battery current in microampere-hours. */
intmax_t current_now;
/* Estimate as to the amount of time remaining until the battery is
charged, in milliseconds. */
intmax_t remaining;
/* Battery status. The value is either:
2, if the battery is charging.
3, if the battery is discharging.
5, if the battery is full.
4, if the battery is not full or discharging,
but is not charging either.
1, if the battery state is unknown. */
int status;
};
extern Lisp_Object android_browse_url (Lisp_Object);
extern int android_query_battery (struct android_battery_state *);

View File

@ -2783,6 +2783,46 @@ frame_parm_handler android_frame_parm_handlers[] =
NULL,
};
/* Battery information support. */
DEFUN ("android-query-battery", Fandroid_query_battery,
Sandroid_query_battery, 0, 0, 0,
doc: /* Perform a query for battery information.
This function will not work before Android 5.0.
Value is nil upon failure, or a list of the form:
(CAPACITY CHARGE-COUNTER CURRENT-AVERAGE CURRENT-NOW STATUS
REMAINING)
See the documentation at
https://developer.android.com/reference/android/os/BatteryManager
for more details about these values. */)
(void)
{
struct android_battery_state state;
/* Make sure the Android libraries have been initialized. */
if (!android_init_gui)
return Qnil;
/* Perform the query. */
if (android_query_battery (&state))
return Qnil;
return listn (6, make_int (state.capacity),
make_int (state.charge_counter),
make_int (state.current_average),
make_int (state.current_now),
make_int (state.status),
make_int (state.remaining));
}
#endif
@ -2837,8 +2877,9 @@ syms_of_androidfns (void)
defsubr (&Sx_hide_tip);
defsubr (&Sandroid_detect_mouse);
defsubr (&Sandroid_toggle_on_screen_keyboard);
#ifndef ANDROID_STUBIFY
defsubr (&Sandroid_query_battery);
tip_timer = Qnil;
staticpro (&tip_timer);
tip_frame = Qnil;

View File

@ -431,12 +431,7 @@ androidfont_from_lisp (Lisp_Object font)
spec = (*android_java_env)->AllocObject (android_java_env,
font_spec_class.class);
if (!spec)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
#define DO_SYMBOL_FIELD(field, index) \
tem = AREF (font, index); \
@ -446,11 +441,7 @@ androidfont_from_lisp (Lisp_Object font)
not matter at all. */ \
string = (*android_java_env)->NewStringUTF (android_java_env, \
SSDATA (SYMBOL_NAME (tem))); \
if (!string) \
{ \
(*android_java_env)->ExceptionClear (android_java_env); \
memory_full (0); \
} \
android_exception_check_1 (spec); \
\
(*android_java_env)->SetObjectField (android_java_env, spec, \
font_spec_class.field, \
@ -472,11 +463,7 @@ androidfont_from_lisp (Lisp_Object font)
integer_class.class, \
integer_class.constructor, \
(jint) value); \
if (!integer) \
{ \
(*android_java_env)->ExceptionClear (android_java_env); \
memory_full (0); \
} \
android_exception_check_1 (spec); \
\
(*android_java_env)->SetObjectField (android_java_env, spec, \
font_spec_class.field, \
@ -582,12 +569,9 @@ androidfont_list (struct frame *f, Lisp_Object font_spec)
font_driver,
font_driver_class.list,
spec);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (spec);
ANDROID_DELETE_LOCAL_REF (spec);
if (!array)
memory_full (0);
entities = (jarray) array;
size = (*android_java_env)->GetArrayLength (android_java_env,
entities);
@ -613,12 +597,9 @@ androidfont_list (struct frame *f, Lisp_Object font_spec)
/* Now, make a global reference to the Java font entity. */
info->object = (*android_java_env)->NewGlobalRef (android_java_env,
(jobject) tem);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_2 (tem, entities);
ANDROID_DELETE_LOCAL_REF (tem);
if (!info->object)
memory_full (0);
value = Fcons (entity, value);
}
@ -641,12 +622,9 @@ androidfont_match (struct frame *f, Lisp_Object font_spec)
font_driver,
font_driver_class.match,
spec);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (spec);
ANDROID_DELETE_LOCAL_REF (spec);
if (!result)
memory_full (0);
entity = font_make_entity_android (VECSIZE (struct androidfont_entity));
info = (struct androidfont_entity *) XFONT_ENTITY (entity);
@ -658,12 +636,9 @@ androidfont_match (struct frame *f, Lisp_Object font_spec)
androidfont_from_java (result, entity);
info->object = (*android_java_env)->NewGlobalRef (android_java_env,
(jobject) result);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_2 (entity, result);
ANDROID_DELETE_LOCAL_REF (result);
if (!info->object)
memory_full (0);
return entity;
}
@ -688,12 +663,7 @@ androidfont_draw (struct glyph_string *s, int from, int to,
ANDROID_HANDLE_WINDOW);
chars = (*android_java_env)->NewIntArray (android_java_env,
to - from);
if (!chars)
{
(*android_java_env)->ExceptionClear (android_java_env);
memory_full (0);
}
android_exception_check ();
(*android_java_env)->SetIntArrayRegion (android_java_env, chars,
0, to - from,
@ -710,7 +680,7 @@ androidfont_draw (struct glyph_string *s, int from, int to,
chars, (jint) x, (jint) y,
(jint) s->width,
(jboolean) with_background);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (chars);
ANDROID_DELETE_LOCAL_REF (chars);
return rc;
@ -769,16 +739,12 @@ androidfont_open_font (struct frame *f, Lisp_Object font_entity,
font_driver_class.open_font,
entity->object,
(jint) pixel_size);
if (!font_info->object)
{
(*android_java_env)->ExceptionClear (android_java_env);
return Qnil;
}
android_exception_check ();
old = font_info->object;
font_info->object
= (*android_java_env)->NewGlobalRef (android_java_env, old);
(*android_java_env)->ExceptionClear (android_java_env);
android_exception_check_1 (old);
ANDROID_DELETE_LOCAL_REF (old);
if (!font_info->object)
@ -839,14 +805,20 @@ androidfont_close_font (struct font *font)
xfree (info->metrics);
}
info->metrics = NULL;
/* If info->object is NULL, then FONT was unsuccessfully created,
and there is no global reference that has to be deleted. */
and there is no global reference that has to be deleted.
Alternatively, FONT may have been closed by font_close_object,
with this function called from GC. */
if (!info->object)
return;
(*android_java_env)->DeleteGlobalRef (android_java_env,
info->object);
info->object = NULL;
}
static int

View File

@ -147,7 +147,7 @@ DEFUN ("android-set-clipboard", Fandroid_set_clipboard,
clipboard,
clipboard_class.set_clipboard,
bytes);
android_exception_check ();
android_exception_check_1 (bytes);
ANDROID_DELETE_LOCAL_REF (bytes);
return Qnil;
@ -172,18 +172,13 @@ Alternatively, return nil if the clipboard is empty. */)
= (*android_java_env)->CallObjectMethod (android_java_env,
clipboard,
method);
if (!bytes)
{
android_exception_check ();
return Qnil;
}
android_exception_check ();
length = (*android_java_env)->GetArrayLength (android_java_env,
bytes);
data = (*android_java_env)->GetByteArrayElements (android_java_env,
bytes, NULL);
android_exception_check ();
android_exception_check_1 (bytes);
string = make_unibyte_string ((char *) data, length);

View File

@ -1634,12 +1634,7 @@ sfnt_map_glyf_table (int fd, struct sfnt_offset_subtable *subtable)
PROT_READ, MAP_PRIVATE, fd, offset);
if (glyphs == MAP_FAILED)
{
fprintf (stderr, "sfnt_map_glyf_table: mmap: %s\n",
strerror (errno));
return NULL;
}
return NULL;
/* An observation is that glyphs tend to be accessed in sequential
order and immediately after the font's glyph table is loaded. */
@ -1656,6 +1651,7 @@ sfnt_map_glyf_table (int fd, struct sfnt_offset_subtable *subtable)
glyf->size = directory->length;
glyf->glyphs = (unsigned char *) glyphs + map_offset;
glyf->start = glyphs;
return glyf;
}

View File

@ -1798,6 +1798,9 @@ sfntfont_free_outline_cache (struct sfnt_outline_cache *cache)
sfntfont_dereference_outline (last->outline);
xfree (last);
}
cache->next = cache;
cache->last = cache;
}
/* Dereference the raster RASTER. Free it once refcount reaches
@ -1913,6 +1916,9 @@ sfntfont_free_raster_cache (struct sfnt_raster_cache *cache)
sfntfont_dereference_raster (last->raster);
xfree (last);
}
cache->next = cache;
cache->last = cache;
}
@ -2664,8 +2670,8 @@ sfntfont_close (struct font *font)
xfree (info->hmtx);
#ifdef HAVE_MMAP
if (info->glyf_table_mapped)
if (info->glyf_table_mapped
&& info->glyf)
{
rc = sfnt_unmap_glyf_table (info->glyf);
@ -2684,6 +2690,23 @@ sfntfont_close (struct font *font)
xfree (info->cvt);
xfree (info->interpreter);
/* Clear these fields. It seems that close can be called twice,
once during font driver destruction, and once during GC. */
info->cmap = NULL;
info->hhea = NULL;
info->maxp = NULL;
info->head = NULL;
info->hhea = NULL;
info->glyf = NULL;
info->loca_short = NULL;
info->loca_long = NULL;
info->cmap_data = NULL;
info->prep = NULL;
info->fpgm = NULL;
info->cvt = NULL;
info->interpreter = NULL;
#ifdef HAVE_MMAP
/* Unlink INFO. */