Update Android port

* doc/lispref/os.texi (Desktop Notifications): Revise
documentation for android-notifications-notify to reflect
changes.

* java/org/gnu/emacs/EmacsDesktopNotification.java (display1):
Convert notification importance to a legacy priority between
Android 7.1 and 4.1.

* java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap): Remove
immutable bitmap constructor, as the underlying Android API
functions are erroneously implemented.

* src/android.c (android_init_emacs_pixmap): Cease searching for
deleted constructor.
(android_create_pixmap_from_bitmap_data): Create a pixmap, then
fill it with the contents of the bitmap, in lieu of employing
the aforementioned constructor.

* src/androidselect.c (Fandroid_notifications_notify): Revise
doc string.
This commit is contained in:
Po Lu 2023-09-25 13:01:44 +08:00
parent 947409d408
commit df5a9a78b5
5 changed files with 129 additions and 116 deletions

View file

@ -3220,15 +3220,25 @@ These have the same meaning as they do when used in calls to
@code{notifications-notify}. @code{notifications-notify}.
@item :urgency @var{urgency} @item :urgency @var{urgency}
The set of values for @var{urgency} is the same as with
@code{notifications-notify}, but the urgency applies to all
notifications displayed with the defined @var{group}, except under
Android 7.1 and earlier.
@item :group @var{group} @item :group @var{group}
These two parameters are ignored under Android 7.1 and earlier @var{group} is a string that designates a category to which the
versions of the system. The set of values for @var{urgency} is the notification sent will belong. This category is reproduced within the
same as with @code{notifications-notify}, but the urgency applies to system's notification settings menus, but is ignored under Android 7.1
all notifications displayed with the defined @var{group}. and earlier.
If @var{group} is nil or not present within @var{params}, it is If @var{group} is nil or not present within @var{params}, it is
replaced by the string @samp{"Desktop Notifications"}. replaced by the string @samp{"Desktop Notifications"}.
Callers should provide one stable combination of @var{urgency} and
@var{group} for each kind of notification they send, given that the
system may elect to disregard @var{urgency} if it does not match that
of any notification previously delivered to @var{group}.
@item :icon @var{icon} @item :icon @var{icon}
This parameter controls the symbolic icon the notification will be This parameter controls the symbolic icon the notification will be
displayed with. Its value is a string designating an icon within the displayed with. Its value is a string designating an icon within the

View file

@ -96,6 +96,7 @@ public final class EmacsDesktopNotification
RemoteViews contentView; RemoteViews contentView;
Intent intent; Intent intent;
PendingIntent pending; PendingIntent pending;
int priority;
tem = context.getSystemService (Context.NOTIFICATION_SERVICE); tem = context.getSystemService (Context.NOTIFICATION_SERVICE);
manager = (NotificationManager) tem; manager = (NotificationManager) tem;
@ -116,11 +117,37 @@ public final class EmacsDesktopNotification
.build ()); .build ());
} }
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
notification = (new Notification.Builder (context) {
.setContentTitle (title) /* Android 7.1 and earlier don't segregate notifications into
.setContentText (content) distinct categories, but permit an importance to be
.setSmallIcon (icon) assigned to each individual notification. */
.build ());
switch (importance)
{
case 2: /* IMPORTANCE_LOW */
default:
priority = Notification.PRIORITY_LOW;
break;
case 3: /* IMPORTANCE_DEFAULT */
priority = Notification.PRIORITY_DEFAULT;
break;
case 4: /* IMPORTANCE_HIGH */
priority = Notification.PRIORITY_HIGH;
break;
}
notification = (new Notification.Builder (context)
.setContentTitle (title)
.setContentText (content)
.setSmallIcon (icon)
.setPriority (priority)
.build ());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN)
notification.priority = priority;
}
else else
{ {
notification = new Notification (); notification = new Notification ();

View file

@ -50,39 +50,6 @@ public final class EmacsPixmap extends EmacsHandleObject
changed. */ changed. */
private long gcClipRectID; private long gcClipRectID;
public
EmacsPixmap (short handle, int colors[], int width,
int height, int depth)
{
super (handle);
if (depth != 1 && depth != 24)
throw new IllegalArgumentException ("Invalid depth specified"
+ " for pixmap: " + depth);
switch (depth)
{
case 1:
bitmap = Bitmap.createBitmap (colors, width, height,
Bitmap.Config.ALPHA_8);
break;
case 24:
bitmap = Bitmap.createBitmap (colors, width, height,
Bitmap.Config.ARGB_8888);
bitmap.setHasAlpha (false);
break;
}
this.width = width;
this.height = height;
this.depth = depth;
/* The immutable bitmap constructor is only leveraged to create
small fringe bitmaps. */
this.needCollect = false;
}
public public
EmacsPixmap (short handle, int width, int height, int depth) EmacsPixmap (short handle, int width, int height, int depth)
{ {

View file

@ -73,7 +73,6 @@ bool android_init_gui;
struct android_emacs_pixmap struct android_emacs_pixmap
{ {
jclass class; jclass class;
jmethodID constructor;
jmethodID constructor_mutable; jmethodID constructor_mutable;
}; };
@ -1649,7 +1648,6 @@ android_init_emacs_pixmap (void)
name, signature); \ name, signature); \
assert (pixmap_class.c_name); assert (pixmap_class.c_name);
FIND_METHOD (constructor, "<init>", "(S[IIII)V");
FIND_METHOD (constructor_mutable, "<init>", "(SIII)V"); FIND_METHOD (constructor_mutable, "<init>", "(SIII)V");
#undef FIND_METHOD #undef FIND_METHOD
@ -3404,86 +3402,91 @@ android_create_pixmap_from_bitmap_data (char *data, unsigned int width,
unsigned long background, unsigned long background,
unsigned int depth) unsigned int depth)
{ {
android_handle prev_max_handle;
jobject object;
jintArray colors;
android_pixmap pixmap; android_pixmap pixmap;
jobject object;
AndroidBitmapInfo info;
unsigned int *depth_24;
unsigned char *depth_8;
void *bitmap_data;
unsigned int x, y; unsigned int x, y;
jint *region; unsigned int r, g, b;
USE_SAFE_ALLOCA; /* Create a pixmap with the right dimensions and depth. */
pixmap = android_create_pixmap (width, height, depth);
/* Create the color array holding the data. */ /* Lock the bitmap data. */
colors = (*android_java_env)->NewIntArray (android_java_env, bitmap_data = android_lock_bitmap (pixmap, &info, &object);
width * height);
android_exception_check ();
SAFE_NALLOCA (region, sizeof *region, width); /* Merely return if locking the bitmap fails. */
if (!bitmap_data)
return pixmap;
for (y = 0; y < height; ++y) eassert (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888
|| info.format == ANDROID_BITMAP_FORMAT_A_8);
/* Begin copying each line. */
switch (info.format)
{ {
for (x = 0; x < width; ++x) case ANDROID_BITMAP_FORMAT_RGBA_8888:
{
if (depth == 24)
{
/* The alpha channels must be set, or otherwise, the
pixmap will be created entirely transparent. */
if (data[x / 8] & (1 << (x % 8))) /* Swizzle the pixels into ABGR format. Android uses Skia's
region[x] = foreground | 0xff000000; ``native color type'', which is ABGR. This is despite the
else format being named ``ARGB'', and more confusingly
region[x] = background | 0xff000000; `ANDROID_BITMAP_FORMAT_RGBA_8888' in bitmap.h. */
}
else r = background & 0x00ff0000;
{ g = background & 0x0000ff00;
if (data[x / 8] & (1 << (x % 8))) b = background & 0x000000ff;
region[x] = foreground; background = (r >> 16) | g | (b << 16) | 0xff000000;
else r = foreground & 0x00ff0000;
region[x] = background; g = foreground & 0x0000ff00;
} b = foreground & 0x000000ff;
foreground = (r >> 16) | g | (b << 16) | 0xff000000;
for (y = 0; y < height; ++y)
{
depth_24 = (void *) ((char *) bitmap_data + y * info.stride);
for (x = 0; x < width; ++x)
depth_24[x] = ((data[x / 8] & (1 << (x % 8)))
? foreground : background);
data += (width + 7) / 8;
} }
(*android_java_env)->SetIntArrayRegion (android_java_env, break;
colors,
width * y, width, case ANDROID_BITMAP_FORMAT_A_8:
region);
data += width / 8; /* 8-bit pixmaps are created, but in spite of that they are
employed only to represent bitmaps. */
foreground = (foreground ? 255 : 0);
background = (background ? 255 : 0);
for (y = 0; y < height; ++y)
{
depth_8 = (void *) ((char *) bitmap_data + y * info.stride);
for (x = 0; x < width; ++x)
depth_8[x] = ((data[x / 8] & (1 << (x % 8)))
? foreground : background);
data += (width + 7) / 8;
}
break;
default:
emacs_abort ();
} }
/* First, allocate the pixmap handle. */ /* Unlock the bitmap itself. */
prev_max_handle = max_handle; AndroidBitmap_unlockPixels (android_java_env, object);
pixmap = android_alloc_id ();
if (!pixmap)
{
ANDROID_DELETE_LOCAL_REF ((jobject) colors);
error ("Out of pixmap handles!");
}
object = (*android_java_env)->NewObject (android_java_env,
pixmap_class.class,
pixmap_class.constructor,
(jshort) pixmap, colors,
(jint) width, (jint) height,
(jint) depth);
(*android_java_env)->ExceptionClear (android_java_env);
ANDROID_DELETE_LOCAL_REF ((jobject) colors);
if (!object)
{
max_handle = prev_max_handle;
memory_full (0);
}
android_handles[pixmap].type = ANDROID_HANDLE_PIXMAP;
android_handles[pixmap].handle
= (*android_java_env)->NewGlobalRef (android_java_env, object);
ANDROID_DELETE_LOCAL_REF (object); ANDROID_DELETE_LOCAL_REF (object);
if (!android_handles[pixmap].handle) /* Return the pixmap. */
memory_full (0);
SAFE_FREE ();
return pixmap; return pixmap;
} }

View file

@ -660,12 +660,18 @@ keywords is understood:
:icon The name of a drawable resource to display as the :icon The name of a drawable resource to display as the
notification's icon. notification's icon.
The notification group and urgency are ignored on Android 7.1 and The notification group is ignored on Android 7.1 and earlier versions
earlier versions of Android. Outside such older systems, it of Android. Outside such older systems, it identifies a category that
identifies a category that will be displayed in the system Settings will be displayed in the system Settings menu, and the urgency
menu. The urgency provided always extends to affect all notifications provided always extends to affect all notifications displayed within
displayed within that category. If the group is not provided, it that category. If the group is not provided, it defaults to the
defaults to the string "Desktop Notifications". string "Desktop Notifications".
Each caller should strive to provide one unchanging combination of
notification group and urgency for each kind of notification it sends,
inasmuch as the system may, subject to user configuration, disregard
the urgency specified within a notification, should it not be the
first notification sent to its notification group.
The provided icon should be the name of a "drawable resource" present The provided icon should be the name of a "drawable resource" present
within the "android.R.drawable" class designating an icon with a within the "android.R.drawable" class designating an icon with a