group
(delq article (gnus-list-of-unread-articles group)))
;; gnus-group-refresh-group
- (gnus-group-update-group group)))))))
+ (gnus-group-update-group group))))))
+ ;; Notifications are removed unless otherwise specified once they (or
+ ;; an action of theirs) are selected
+ (assoc-delete-all id gnus-notifications-id-to-msg))
+
+(defun gnus-notification-close (id reason)
+ "Remove ID from the alist of notification identifiers to messages.
+REASON is ignored."
+ (assoc-delete-all id gnus-notifications-id-to-msg))
(defun gnus-notifications-notify (from subject photo-file)
"Send a notification about a new mail.
Return a notification id if any, or t on success."
- (if (fboundp 'notifications-notify)
+ (if (featurep 'android)
(gnus-funcall-no-warning
- 'notifications-notify
+ 'android-notifications-notify
:title from
:body subject
:actions '("read" "Read" "mark-read" "Mark As Read")
:on-action 'gnus-notifications-action
- :app-icon (gnus-funcall-no-warning
- 'image-search-load-path "gnus/gnus.png")
- :image-path photo-file
- :app-name "Gnus"
- :category "email.arrived"
+ :on-close 'gnus-notifications-close
+ :group "Email arrivals"
:timeout gnus-notifications-timeout)
- (message "New message from %s: %s" from subject)
- ;; Don't return an id
- t))
+ (if (fboundp 'notifications-notify)
+ (gnus-funcall-no-warning
+ 'notifications-notify
+ :title from
+ :body subject
+ :actions '("read" "Read" "mark-read" "Mark As Read")
+ :on-action 'gnus-notifications-action
+ :on-close 'gnus-notifications-close
+ :app-icon (gnus-funcall-no-warning
+ 'image-search-load-path "gnus/gnus.png")
+ :image-path photo-file
+ :app-name "Gnus"
+ :category "email.arrived"
+ :timeout gnus-notifications-timeout)
+ (message "New message from %s: %s" from subject)
+ ;; Don't return an id
+ t)))
(declare-function gravatar-retrieve-synchronously "gravatar.el"
(mail-address))
FIND_METHOD (init, "<init>", "(Ljava/lang/String;"
"Ljava/lang/String;Ljava/lang/String;"
"Ljava/lang/String;II[Ljava/lang/String;"
- "[Ljava/lang/String;)V");
+ "[Ljava/lang/String;J)V");
FIND_METHOD (display, "display", "()V");
#undef FIND_METHOD
}
}
/* Display a desktop notification with the provided TITLE, BODY,
- REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, RESIDENT, ACTION_CB and
- CLOSE_CB. Return an identifier for the resulting notification. */
+ REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, TIMEOUT, RESIDENT,
+ ACTION_CB and CLOSE_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 resident, Lisp_Object action_cb,
- Lisp_Object close_cb)
+ Lisp_Object timeout, Lisp_Object resident,
+ Lisp_Object action_cb, Lisp_Object close_cb)
{
static intmax_t counter;
intmax_t id;
jint nitems, i;
jstring item;
Lisp_Object length;
+ jlong timeout_val;
if (EQ (urgency, Qlow))
type = 2; /* IMPORTANCE_LOW */
else
signal_error ("Invalid notification importance given", urgency);
+ /* Decode the timeout. */
+
+ timeout_val = 0;
+
+ if (!NILP (timeout))
+ {
+ CHECK_INTEGER (timeout);
+
+ if (!integer_to_intmax (timeout, &id)
+ || id > TYPE_MAXIMUM (jlong)
+ || id < TYPE_MINIMUM (jlong))
+ signal_error ("Invalid timeout", timeout);
+
+ if (id > 0)
+ timeout_val = id;
+ }
+
nitems = 0;
/* If ACTIONS is provided, split it into two arrays of Java strings
notification_class.init,
title1, body1, group1,
identifier1, icon1, type,
- action_keys, action_titles);
+ action_keys, action_titles,
+ timeout_val);
android_exception_check_6 (title1, body1, group1, identifier1,
action_titles, action_keys);
ANDROID_DELETE_LOCAL_REF (body1);
ANDROID_DELETE_LOCAL_REF (group1);
ANDROID_DELETE_LOCAL_REF (identifier1);
-
- if (action_keys)
- ANDROID_DELETE_LOCAL_REF (action_keys);
-
- if (action_titles)
- ANDROID_DELETE_LOCAL_REF (action_titles);
+ ANDROID_DELETE_LOCAL_REF (action_keys);
+ ANDROID_DELETE_LOCAL_REF (action_titles);
/* Display the notification. */
(*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
The action for which CALLBACK is called when the
notification itself is selected is named "default",
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.
+ No more than three actions defined here will be
+ displayed, not counting any with "default" as its
+ key.
+ :timeout Number of miliseconds from the display of the
+ notification at which it will be automatically
+ dismissed, or a value of zero or smaller if it
+ is to remain until user action is taken to dismiss
+ it.
: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.
with the notification id and the symbol `undefined'
for arguments.
-The notification group is ignored on Android 7.1 and earlier versions
-of Android. Outside such older systems, it identifies a category that
-will be displayed in the system Settings menu, and the urgency
-provided always extends to affect all notifications displayed within
-that category. If the group is not provided, it defaults to the
-string "Desktop Notifications".
+The notification group and timeout are ignored on Android 7.1 and
+earlier versions of Android. On more recent versions, the urgency
+identifies a category that will be displayed in the system Settings
+menu, and the urgency provided always extends to affect all
+notifications displayed within that category, though it may be ignored
+if higher than any previously-specified urgency or if the user have
+already configured a different urgency for this category from Settings.
+If the group is not provided, it defaults to the string "Desktop
+Notifications" with the urgency suffixed.
Each caller should strive to provide one unchanging combination of
notification group and urgency for each kind of notification it sends,
The provided icon should be the name of a "drawable resource" present
within the "android.R.drawable" class designating an icon with a
-transparent background. If no icon is provided (or the icon is absent
-from this system), it defaults to "ic_dialog_alert".
+transparent background. Should no icon be provided (or the icon is
+absent from this system), it defaults to "ic_dialog_alert".
Actions specified with :actions cannot be displayed on Android 4.0 and
earlier versions of the system.
usage: (android-notifications-notify &rest ARGS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- Lisp_Object title, body, replaces_id, group, urgency, resident;
+ Lisp_Object title, body, replaces_id, group, urgency, timeout, resident;
Lisp_Object icon;
Lisp_Object key, value, actions, action_cb, close_cb;
ptrdiff_t i;
+ AUTO_STRING (default_icon, "ic_dialog_alert");
if (!android_init_gui)
error ("No Android display connection!");
/* Clear each variable above. */
title = body = replaces_id = group = icon = urgency = actions = Qnil;
- resident = action_cb = close_cb = Qnil;
+ timeout = resident = action_cb = close_cb = Qnil;
/* If NARGS is odd, error. */
icon = value;
else if (EQ (key, QCactions))
actions = value;
+ else if (EQ (key, QCtimeout))
+ timeout = value;
else if (EQ (key, QCresident))
resident = value;
else if (EQ (key, QCon_action))
urgency = Qlow;
if (NILP (group))
- group = build_string ("Desktop Notifications");
+ {
+ AUTO_STRING (format, "Desktop Notifications (%s importance)");
+ group = CALLN (Fformat, format, urgency);
+ }
if (NILP (icon))
- icon = build_string ("ic_dialog_alert");
+ icon = default_icon;
else
CHECK_STRING (icon);
return make_int (android_notifications_notify_1 (title, body, replaces_id,
group, icon, urgency,
- actions, resident,
+ actions, timeout, resident,
action_cb, close_cb));
}
DEFSYM (QCurgency, ":urgency");
DEFSYM (QCicon, ":icon");
DEFSYM (QCactions, ":actions");
+ DEFSYM (QCtimeout, ":timeout");
DEFSYM (QCresident, ":resident");
DEFSYM (QCon_action, ":on-action");
DEFSYM (QCon_close, ":on-close");