From: Po Lu Date: Tue, 12 Mar 2024 01:48:53 +0000 (+0800) Subject: Implement notification residency on Android X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=323f3f878cb3b7bad282fc31d41c7c05977b535d;p=emacs.git 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): : New symbol. (cherry picked from commit d7ded996082503ca00546c220c7ce8d96e16b76a) --- 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");