Skip to content

Commit c4a2478

Browse files
committed
ANDROID: new module androidforeground
In order to avoid being killed by Android apps are supposed to register a notification/service. Usage: (foreground-service! #t) ;; start service (foreground-service! #f) ;; stop service
1 parent 581cb63 commit c4a2478

File tree

7 files changed

+208
-0
lines changed

7 files changed

+208
-0
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/* androidforeground -*-C-*- */
2+
3+
int android_start_ln_foreground_service()
4+
{
5+
JNIEnv *env = GetJNIEnv();
6+
if (env&&globalObj){
7+
jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
8+
jmethodID method = main_class ? (*env)->GetMethodID(env, main_class, "startLnForegroundService", "()V") : NULL;
9+
if(main_class) (*env)->DeleteLocalRef(env, main_class);
10+
if(!method) {
11+
JNI_forward_exception_to_gambit(env);
12+
return -1;
13+
}
14+
(*env)->CallVoidMethod(env, globalObj, method);
15+
(*env)->DeleteLocalRef(env, method);
16+
if(JNI_forward_exception_to_gambit(env)) { return -2; }
17+
return 0;
18+
}
19+
}
20+
21+
int android_stop_ln_foreground_service()
22+
{
23+
JNIEnv *env = GetJNIEnv();
24+
if (env&&globalObj){
25+
jclass main_class = (*env)->FindClass(env, "@SYS_PACKAGE_SLASH@/@SYS_APPNAME@");
26+
jmethodID method = main_class ? (*env)->GetMethodID(env, main_class, "stopLnForegroundService", "()V") : NULL;
27+
if(main_class) (*env)->DeleteLocalRef(env, main_class);
28+
if(!method) {
29+
JNI_forward_exception_to_gambit(env);
30+
return -1;
31+
}
32+
(*env)->CallVoidMethod(env, globalObj, method);
33+
(*env)->DeleteLocalRef(env, method);
34+
if(JNI_forward_exception_to_gambit(env)) { return -2; }
35+
return 0;
36+
}
37+
}
38+
39+
/* EOF androidforeground */
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* androidforeground -*- mode: java; c-basic-offset: 2; -*- */
2+
3+
void startLnForegroundService() {
4+
/* API 26+: In order to compile for prior API versions comment out
5+
* the following attempt to disable battery optimizations
6+
*/
7+
@IF_ANDROIDAPI_GT_22@
8+
if(Build.VERSION.SDK_INT>Build.VERSION_CODES.LOLLIPOP_MR1) {
9+
String pkg=getPackageName();
10+
PowerManager pm=getSystemService(PowerManager.class);
11+
if(!pm.isIgnoringBatteryOptimizations(pkg)) {
12+
// See also the comment in ANDROID_xml_permissions: Google may
13+
// not like the required
14+
// ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS permission
15+
// being used.
16+
//
17+
// If it is not requested in the permissions file,
18+
// uncomment the following startActivityForResult(...) and
19+
// comment out startActivity(...) in the line after.
20+
21+
// startActivityForResult(new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS), 0);
22+
startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).setData(Uri.parse("package:"+pkg)));
23+
}
24+
}
25+
// end of IF_ANDROIDAPI_GT_22 */
26+
27+
startService(new Intent(this, LambdaNativeForegroundService.class));
28+
}
29+
30+
void stopLnForegroundService() {
31+
stopService(new Intent(this, LambdaNativeForegroundService.class));
32+
}
33+
34+
/* EOF androidforeground */
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import android.provider.Settings;
2+
import android.os.Build;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/* -*- mode: java; c-basic-offset: 2; -*- */
2+
3+
package @SYS_PACKAGE_DOT@;
4+
@IF_ANDROIDAPI_GT_25@
5+
import android.app.NotificationChannel;
6+
import android.app.NotificationManager;
7+
/* end of IF_ANDROIDAPI_GT_25 */
8+
9+
import android.util.Log;
10+
import android.app.Service;
11+
import android.app.Notification;
12+
import android.app.Notification.Builder;
13+
14+
//import android.support.v4.app.NotificationCompat;
15+
16+
import android.content.Intent;
17+
import android.os.IBinder;
18+
import android.os.SystemClock;
19+
20+
public class LambdaNativeForegroundService extends Service {
21+
final static int notificationIsRunningId = 1;
22+
boolean running=true;
23+
Thread backgroundThread;
24+
public LambdaNativeForegroundService() {
25+
}
26+
private Notification.Builder make_notification_template() {
27+
return new Notification.Builder(this)
28+
.setContentTitle(getString(R.string.app_name))
29+
// .setContentText("TBD")
30+
.setSmallIcon(R.drawable.icon)
31+
// .setLargeIcon(aBitmap)
32+
.setOngoing(true);
33+
}
34+
private void keepAwake_LT_API26() {
35+
startForeground(notificationIsRunningId, make_notification_template().build());
36+
}
37+
private void keepAwake() {
38+
@IF_ANDROIDAPI_GT_25@
39+
if(true) {
40+
NotificationManager mgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
41+
assert mgr != null;
42+
NotificationChannel channel =
43+
new NotificationChannel ("@SYS_PACKAGE_DOT@", ".working", NotificationManager.IMPORTANCE_NONE);
44+
mgr.createNotificationChannel(channel);
45+
Notification.Builder mknote = make_notification_template()
46+
.setChannelId("@SYS_PACKAGE_DOT@")
47+
.setCategory(Notification.CATEGORY_SERVICE);
48+
startForeground(notificationIsRunningId, mknote.build());
49+
return;
50+
}
51+
/* end of IF_ANDROIDAPI_GT_25 */
52+
keepAwake_LT_API26();
53+
}
54+
@Override
55+
public IBinder onBind(Intent intent) {
56+
throw new UnsupportedOperationException("Not implemented");
57+
}
58+
@Override
59+
public void onCreate() {
60+
// Log.d("","LambdaNativeForegroundService created");
61+
super.onCreate();
62+
keepAwake();
63+
}
64+
@Override
65+
public void onStart(Intent intent, int startId) {
66+
// Log.d("","LambdaNativeForegroundService starting");
67+
}
68+
@Override public int onStartCommand(Intent intent, int flags, int startId) {
69+
super.onStartCommand(intent, flags, startId);
70+
return START_STICKY;
71+
}
72+
@Override
73+
public void onDestroy() {
74+
// running=false;
75+
// Log.d("","LambdaNativeForegroundService stopped");
76+
}
77+
// This is bound in the main class only!!! native void nativeEvent(int t, int x, int y);
78+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<uses-feature android:name="android.permission.FOREGROUND_SERVICE" android:required="true" />
2+
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" android:required="false" />
3+
<!--
4+
5+
With API level 26 REQUEST_IGNORE_BATTERY_OPTIMIZATIONS might be
6+
appropriate to enable services to continuesly run.
7+
8+
However: Google is reported to remove apps needing this permission:
9+
https://commonsware.com/blog/2015/11/11/google-anti-trust-issues.html
10+
11+
If this is bothering you, remove this comment and the permission below
12+
and modify ANDROID_java_activityadditions to use the alternative,
13+
- though rather impractical - method.
14+
15+
-->
16+
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" android:required="false" />
17+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<service android:name=".LambdaNativeForegroundService" android:enabled="true" />
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
;; this module creates an android service to drive the native lambdanative payload in the background
2+
3+
;; Usage:
4+
;;
5+
;; (foreground-service! #t) ;; start service
6+
;;
7+
;; (foreground-service! #f) ;; stop service
8+
9+
(c-declare "int android_start_ln_foreground_service();")
10+
(c-declare "int android_stop_ln_foreground_service();")
11+
12+
(define foreground-service!
13+
(let ((running #f)
14+
(start! (c-lambda () int "
15+
#if defined(__ANDROID__)
16+
___return(android_start_ln_foreground_service());
17+
#else
18+
___return(0);
19+
#endif
20+
"))
21+
(stop! (c-lambda () int "
22+
#if defined(__ANDROID__)
23+
___return(android_stop_ln_foreground_service());
24+
#else
25+
___return(0);
26+
#endif
27+
")))
28+
(lambda (flag)
29+
(cond
30+
((and flag (not running))
31+
(set! running #t)
32+
(let ((result (start!)))
33+
(when (negative? result) (log-error "foreground-service! failed to start " result))))
34+
((and (not flag) running)
35+
(set! running #f)
36+
(let ((result (stop!)))
37+
(when (negative? result) (log-error "foreground-service! failed to stop " result))))))))

0 commit comments

Comments
 (0)