diff --git a/modules/androidforeground/ANDROID_c_additions b/modules/androidforeground/ANDROID_c_additions
new file mode 100644
index 00000000..35d11590
--- /dev/null
+++ b/modules/androidforeground/ANDROID_c_additions
@@ -0,0 +1,39 @@
+/* androidforeground -*-C-*- */
+
+int android_start_ln_foreground_service()
+{
+ JNIEnv *env = GetJNIEnv();
+ if (env&&globalObj){
+ jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
+ jmethodID method = main_class ? (*env)->GetMethodID(env, main_class, "startLnForegroundService", "()V") : NULL;
+ if(main_class) (*env)->DeleteLocalRef(env, main_class);
+ if(!method) {
+ JNI_forward_exception_to_gambit(env);
+ return -1;
+ }
+ (*env)->CallVoidMethod(env, globalObj, method);
+ (*env)->DeleteLocalRef(env, method);
+ if(JNI_forward_exception_to_gambit(env)) { return -2; }
+ return 0;
+ }
+}
+
+int android_stop_ln_foreground_service()
+{
+ JNIEnv *env = GetJNIEnv();
+ if (env&&globalObj){
+ jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
+ jmethodID method = main_class ? (*env)->GetMethodID(env, main_class, "stopLnForegroundService", "()V") : NULL;
+ if(main_class) (*env)->DeleteLocalRef(env, main_class);
+ if(!method) {
+ JNI_forward_exception_to_gambit(env);
+ return -1;
+ }
+ (*env)->CallVoidMethod(env, globalObj, method);
+ (*env)->DeleteLocalRef(env, method);
+ if(JNI_forward_exception_to_gambit(env)) { return -2; }
+ return 0;
+ }
+}
+
+/* EOF androidforeground */
diff --git a/modules/androidforeground/ANDROID_java_activityadditions b/modules/androidforeground/ANDROID_java_activityadditions
new file mode 100644
index 00000000..b57396e7
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_activityadditions
@@ -0,0 +1,34 @@
+/* androidforeground -*- mode: java; c-basic-offset: 2; -*- */
+
+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));
+}
+
+/* EOF androidforeground */
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.in b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService.in
new file mode 100644
index 00000000..5e41ba08
--- /dev/null
+++ b/modules/androidforeground/ANDROID_java_public_LambdaNativeForegroundService.in
@@ -0,0 +1,78 @@
+/* -*- mode: java; c-basic-offset: 2; -*- */
+
+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..bed9072d
--- /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..a423b116
--- /dev/null
+++ b/modules/androidforeground/androidforeground.scm
@@ -0,0 +1,37 @@
+;; this module creates an android service to drive the native lambdanative payload in the background
+
+;; Usage:
+;;
+;; (foreground-service! #t) ;; start service
+;;
+;; (foreground-service! #f) ;; stop service
+
+(c-declare "int android_start_ln_foreground_service();")
+(c-declare "int android_stop_ln_foreground_service();")
+
+(define foreground-service!
+ (let ((running #f)
+ (start! (c-lambda () int "
+#if defined(__ANDROID__)
+ ___return(android_start_ln_foreground_service());
+#else
+ ___return(0);
+#endif
+"))
+ (stop! (c-lambda () int "
+#if defined(__ANDROID__)
+ ___return(android_stop_ln_foreground_service());
+#else
+ ___return(0);
+#endif
+")))
+ (lambda (flag)
+ (cond
+ ((and flag (not running))
+ (set! running #t)
+ (let ((result (start!)))
+ (when (negative? result) (log-error "foreground-service! failed to start " result))))
+ ((and (not flag) running)
+ (set! running #f)
+ (let ((result (stop!)))
+ (when (negative? result) (log-error "foreground-service! failed to stop " result))))))))