Support desktop notifications on Android
* doc/emacs/android.texi (Android Environment): Correct list of permissions granted by default. * doc/lispref/os.texi (Desktop Notifications): Document the new function `android-notifications-notify' and its limitations. * java/AndroidManifest.xml.in: Request notification permissions. * java/org/gnu/emacs/EmacsDesktopNotification.java: New file. * java/res/layout/sdk8_notifications_view.xml: New file holding substitute notification widget definitions for Android versions prior to 3.0. * java/res/values/strings.xml: Remove inadvertently introduced tag attribute. * lisp/org/org-clock.el (haiku-notifications-notify): Correct file name in function declaration. (android-notifications-notify): New declaration. (org-show-notification): Use `android-notifications-notify'. * src/androidselect.c (android_init_emacs_desktop_notification) (android_notifications_notify_1, Fandroid_notifications_notify): New functions. (init_androidselect, syms_of_androidselect): Initialize new class and define new subr.
This commit is contained in:
parent
321f6bd572
commit
4f714dc081
8 changed files with 484 additions and 6 deletions
|
@ -491,6 +491,8 @@ permissions it has requested upon being installed:
|
|||
@code{android.permission.RECORD_AUDIO}
|
||||
@item
|
||||
@code{android.permission.CAMERA}
|
||||
@item
|
||||
@code{android.permission.POST_NOTIFICATIONS}
|
||||
@end itemize
|
||||
|
||||
While most of these permissions are left unused by Emacs itself, they
|
||||
|
@ -516,8 +518,6 @@ permissions upon installation:
|
|||
@code{android.permission.TRANSMIT_IR}
|
||||
@item
|
||||
@code{android.permission.WAKE_LOCK}
|
||||
@item
|
||||
@code{android.permission.POST_NOTIFICATIONS}
|
||||
@end itemize
|
||||
|
||||
Other permissions must be granted by the user through the system
|
||||
|
|
|
@ -2850,8 +2850,8 @@ Emacs is restarted by the session manager.
|
|||
@cindex notifications, on desktop
|
||||
|
||||
Emacs is able to send @dfn{notifications} on systems that support the
|
||||
freedesktop.org Desktop Notifications Specification, MS-Windows, and
|
||||
Haiku.
|
||||
freedesktop.org Desktop Notifications Specification, MS-Windows,
|
||||
Haiku, and Android.
|
||||
|
||||
In order to use this functionality on POSIX hosts, Emacs must have
|
||||
been compiled with D-Bus support, and the @code{notifications} library
|
||||
|
@ -3200,6 +3200,46 @@ be exploited as the @code{:replaces-id} parameter to a subsequent call
|
|||
to this function.
|
||||
@end defun
|
||||
|
||||
@cindex desktop notifications, Android
|
||||
When Emacs is built as an Android application package, displaying
|
||||
notifications is facilitated by the function
|
||||
@code{android-notifications-notify}. This function does not feature
|
||||
call-backs, and has several idiosyncrasies, when compared to
|
||||
@code{notifications-notify}.
|
||||
|
||||
@defun android-notifications-notify &rest params
|
||||
This function displays a desktop notification. @var{params} is a list
|
||||
of parameters analogous to its namesake in
|
||||
@code{notifications-notify}. The parameters are:
|
||||
|
||||
@table @code
|
||||
@item :title @var{title}
|
||||
@item :body @var{body}
|
||||
@item :replaces-id @var{replaces-id}
|
||||
These have the same meaning as they do when used in calls to
|
||||
@code{notifications-notify}.
|
||||
|
||||
@item :urgency @var{urgency}
|
||||
@item :group @var{group}
|
||||
These two parameters are ignored under Android 7.1 and earlier
|
||||
versions of the system. 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}.
|
||||
|
||||
If @var{group} is nil or not present within @var{params}, it is
|
||||
replaced by the string @samp{"Desktop Notifications"}.
|
||||
@end table
|
||||
|
||||
It returns a number identifying the notification, which may be
|
||||
supplied as the @code{:replaces-id} parameter to a later call to this
|
||||
function.
|
||||
|
||||
If Emacs is not afforded the permission to display notifications
|
||||
(@pxref{Android Environment,,, emacs, The GNU Emacs Manual}) under
|
||||
Android 13 and later, any notifications sent will be silently
|
||||
disregarded.
|
||||
@end defun
|
||||
|
||||
@node File Notifications
|
||||
@section Notifications on File Changes
|
||||
@cindex file notifications
|
||||
|
|
|
@ -66,6 +66,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
|
|||
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
|
||||
<!-- And under Android 13 or later to post desktop
|
||||
notifications. -->
|
||||
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<uses-sdk android:minSdkVersion="@ANDROID_MIN_SDK@"
|
||||
android:targetSdkVersion="33"/>
|
||||
|
||||
|
|
152
java/org/gnu/emacs/EmacsDesktopNotification.java
Normal file
152
java/org/gnu/emacs/EmacsDesktopNotification.java
Normal file
|
@ -0,0 +1,152 @@
|
|||
/* Communication module for Android terminals. -*- c-file-style: "GNU" -*-
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
package org.gnu.emacs;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.NotificationChannel;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
|
||||
|
||||
/* Structure designating a single desktop notification.
|
||||
|
||||
New versions of Android also organize notifications into individual
|
||||
``channels'', which are used to implement groups. Unlike on other
|
||||
systems, notification importance is set for each group, not for
|
||||
each individual notification. */
|
||||
|
||||
|
||||
|
||||
public final class EmacsDesktopNotification
|
||||
{
|
||||
/* The content of this desktop notification. */
|
||||
public final String content;
|
||||
|
||||
/* The title of this desktop notification. */
|
||||
public final String title;
|
||||
|
||||
/* The notification group. */
|
||||
public final String group;
|
||||
|
||||
/* String identifying this notification for future replacement.
|
||||
Typically a string resembling ``XXXX.NNNN.YYYY'', where XXXX is
|
||||
the system boot time, NNNN is the PID of this Emacs instance, and
|
||||
YYYY is the counter value returned by the notifications display
|
||||
function. */
|
||||
public final String tag;
|
||||
|
||||
/* The importance of this notification's group. */
|
||||
public final int importance;
|
||||
|
||||
public
|
||||
EmacsDesktopNotification (String title, String content,
|
||||
String group, String tag, int importance)
|
||||
{
|
||||
this.content = content;
|
||||
this.title = title;
|
||||
this.group = group;
|
||||
this.tag = tag;
|
||||
this.importance = importance;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Functions for displaying desktop notifications. */
|
||||
|
||||
/* Internal helper for `display' executed on the main thread. */
|
||||
|
||||
@SuppressWarnings ("deprecation") /* Notification.Builder (Context). */
|
||||
private void
|
||||
display1 (Context context)
|
||||
{
|
||||
NotificationManager manager;
|
||||
NotificationChannel channel;
|
||||
Notification notification;
|
||||
Object tem;
|
||||
RemoteViews contentView;
|
||||
|
||||
tem = context.getSystemService (Context.NOTIFICATION_SERVICE);
|
||||
manager = (NotificationManager) tem;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
{
|
||||
/* Create the notification channel for this group. If a group
|
||||
already exists with the same name, its linked attributes
|
||||
(such as its importance) will be overridden. */
|
||||
channel = new NotificationChannel (group, group, importance);
|
||||
manager.createNotificationChannel (channel);
|
||||
|
||||
/* Create a notification object and display it. */
|
||||
notification = (new Notification.Builder (context, group)
|
||||
.setContentTitle (title)
|
||||
.setContentText (content)
|
||||
.setSmallIcon (R.drawable.emacs)
|
||||
.build ());
|
||||
}
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
|
||||
notification = (new Notification.Builder (context)
|
||||
.setContentTitle (title)
|
||||
.setContentText (content)
|
||||
.setSmallIcon (R.drawable.emacs)
|
||||
.build ());
|
||||
else
|
||||
{
|
||||
notification = new Notification ();
|
||||
notification.icon = R.drawable.emacs;
|
||||
|
||||
/* This remote widget tree is defined in
|
||||
java/res/layout/sdk8_notifications_view.xml. */
|
||||
notification.contentView
|
||||
= contentView
|
||||
= new RemoteViews ("org.gnu.emacs",
|
||||
R.layout.sdk8_notifications_view);
|
||||
contentView.setTextViewText (R.id.sdk8_notifications_title,
|
||||
title);
|
||||
contentView.setTextViewText (R.id.sdk8_notifications_content,
|
||||
content);
|
||||
}
|
||||
|
||||
manager.notify (tag, 2, notification);
|
||||
}
|
||||
|
||||
/* Display this desktop notification.
|
||||
|
||||
Create a notification channel named GROUP or update its
|
||||
importance if such a channel is already defined. */
|
||||
|
||||
public void
|
||||
display ()
|
||||
{
|
||||
EmacsService.SERVICE.runOnUiThread (new Runnable () {
|
||||
@Override
|
||||
public void
|
||||
run ()
|
||||
{
|
||||
display1 (EmacsService.SERVICE);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
31
java/res/layout/sdk8_notifications_view.xml
Normal file
31
java/res/layout/sdk8_notifications_view.xml
Normal file
|
@ -0,0 +1,31 @@
|
|||
<!-- Notification content widget tree for GNU Emacs on Android 2.3.
|
||||
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
GNU Emacs is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dp">
|
||||
<TextView android:id="@+id/sdk8_notifications_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
<TextView android:id="@+id/sdk8_notifications_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
</LinearLayout>
|
|
@ -17,7 +17,7 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. -->
|
||||
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<resources>
|
||||
<string name="start_quick_title">
|
||||
Restart Emacs with -Q
|
||||
</string>
|
||||
|
|
|
@ -51,7 +51,8 @@
|
|||
(declare-function org-dynamic-block-define "org" (type func))
|
||||
(declare-function w32-notification-notify "w32fns.c" (&rest params))
|
||||
(declare-function w32-notification-close "w32fns.c" (&rest params))
|
||||
(declare-function haiku-notifications-notify "haikufns.c")
|
||||
(declare-function haiku-notifications-notify "haikuselect.c")
|
||||
(declare-function android-notifications-notify "androidselect.c")
|
||||
|
||||
(defvar org-frame-title-format-backup nil)
|
||||
(defvar org-state)
|
||||
|
@ -861,6 +862,13 @@ use libnotify if available, or fall back on a message."
|
|||
(haiku-notifications-notify :title "Org mode message"
|
||||
:body notification
|
||||
:urgency 'low))
|
||||
((fboundp 'android-notifications-notify)
|
||||
;; N.B. timeouts are not available under Haiku or Android.
|
||||
(android-notifications-notify :title "Org mode message"
|
||||
:body notification
|
||||
;; Low urgency notifications
|
||||
;; are by default hidden.
|
||||
:urgency 'normal))
|
||||
((fboundp 'w32-notification-notify)
|
||||
(let ((id (w32-notification-notify
|
||||
:title "Org mode message"
|
||||
|
|
|
@ -22,6 +22,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
#include <minmax.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boot-time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "lisp.h"
|
||||
#include "blockinput.h"
|
||||
#include "coding.h"
|
||||
|
@ -466,6 +469,232 @@ does not have any corresponding data. In that case, use
|
|||
|
||||
|
||||
|
||||
/* Desktop notifications. `android-desktop-notify' implements a
|
||||
facsimile of `notifications-notify'. */
|
||||
|
||||
/* Structure describing the EmacsDesktopNotification class. */
|
||||
|
||||
struct android_emacs_desktop_notification
|
||||
{
|
||||
jclass class;
|
||||
jmethodID init;
|
||||
jmethodID display;
|
||||
};
|
||||
|
||||
/* Methods provided by the EmacsDesktopNotification class. */
|
||||
static struct android_emacs_desktop_notification notification_class;
|
||||
|
||||
/* Initialize virtual function IDs and class pointers tied to the
|
||||
EmacsDesktopNotification class. */
|
||||
|
||||
static void
|
||||
android_init_emacs_desktop_notification (void)
|
||||
{
|
||||
jclass old;
|
||||
|
||||
notification_class.class
|
||||
= (*android_java_env)->FindClass (android_java_env,
|
||||
"org/gnu/emacs/EmacsDesktopNotification");
|
||||
eassert (notification_class.class);
|
||||
|
||||
old = notification_class.class;
|
||||
notification_class.class
|
||||
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
|
||||
old);
|
||||
ANDROID_DELETE_LOCAL_REF (old);
|
||||
|
||||
if (!notification_class.class)
|
||||
emacs_abort ();
|
||||
|
||||
#define FIND_METHOD(c_name, name, signature) \
|
||||
notification_class.c_name \
|
||||
= (*android_java_env)->GetMethodID (android_java_env, \
|
||||
notification_class.class, \
|
||||
name, signature); \
|
||||
assert (notification_class.c_name);
|
||||
|
||||
FIND_METHOD (init, "<init>", "(Ljava/lang/String;"
|
||||
"Ljava/lang/String;Ljava/lang/String;"
|
||||
"Ljava/lang/String;I)V");
|
||||
FIND_METHOD (display, "display", "()V");
|
||||
#undef FIND_METHOD
|
||||
}
|
||||
|
||||
/* Display a desktop notification with the provided TITLE, BODY,
|
||||
REPLACES_ID, GROUP and URGENCY. 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 urgency)
|
||||
{
|
||||
static intmax_t counter;
|
||||
intmax_t id;
|
||||
jstring title1, body1, group1, identifier1;
|
||||
jint type;
|
||||
jobject notification;
|
||||
char identifier[INT_STRLEN_BOUND (int)
|
||||
+ INT_STRLEN_BOUND (long int)
|
||||
+ INT_STRLEN_BOUND (intmax_t)
|
||||
+ sizeof "..."];
|
||||
struct timespec boot_time;
|
||||
|
||||
if (EQ (urgency, Qlow))
|
||||
type = 2; /* IMPORTANCE_LOW */
|
||||
else if (EQ (urgency, Qnormal))
|
||||
type = 3; /* IMPORTANCE_DEFAULT */
|
||||
else if (EQ (urgency, Qcritical))
|
||||
type = 4; /* IMPORTANCE_HIGH */
|
||||
else
|
||||
signal_error ("Invalid notification importance given", urgency);
|
||||
|
||||
if (NILP (replaces_id))
|
||||
{
|
||||
/* Generate a new identifier. */
|
||||
INT_ADD_WRAPV (counter, 1, &counter);
|
||||
id = counter;
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_INTEGER (replaces_id);
|
||||
if (!integer_to_intmax (replaces_id, &id))
|
||||
id = -1; /* Overflow. */
|
||||
}
|
||||
|
||||
/* Generate a unique identifier for this notification. Because
|
||||
Android persists notifications past system shutdown, also include
|
||||
the boot time within IDENTIFIER. Scale it down to avoid being
|
||||
perturbed by minor instabilities in the returned boot time,
|
||||
however. */
|
||||
|
||||
boot_time.tv_sec = 0;
|
||||
get_boot_time (&boot_time);
|
||||
sprintf (identifier, "%d.%ld.%jd", (int) getpid (),
|
||||
(long int) (boot_time.tv_sec / 2), id);
|
||||
|
||||
/* Encode all strings into their Java counterparts. */
|
||||
title1 = android_build_string (title);
|
||||
body1 = android_build_string (body);
|
||||
group1 = android_build_string (group);
|
||||
identifier1 = android_build_jstring (identifier);
|
||||
|
||||
/* Create the notification. */
|
||||
notification
|
||||
= (*android_java_env)->NewObject (android_java_env,
|
||||
notification_class.class,
|
||||
notification_class.init,
|
||||
title1, body1, group1,
|
||||
identifier1, type);
|
||||
android_exception_check_4 (title1, body1, group1, identifier1);
|
||||
|
||||
/* Delete unused local references. */
|
||||
ANDROID_DELETE_LOCAL_REF (title1);
|
||||
ANDROID_DELETE_LOCAL_REF (body1);
|
||||
ANDROID_DELETE_LOCAL_REF (group1);
|
||||
ANDROID_DELETE_LOCAL_REF (identifier1);
|
||||
|
||||
/* Display the notification. */
|
||||
(*android_java_env)->CallNonvirtualVoidMethod (android_java_env,
|
||||
notification,
|
||||
notification_class.class,
|
||||
notification_class.display);
|
||||
android_exception_check_1 (notification);
|
||||
ANDROID_DELETE_LOCAL_REF (notification);
|
||||
|
||||
/* Return the ID. */
|
||||
return id;
|
||||
}
|
||||
|
||||
DEFUN ("android-notifications-notify", Fandroid_notifications_notify,
|
||||
Sandroid_notifications_notify, 0, MANY, 0, doc:
|
||||
/* Display a desktop notification.
|
||||
ARGS must contain keywords followed by values. Each of the following
|
||||
keywords is understood:
|
||||
|
||||
:title The notification title.
|
||||
: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.
|
||||
|
||||
The notification group and urgency are 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. 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".
|
||||
|
||||
When the system is running Android 13 or later, notifications sent
|
||||
will be silently disregarded unless permission to display
|
||||
notifications is expressly granted from the "App Info" settings panel
|
||||
corresponding to Emacs.
|
||||
|
||||
A title and body must be supplied. Value is an integer (fixnum or
|
||||
bignum) uniquely designating the notification displayed, which may
|
||||
subsequently be specified as the `:replaces-id' of another call to
|
||||
this function.
|
||||
|
||||
usage: (android-notifications-notify &rest ARGS) */)
|
||||
(ptrdiff_t nargs, Lisp_Object *args)
|
||||
{
|
||||
Lisp_Object title, body, replaces_id, group, urgency;
|
||||
Lisp_Object key, value;
|
||||
ptrdiff_t i;
|
||||
|
||||
if (!android_init_gui)
|
||||
error ("No Android display connection!");
|
||||
|
||||
/* Clear each variable above. */
|
||||
title = body = replaces_id = group = urgency = Qnil;
|
||||
|
||||
/* If NARGS is odd, error. */
|
||||
|
||||
if (nargs & 1)
|
||||
error ("Odd number of arguments in call to `android-notifications-notify'");
|
||||
|
||||
/* Next, iterate through ARGS, searching for arguments. */
|
||||
|
||||
for (i = 0; i < nargs; i += 2)
|
||||
{
|
||||
key = args[i];
|
||||
value = args[i + 1];
|
||||
|
||||
if (EQ (key, QCtitle))
|
||||
title = value;
|
||||
else if (EQ (key, QCbody))
|
||||
body = value;
|
||||
else if (EQ (key, QCreplaces_id))
|
||||
replaces_id = value;
|
||||
else if (EQ (key, QCgroup))
|
||||
group = value;
|
||||
else if (EQ (key, QCurgency))
|
||||
urgency = value;
|
||||
}
|
||||
|
||||
/* Demand at least TITLE and BODY be present. */
|
||||
|
||||
if (NILP (title) || NILP (body))
|
||||
error ("Title or body not provided");
|
||||
|
||||
/* Now check the type and possibly expand each non-nil argument. */
|
||||
|
||||
CHECK_STRING (title);
|
||||
CHECK_STRING (body);
|
||||
|
||||
if (NILP (urgency))
|
||||
urgency = Qlow;
|
||||
|
||||
if (NILP (group))
|
||||
group = build_string ("Desktop Notifications");
|
||||
|
||||
return make_int (android_notifications_notify_1 (title, body, replaces_id,
|
||||
group, urgency));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
init_androidselect (void)
|
||||
{
|
||||
|
@ -476,6 +705,7 @@ init_androidselect (void)
|
|||
return;
|
||||
|
||||
android_init_emacs_clipboard ();
|
||||
android_init_emacs_desktop_notification ();
|
||||
|
||||
make_clipboard = clipboard_class.make_clipboard;
|
||||
tem
|
||||
|
@ -496,6 +726,16 @@ init_androidselect (void)
|
|||
void
|
||||
syms_of_androidselect (void)
|
||||
{
|
||||
DEFSYM (QCtitle, ":title");
|
||||
DEFSYM (QCbody, ":body");
|
||||
DEFSYM (QCreplaces_id, ":replaces-id");
|
||||
DEFSYM (QCgroup, ":group");
|
||||
DEFSYM (QCurgency, ":urgency");
|
||||
|
||||
DEFSYM (Qlow, "low");
|
||||
DEFSYM (Qnormal, "normal");
|
||||
DEFSYM (Qcritical, "critical");
|
||||
|
||||
defsubr (&Sandroid_clipboard_owner_p);
|
||||
defsubr (&Sandroid_set_clipboard);
|
||||
defsubr (&Sandroid_get_clipboard);
|
||||
|
@ -503,4 +743,6 @@ syms_of_androidselect (void)
|
|||
defsubr (&Sandroid_browse_url);
|
||||
defsubr (&Sandroid_get_clipboard_targets);
|
||||
defsubr (&Sandroid_get_clipboard_data);
|
||||
|
||||
defsubr (&Sandroid_notifications_notify);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue