diff options
| author | Po Lu | 2024-03-12 09:48:53 +0800 |
|---|---|---|
| committer | Po Lu | 2024-03-12 09:48:53 +0800 |
| commit | d7ded996082503ca00546c220c7ce8d96e16b76a (patch) | |
| tree | c134bf9471567f3a27be6814f117d09994987059 /src | |
| parent | bf38783c32e794e46fd03210242f265f34257940 (diff) | |
| download | emacs-d7ded996082503ca00546c220c7ce8d96e16b76a.tar.gz emacs-d7ded996082503ca00546c220c7ce8d96e16b76a.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/android.c | 2 | ||||
| -rw-r--r-- | src/android.h | 1 | ||||
| -rw-r--r-- | src/androidselect.c | 55 |
3 files changed, 46 insertions, 12 deletions
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) | |||
| 1688 | "externalStorageAvailable", "()Z"); | 1688 | "externalStorageAvailable", "()Z"); |
| 1689 | FIND_METHOD (request_storage_access, | 1689 | FIND_METHOD (request_storage_access, |
| 1690 | "requestStorageAccess", "()V"); | 1690 | "requestStorageAccess", "()V"); |
| 1691 | FIND_METHOD (cancel_notification, | ||
| 1692 | "cancelNotification", "(Ljava/lang/String;)V"); | ||
| 1691 | #undef FIND_METHOD | 1693 | #undef FIND_METHOD |
| 1692 | } | 1694 | } |
| 1693 | 1695 | ||
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 | |||
| 302 | jmethodID valid_authority; | 302 | jmethodID valid_authority; |
| 303 | jmethodID external_storage_available; | 303 | jmethodID external_storage_available; |
| 304 | jmethodID request_storage_access; | 304 | jmethodID request_storage_access; |
| 305 | jmethodID cancel_notification; | ||
| 305 | }; | 306 | }; |
| 306 | 307 | ||
| 307 | extern JNIEnv *android_java_env; | 308 | 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) | |||
| 567 | } | 567 | } |
| 568 | 568 | ||
| 569 | /* Display a desktop notification with the provided TITLE, BODY, | 569 | /* Display a desktop notification with the provided TITLE, BODY, |
| 570 | REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, ACTION_CB and CANCEL_CB. | 570 | REPLACES_ID, GROUP, ICON, URGENCY, ACTIONS, RESIDENT, ACTION_CB and |
| 571 | Return an identifier for the resulting notification. */ | 571 | CANCEL_CB. Return an identifier for the resulting notification. */ |
| 572 | 572 | ||
| 573 | static intmax_t | 573 | static intmax_t |
| 574 | android_notifications_notify_1 (Lisp_Object title, Lisp_Object body, | 574 | android_notifications_notify_1 (Lisp_Object title, Lisp_Object body, |
| 575 | Lisp_Object replaces_id, | 575 | Lisp_Object replaces_id, |
| 576 | Lisp_Object group, Lisp_Object icon, | 576 | Lisp_Object group, Lisp_Object icon, |
| 577 | Lisp_Object urgency, Lisp_Object actions, | 577 | Lisp_Object urgency, Lisp_Object actions, |
| 578 | Lisp_Object action_cb, | 578 | Lisp_Object resident, Lisp_Object action_cb, |
| 579 | Lisp_Object cancel_cb) | 579 | Lisp_Object cancel_cb) |
| 580 | { | 580 | { |
| 581 | static intmax_t counter; | 581 | static intmax_t counter; |
| @@ -740,8 +740,9 @@ android_notifications_notify_1 (Lisp_Object title, Lisp_Object body, | |||
| 740 | 740 | ||
| 741 | /* If callbacks are provided, save them into notification_table. */ | 741 | /* If callbacks are provided, save them into notification_table. */ |
| 742 | 742 | ||
| 743 | if (!NILP (action_cb) || !NILP (cancel_cb)) | 743 | if (!NILP (action_cb) || !NILP (cancel_cb) || !NILP (resident)) |
| 744 | Fputhash (build_string (identifier), Fcons (action_cb, cancel_cb), | 744 | Fputhash (build_string (identifier), list3 (action_cb, cancel_cb, |
| 745 | resident), | ||
| 745 | notification_table); | 746 | notification_table); |
| 746 | 747 | ||
| 747 | /* Return the ID. */ | 748 | /* Return the ID. */ |
| @@ -755,12 +756,12 @@ ARGS must contain keywords followed by values. Each of the following | |||
| 755 | keywords is understood: | 756 | keywords is understood: |
| 756 | 757 | ||
| 757 | :title The notification title. | 758 | :title The notification title. |
| 758 | :body The notification body. | 759 | :body The notification body. |
| 759 | :replaces-id The ID of a previous notification to supersede. | 760 | :replaces-id The ID of a previous notification to supersede. |
| 760 | :group The notification group, or nil. | 761 | :group The notification group, or nil. |
| 761 | :urgency One of the symbols `low', `normal' or `critical', | 762 | :urgency One of the symbols `low', `normal' or `critical', |
| 762 | defining the importance of the notification group. | 763 | defining the importance of the notification group. |
| 763 | :icon The name of a drawable resource to display as the | 764 | :icon The name of a drawable resource to display as the |
| 764 | notification's icon. | 765 | notification's icon. |
| 765 | :actions A list of actions of the form: | 766 | :actions A list of actions of the form: |
| 766 | (KEY TITLE KEY TITLE ...) | 767 | (KEY TITLE KEY TITLE ...) |
| @@ -770,6 +771,8 @@ keywords is understood: | |||
| 770 | its existence is implied, and its TITLE is ignored. | 771 | its existence is implied, and its TITLE is ignored. |
| 771 | No more than three actions can be defined, not | 772 | No more than three actions can be defined, not |
| 772 | counting any action with "default" as its key. | 773 | counting any action with "default" as its key. |
| 774 | :resident When set the notification will not be automatically | ||
| 775 | dismissed when it or an action is selected. | ||
| 773 | :on-action Function to call when an action is invoked. | 776 | :on-action Function to call when an action is invoked. |
| 774 | The notification id and the key of the action are | 777 | The notification id and the key of the action are |
| 775 | provided as arguments to the function. | 778 | provided as arguments to the function. |
| @@ -811,7 +814,7 @@ this function. | |||
| 811 | usage: (android-notifications-notify &rest ARGS) */) | 814 | usage: (android-notifications-notify &rest ARGS) */) |
| 812 | (ptrdiff_t nargs, Lisp_Object *args) | 815 | (ptrdiff_t nargs, Lisp_Object *args) |
| 813 | { | 816 | { |
| 814 | Lisp_Object title, body, replaces_id, group, urgency; | 817 | Lisp_Object title, body, replaces_id, group, urgency, resident; |
| 815 | Lisp_Object icon; | 818 | Lisp_Object icon; |
| 816 | Lisp_Object key, value, actions, action_cb, cancel_cb; | 819 | Lisp_Object key, value, actions, action_cb, cancel_cb; |
| 817 | ptrdiff_t i; | 820 | ptrdiff_t i; |
| @@ -821,7 +824,7 @@ usage: (android-notifications-notify &rest ARGS) */) | |||
| 821 | 824 | ||
| 822 | /* Clear each variable above. */ | 825 | /* Clear each variable above. */ |
| 823 | title = body = replaces_id = group = icon = urgency = actions = Qnil; | 826 | title = body = replaces_id = group = icon = urgency = actions = Qnil; |
| 824 | action_cb = cancel_cb = Qnil; | 827 | resident = action_cb = cancel_cb = Qnil; |
| 825 | 828 | ||
| 826 | /* If NARGS is odd, error. */ | 829 | /* If NARGS is odd, error. */ |
| 827 | 830 | ||
| @@ -849,6 +852,8 @@ usage: (android-notifications-notify &rest ARGS) */) | |||
| 849 | icon = value; | 852 | icon = value; |
| 850 | else if (EQ (key, QCactions)) | 853 | else if (EQ (key, QCactions)) |
| 851 | actions = value; | 854 | actions = value; |
| 855 | else if (EQ (key, QCresident)) | ||
| 856 | resident = value; | ||
| 852 | else if (EQ (key, QCon_action)) | 857 | else if (EQ (key, QCon_action)) |
| 853 | action_cb = value; | 858 | action_cb = value; |
| 854 | else if (EQ (key, QCon_cancel)) | 859 | else if (EQ (key, QCon_cancel)) |
| @@ -878,8 +883,8 @@ usage: (android-notifications-notify &rest ARGS) */) | |||
| 878 | 883 | ||
| 879 | return make_int (android_notifications_notify_1 (title, body, replaces_id, | 884 | return make_int (android_notifications_notify_1 (title, body, replaces_id, |
| 880 | group, icon, urgency, | 885 | group, icon, urgency, |
| 881 | actions, action_cb, | 886 | actions, resident, |
| 882 | cancel_cb)); | 887 | action_cb, cancel_cb)); |
| 883 | } | 888 | } |
| 884 | 889 | ||
| 885 | /* Run callbacks in response to a notification being deleted. | 890 | /* Run callbacks in response to a notification being deleted. |
| @@ -899,7 +904,7 @@ android_notification_deleted (struct android_notification_event *event, | |||
| 899 | if (!NILP (item)) | 904 | if (!NILP (item)) |
| 900 | Fremhash (tag, notification_table); | 905 | Fremhash (tag, notification_table); |
| 901 | 906 | ||
| 902 | if (CONSP (item) && FUNCTIONP (XCDR (item)) | 907 | if (CONSP (item) && FUNCTIONP (XCAR (XCDR (item))) |
| 903 | && sscanf (event->tag, "%*d.%*ld.%jd", &id) > 0) | 908 | && sscanf (event->tag, "%*d.%*ld.%jd", &id) > 0) |
| 904 | { | 909 | { |
| 905 | ie->kind = NOTIFICATION_EVENT; | 910 | ie->kind = NOTIFICATION_EVENT; |
| @@ -919,6 +924,8 @@ android_notification_action (struct android_notification_event *event, | |||
| 919 | { | 924 | { |
| 920 | Lisp_Object item, tag; | 925 | Lisp_Object item, tag; |
| 921 | intmax_t id; | 926 | intmax_t id; |
| 927 | jstring tag_object; | ||
| 928 | jmethodID method; | ||
| 922 | 929 | ||
| 923 | tag = build_string (event->tag); | 930 | tag = build_string (event->tag); |
| 924 | item = Fgethash (tag, notification_table, Qnil); | 931 | item = Fgethash (tag, notification_table, Qnil); |
| @@ -929,6 +936,29 @@ android_notification_action (struct android_notification_event *event, | |||
| 929 | ie->kind = NOTIFICATION_EVENT; | 936 | ie->kind = NOTIFICATION_EVENT; |
| 930 | ie->arg = list3 (XCAR (item), make_int (id), action); | 937 | ie->arg = list3 (XCAR (item), make_int (id), action); |
| 931 | } | 938 | } |
| 939 | |||
| 940 | /* Test whether ITEM is resident. Non-resident notifications must be | ||
| 941 | removed when activated. */ | ||
| 942 | |||
| 943 | if (!CONSP (item) || NILP (XCAR (XCDR (XCDR (item))))) | ||
| 944 | { | ||
| 945 | method = service_class.cancel_notification; | ||
| 946 | tag_object | ||
| 947 | = (*android_java_env)->NewStringUTF (android_java_env, | ||
| 948 | event->tag); | ||
| 949 | android_exception_check (); | ||
| 950 | |||
| 951 | (*android_java_env)->CallNonvirtualVoidMethod (android_java_env, | ||
| 952 | emacs_service, | ||
| 953 | service_class.class, | ||
| 954 | method, tag_object); | ||
| 955 | android_exception_check_1 (tag_object); | ||
| 956 | ANDROID_DELETE_LOCAL_REF (tag_object); | ||
| 957 | |||
| 958 | /* Remove the notification from the callback table. */ | ||
| 959 | if (!NILP (item)) | ||
| 960 | Fremhash (tag, notification_table); | ||
| 961 | } | ||
| 932 | } | 962 | } |
| 933 | 963 | ||
| 934 | 964 | ||
| @@ -971,6 +1001,7 @@ syms_of_androidselect (void) | |||
| 971 | DEFSYM (QCurgency, ":urgency"); | 1001 | DEFSYM (QCurgency, ":urgency"); |
| 972 | DEFSYM (QCicon, ":icon"); | 1002 | DEFSYM (QCicon, ":icon"); |
| 973 | DEFSYM (QCactions, ":actions"); | 1003 | DEFSYM (QCactions, ":actions"); |
| 1004 | DEFSYM (QCresident, ":resident"); | ||
| 974 | DEFSYM (QCon_action, ":on-action"); | 1005 | DEFSYM (QCon_action, ":on-action"); |
| 975 | DEFSYM (QCon_cancel, ":on-cancel"); | 1006 | DEFSYM (QCon_cancel, ":on-cancel"); |
| 976 | 1007 | ||