diff --git a/modules/androidforeground/ANDROID_c_additions b/modules/androidforeground/ANDROID_c_additions
new file mode 100644
index 00000000..d20a9312
--- /dev/null
+++ b/modules/androidforeground/ANDROID_c_additions
@@ -0,0 +1,21 @@
+/* -*-C-*- */
+
+void android_start_ln_foreground_service()
+{
+ JNIEnv *env = GetJNIEnv();
+ jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
+ if (env&&globalObj){
+ jmethodID method = (*env)->GetMethodID(env, main_class, "startLnForegroundService", "()V");
+ (*env)->CallVoidMethod(env, globalObj, method);
+ }
+}
+
+void android_stop_ln_foreground_service()
+{
+ JNIEnv *env = GetJNIEnv();
+ jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
+ if (env&&globalObj){
+ jmethodID method = (*env)->GetMethodID(env, main_class, "stopLnForegroundService", "()V");
+ (*env)->CallVoidMethod(env, globalObj, method);
+ }
+}
diff --git a/modules/androidforeground/ANDROID_c_defines b/modules/androidforeground/ANDROID_c_defines
new file mode 100644
index 00000000..a9b41c20
--- /dev/null
+++ b/modules/androidforeground/ANDROID_c_defines
@@ -0,0 +1,6 @@
+/* -*-C-*- */
+
+void Java_@SYS_PACKAGE_UNDERSCORE@_LambdaNativeForegroundService_nativeEvent(JNIEnv* e, jobject o, jint t, jint x, jint y){
+ if ((*e)->ExceptionCheck(e)) return;
+ ffi_event((int)t,(int)x,(int)y);
+}
diff --git a/modules/androidforeground/ANDROID_java_activityadditions b/modules/androidforeground/ANDROID_java_activityadditions
new file mode 100644
index 00000000..51243b7f
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_activityadditions
@@ -0,0 +1,31 @@
+/* -*-java-*- */
+void startLnForegroundService() {
+ /* API 26+: In order to compile for prior API versions comment out
+ * the following attempt to disable battery optimizations
+ */
+ @IF_ANDROIDAPI_GT_22@
+ if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1) {
+ String pkg=getPackageName();
+ PowerManager pm=getSystemService(PowerManager.class);
+ if(!pm.isIgnoringBatteryOptimizations(pkg)) {
+ // See also the comment in ANDROID_xml_permissions: Google may
+ // not like the required
+ // ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS permission
+ // being used.
+ //
+ // If it is not requested in the permissions file,
+ // uncomment the following startActivityForResult(...) and
+ // comment out startActivity(...) in the line after.
+
+ // startActivityForResult(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS), 0);
+ startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:"+pkg)));
+ }
+ }
+ // end of IF_ANDROIDAPI_GT_22 */
+
+ startService(new Intent(this, LambdaNativeForegroundService.class));
+}
+
+void stopLnForegroundService() {
+ stopService(new Intent(this, LambdaNativeForegroundService.class));
+}
diff --git a/modules/androidforeground/ANDROID_java_imports b/modules/androidforeground/ANDROID_java_imports
new file mode 100644
index 00000000..96c2540e
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_imports
@@ -0,0 +1,2 @@
+import android.provider.Settings;
+import android.os.Build;
diff --git a/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService
new file mode 100644
index 00000000..a038e99b
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService
@@ -0,0 +1,76 @@
+/* -*-java-*- */
+
+import android.util.Log;
+import android.app.Service;
+import android.app.Notification;
+import android.app.Notification.Builder;
+//import android.support.v4.app.NotificationCompat;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+
+public class LambdaNativeForegroundService extends Service {
+ final static int notificationIsRunningId = 1;
+ boolean running=true;
+ Thread backgroundThread;
+ public LambdaNativeForegroundService() {
+ }
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+ @Override
+ public void onCreate() {
+// Log.d("","LambdaNativeForegroundService created");
+ }
+ private void bgActivity() {
+// Log.d("","LambdaNativeForegroundService started");
+ backgroundThread = new Thread() {
+ public void run() {
+ // setPriority(Thread.MAX_PRIORITY);
+ setPriority(Thread.MIN_PRIORITY);
+ while (running) {
+// Log.d("", "LambdaNativeForegroundService EVENT_IDLE");
+// nativeEvent(19,0,0); // EVENT_IDLE
+
+ // SystemClock.sleep(30000); // should be 30 seconds i.e. 30000 ms
+ try {
+ this.sleep(30000); // should be 30 seconds i.e. 30000 ms
+ try {
+ nativeEvent(19,0,0); // EVENT_IDLE
+ } catch (Throwable e) {
+ Log.e("LambdaNativeForegroundService", "exception: " + e.toString());
+ }
+ } catch (InterruptedException e) {}
+ }
+// Log.d("","LambdaNativeForegroundService thread stopped");
+ }
+ };
+ backgroundThread.start();
+ }
+ @Override
+ public void onStart(Intent intent, int startId) {
+// Log.d("","LambdaNativeForegroundService starting");
+
+ Notification notification = new Notification.Builder(this)
+ .setContentTitle(getString(R.string.app_name))
+ // .setContentText("TBD")
+ .setSmallIcon(R.drawable.icon)
+ // .setLargeIcon(aBitmap)
+ .setOngoing(true)
+ .build();
+
+ startForeground(notificationIsRunningId, notification);
+ bgActivity();
+ }
+ @Override public int onStartCommand(Intent intent, int flags, int startId) {
+ super.onStartCommand(intent, flags, startId);
+ return START_STICKY;
+ }
+ @Override
+ public void onDestroy() {
+ // running=false;
+// Log.d("","LambdaNativeForegroundService stopped");
+ }
+ native void nativeEvent(int t, int x, int y);
+}
diff --git a/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService.in b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService.in
new file mode 100644
index 00000000..96cb494f
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService.in
@@ -0,0 +1,78 @@
+/* -*-java-*- */
+
+package @SYS_PACKAGE_DOT@;
+@IF_ANDROIDAPI_GT_25@
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+/* end of IF_ANDROIDAPI_GT_25 */
+
+import android.util.Log;
+import android.app.Service;
+import android.app.Notification;
+import android.app.Notification.Builder;
+
+//import android.support.v4.app.NotificationCompat;
+
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.SystemClock;
+
+public class LambdaNativeForegroundService extends Service {
+ final static int notificationIsRunningId = 1;
+ boolean running=true;
+ Thread backgroundThread;
+ public LambdaNativeForegroundService() {
+ }
+ private Notification.Builder make_notification_template() {
+ return new Notification.Builder(this)
+ .setContentTitle(getString(R.string.app_name))
+ // .setContentText("TBD")
+ .setSmallIcon(R.drawable.icon)
+ // .setLargeIcon(aBitmap)
+ .setOngoing(true);
+ }
+ private void keepAwake_LT_API26() {
+ startForeground(notificationIsRunningId, make_notification_template().build());
+ }
+ private void keepAwake() {
+ @IF_ANDROIDAPI_GT_25@
+ if(true) {
+ NotificationManager mgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ assert mgr != null;
+ NotificationChannel channel =
+ new NotificationChannel ("@SYS_PACKAGE_DOT@", ".working", NotificationManager.IMPORTANCE_NONE);
+ mgr.createNotificationChannel(channel);
+ Notification.Builder mknote = make_notification_template()
+ .setChannelId("@SYS_PACKAGE_DOT@")
+ .setCategory(Notification.CATEGORY_SERVICE);
+ startForeground(notificationIsRunningId, mknote.build());
+ return;
+ }
+ /* end of IF_ANDROIDAPI_GT_25 */
+ keepAwake_LT_API26();
+ }
+ @Override
+ public IBinder onBind(Intent intent) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+ @Override
+ public void onCreate() {
+// Log.d("","LambdaNativeForegroundService created");
+ super.onCreate();
+ keepAwake();
+ }
+ @Override
+ public void onStart(Intent intent, int startId) {
+// Log.d("","LambdaNativeForegroundService starting");
+ }
+ @Override public int onStartCommand(Intent intent, int flags, int startId) {
+ super.onStartCommand(intent, flags, startId);
+ return START_STICKY;
+ }
+ @Override
+ public void onDestroy() {
+ // running=false;
+// Log.d("","LambdaNativeForegroundService stopped");
+ }
+ // This is bound in the main class only!!! native void nativeEvent(int t, int x, int y);
+}
diff --git a/modules/androidforeground/ANDROID_xml_permissions b/modules/androidforeground/ANDROID_xml_permissions
new file mode 100644
index 00000000..60eb79fb
--- /dev/null
+++ b/modules/androidforeground/ANDROID_xml_permissions
@@ -0,0 +1,17 @@
+
+
+
+
+
diff --git a/modules/androidforeground/ANDROID_xml_services b/modules/androidforeground/ANDROID_xml_services
new file mode 100644
index 00000000..61a36949
--- /dev/null
+++ b/modules/androidforeground/ANDROID_xml_services
@@ -0,0 +1 @@
+
diff --git a/modules/androidforeground/androidforeground.scm b/modules/androidforeground/androidforeground.scm
new file mode 100644
index 00000000..90291a2b
--- /dev/null
+++ b/modules/androidforeground/androidforeground.scm
@@ -0,0 +1,18 @@
+;; this module creates an android service to drive the native lambdanative payload in the background
+
+(define foreground-service!
+ (let ((running #f)
+ (start! (c-lambda () void "
+#if defined(__ANDROID__)
+ android_start_ln_foreground_service();
+#endif
+"))
+ (stop! (c-lambda () void "
+#if defined(__ANDROID__)
+ android_stop_ln_foreground_service();
+#endif
+")))
+ (lambda (flag)
+ (cond
+ ((and flag (not running)) (set! running #t) (start!))
+ ((and (not flag) running) (set! running #f) (stop!))))))