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''.
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
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
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.
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
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.
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,
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;
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, };
+ }
};
;; - 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:
(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)
(cons ?m (or minutes "N/A"))
(cons ?t (or remaining-time "N/A")))))
+\f
+;;; `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")))))
+
\f
;;; Private functions.
jmethodID reset_ic;
jmethodID open_content_uri;
jmethodID check_content_uri;
+ jmethodID query_battery;
};
struct android_emacs_pixmap
!= 0),
(jboolean) ((mode & W_OK)
!= 0));
- android_exception_check ();
+ android_exception_check_1 (string);
ANDROID_DELETE_LOCAL_REF (string);
return rc;
"([BZZZ)I");
FIND_METHOD (check_content_uri, "checkContentUri",
"([BZZ)Z");
+ FIND_METHOD (query_battery, "queryBattery", "()[J");
#undef FIND_METHOD
}
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,
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
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
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,
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)
{
(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);
/* 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);
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)
{
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);
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
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
(*android_java_env)->CallVoidMethod (android_java_env,
emacs_service,
service_class.ring_bell);
+ android_exception_check ();
}
void
(*android_java_env)->CallVoidMethod (android_java_env, window,
make_input_focus, (jlong) time);
+ android_exception_check ();
}
void
(*android_java_env)->CallVoidMethod (android_java_env, window,
raise);
+ android_exception_check ();
}
void
(*android_java_env)->CallVoidMethod (android_java_env, window,
lower);
+ android_exception_check ();
}
int
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. */
= (*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. */
= (*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. */
/* 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];
/* 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,
(*android_java_env)->ReleaseStringChars (android_java_env, string,
characters);
- android_exception_check ();
ANDROID_DELETE_LOCAL_REF (string);
}
}
+ 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);
}
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;
}
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;
}
+\f
+
+/* 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. */
}
}
+/* 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);
+ }
+}
+
+
\f
/* Native image transforms. */
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);
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;
+}
+
\f
/* Whether or not a query is currently being made. */
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);
/* 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 *);
\f
NULL,
};
+\f
+
+/* 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
\f
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;
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); \
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, \
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, \
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);
/* 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);
}
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);
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;
}
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,
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;
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)
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
clipboard,
clipboard_class.set_clipboard,
bytes);
- android_exception_check ();
+ android_exception_check_1 (bytes);
ANDROID_DELETE_LOCAL_REF (bytes);
return Qnil;
= (*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);
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. */
glyf->size = directory->length;
glyf->glyphs = (unsigned char *) glyphs + map_offset;
glyf->start = glyphs;
+
return glyf;
}
sfntfont_dereference_outline (last->outline);
xfree (last);
}
+
+ cache->next = cache;
+ cache->last = cache;
}
/* Dereference the raster RASTER. Free it once refcount reaches
sfntfont_dereference_raster (last->raster);
xfree (last);
}
+
+ cache->next = cache;
+ cache->last = cache;
}
\f
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);
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. */