summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2024-03-12 09:48:53 +0800
committerPo Lu <luangruo@yahoo.com>2024-03-12 09:48:53 +0800
commitd7ded996082503ca00546c220c7ce8d96e16b76a (patch)
treec134bf9471567f3a27be6814f117d09994987059
parentbf38783c32e794e46fd03210242f265f34257940 (diff)
downloademacs-d7ded996082503ca00546c220c7ce8d96e16b76a.tar.gz
Implement notification residency on Android
* doc/lispref/os.texi (Desktop Notifications): Document support for `:resident'. * java/org/gnu/emacs/EmacsService.java (cancelNotification): * src/android.c (android_init_emacs_service): * src/android.h (struct android_emacs_service): New function. * src/androidselect.c (android_notifications_notify_1) (Fandroid_notifications_notify): New parameter QCresident; save it within notification lists. (android_notification_deleted, android_notification_action): Adjust for changes to the format of notification lists and cancel non-resident notifications when an action is selected. (syms_of_androidselect): <QCresident>: New symbol.
-rw-r--r--doc/lispref/os.texi6
-rw-r--r--java/org/gnu/emacs/EmacsService.java25
-rw-r--r--src/android.c2
-rw-r--r--src/android.h1
-rw-r--r--src/androidselect.c55
5 files changed, 75 insertions, 14 deletions
diff --git a/doc/lispref/os.texi b/doc/lispref/os.texi
index ecd88a39489..65c5ed2b4cc 100644
--- a/doc/lispref/os.texi
+++ b/doc/lispref/os.texi
@@ -3244,11 +3244,13 @@ of parameters analogous to its namesake in
@item :on-action @var{on-action}
@item :on-cancel @var{on-cancel}
@item :actions @var{actions}
+@item :resident @var{resident}
These have the same meaning as they do when used in calls to
-@code{notifications-notify}.
+@code{notifications-notify}, except that no more than three non-default
+actions will be displayed.
@item :urgency @var{urgency}
-The set of values for @var{urgency} is the same as with
+The set of accepted 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.
diff --git a/java/org/gnu/emacs/EmacsService.java b/java/org/gnu/emacs/EmacsService.java
index d17ba597d8e..9bc40d63311 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -1967,4 +1967,29 @@ public final class EmacsService extends Service
else
requestStorageAccess30 ();
}
+
+
+
+ /* Notification miscellany. */
+
+ /* Cancel any notification displayed with the tag TAG. */
+
+ public void
+ cancelNotification (final String string)
+ {
+ Object tem;
+ final NotificationManager manager;
+
+ tem = getSystemService (Context.NOTIFICATION_SERVICE);
+ manager = (NotificationManager) tem;
+
+ runOnUiThread (new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ manager.cancel (string, 2);
+ }
+ });
+ }
};
diff --git a/src/android.c b/src/android.c
index 125bb5209c3..dcd5c6d99c7 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1688,6 +1688,8 @@ android_init_emacs_service (void)
"externalStorageAvailable", "()Z");
FIND_METHOD (request_storage_access,
"requestStorageAccess", "()V");
+ FIND_METHOD (cancel_notification,
+ "cancelNotification", "(Ljava/lang/String;)V");
#undef FIND_METHOD
}
diff --git a/src/android.h b/src/android.h
index ee634a3e76c..2ca3d7e1446 100644
--- a/src/android.h
+++ b/src/android.h
@@ -302,6 +302,7 @@ struct android_emacs_service
jmethodID valid_authority;
jmethodID external_storage_available;
jmethodID request_storage_access;
+ jmethodID cancel_notification;
};
extern JNIEnv *android_java_env;
diff --git a/src/androidselect.c b/src/androidselect.c
index 04f4cf1573f..bcb7bcd2c3b 100644
--- a/src/androidselect.c
+++ b/src/androidselect.c
@@ -567,15 +567,15 @@ android_locate_icon (const char *name)
}
/* Display a desktop notification with the provided TITLE, BODY,
- REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, ACTION_CB and CANCEL_CB.
- Return an identifier for the resulting notification. */
+ REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, RESIDENT, ACTION_CB and
+ CANCEL_CB. Return an identifier for the resulting notification. */
static intmax_t
android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
Lisp_Object replaces_id,
Lisp_Object group, Lisp_Object icon,
Lisp_Object urgency, Lisp_Object actions,
- Lisp_Object action_cb,
+ Lisp_Object resident, Lisp_Object action_cb,
Lisp_Object cancel_cb)
{
static intmax_t counter;
@@ -740,8 +740,9 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body,
/* If callbacks are provided, save them into notification_table. */
- if (!NILP (action_cb) || !NILP (cancel_cb))
- Fputhash (build_string (identifier), Fcons (action_cb, cancel_cb),
+ if (!NILP (action_cb) || !NILP (cancel_cb) || !NILP (resident))
+ Fputhash (build_string (identifier), list3 (action_cb, cancel_cb,
+ resident),
notification_table);
/* Return the ID. */
@@ -755,12 +756,12 @@ ARGS must contain keywords followed by values. Each of the following
keywords is understood:
:title The notification title.
- :body The notification body.
+ :body The notification body.
:replaces-id The ID of a previous notification to supersede.
:group The notification group, or nil.
:urgency One of the symbols `low', `normal' or `critical',
defining the importance of the notification group.
- :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.
:actions A list of actions of the form:
(KEY TITLE KEY TITLE ...)
@@ -770,6 +771,8 @@ keywords is understood:
its existence is implied, and its TITLE is ignored.
No more than three actions can be defined, not
counting any action with "default" as its key.
+ :resident When set the notification will not be automatically
+ dismissed when it or an action is selected.
:on-action Function to call when an action is invoked.
The notification id and the key of the action are
provided as arguments to the function.
@@ -811,7 +814,7 @@ this function.
usage: (android-notifications-notify &rest ARGS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- Lisp_Object title, body, replaces_id, group, urgency;
+ Lisp_Object title, body, replaces_id, group, urgency, resident;
Lisp_Object icon;
Lisp_Object key, value, actions, action_cb, cancel_cb;
ptrdiff_t i;
@@ -821,7 +824,7 @@ usage: (android-notifications-notify &rest ARGS) */)
/* Clear each variable above. */
title = body = replaces_id = group = icon = urgency = actions = Qnil;
- action_cb = cancel_cb = Qnil;
+ resident = action_cb = cancel_cb = Qnil;
/* If NARGS is odd, error. */
@@ -849,6 +852,8 @@ usage: (android-notifications-notify &rest ARGS) */)
icon = value;
else if (EQ (key, QCactions))
actions = value;
+ else if (EQ (key, QCresident))
+ resident = value;
else if (EQ (key, QCon_action))
action_cb = value;
else if (EQ (key, QCon_cancel))
@@ -878,8 +883,8 @@ usage: (android-notifications-notify &rest ARGS) */)
return make_int (android_notifications_notify_1 (title, body, replaces_id,
group, icon, urgency,
- actions, action_cb,
- cancel_cb));
+ actions, resident,
+ action_cb, cancel_cb));
}
/* Run callbacks in response to a notification being deleted.
@@ -899,7 +904,7 @@ android_notification_deleted (struct android_notification_event *event,
if (!NILP (item))
Fremhash (tag, notification_table);
- if (CONSP (item) && FUNCTIONP (XCDR (item))
+ if (CONSP (item) && FUNCTIONP (XCAR (XCDR (item)))
&& sscanf (event->tag, "%*d.%*ld.%jd", &id) > 0)
{
ie->kind = NOTIFICATION_EVENT;
@@ -919,6 +924,8 @@ android_notification_action (struct android_notification_event *event,
{
Lisp_Object item, tag;
intmax_t id;
+ jstring tag_object;
+ jmethodID method;
tag = build_string (event->tag);
item = Fgethash (tag, notification_table, Qnil);
@@ -929,6 +936,29 @@ android_notification_action (struct android_notification_event *event,
ie->kind = NOTIFICATION_EVENT;
ie->arg = list3 (XCAR (item), make_int (id), action);
}
+
+ /* Test whether ITEM is resident. Non-resident notifications must be
+ removed when activated. */
+
+ if (!CONSP (item) || NILP (XCAR (XCDR (XCDR (item)))))
+ {
+ method = service_class.cancel_notification;
+ tag_object
+ = (*android_java_env)->NewStringUTF (android_java_env,
+ event->tag);
+ android_exception_check ();
+
+ (*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
+ emacs_service,
+ service_class.class,
+ method, tag_object);
+ android_exception_check_1 (tag_object);
+ ANDROID_DELETE_LOCAL_REF (tag_object);
+
+ /* Remove the notification from the callback table. */
+ if (!NILP (item))
+ Fremhash (tag, notification_table);
+ }
}
@@ -971,6 +1001,7 @@ syms_of_androidselect (void)
DEFSYM (QCurgency, ":urgency");
DEFSYM (QCicon, ":icon");
DEFSYM (QCactions, ":actions");
+ DEFSYM (QCresident, ":resident");
DEFSYM (QCon_action, ":on-action");
DEFSYM (QCon_cancel, ":on-cancel");