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:
parent
d5cccfdc56
commit
8e4c5db193
@ -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.
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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, };
|
||||
}
|
||||
};
|
||||
|
@ -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.
|
||||
|
||||
|
239
src/android.c
239
src/android.c
@ -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. */
|
||||
|
@ -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 *);
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
Loading…
Reference in New Issue
Block a user