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!))))))