Skip to content

Commit 308df31

Browse files
author
JonasT
authored
Merge pull request #1888 from JonasT/fix_forced_service_foreground2
Fix foreground notification being mandatory and more (attempt 2)
2 parents 8cf23aa + db6e735 commit 308df31

File tree

9 files changed

+134
-103
lines changed

9 files changed

+134
-103
lines changed

pythonforandroid/bootstraps/common/build/src/main/java/org/kivy/android/PythonService.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,11 @@ public class PythonService extends Service implements Runnable {
3535
private String pythonHome;
3636
private String pythonPath;
3737
private String serviceEntrypoint;
38+
private boolean serviceStartAsForeground;
3839
// Argument to pass to Python code,
3940
private String pythonServiceArgument;
41+
42+
4043
public static PythonService mService = null;
4144
private Intent startIntent = null;
4245

@@ -46,10 +49,6 @@ public void setAutoRestartService(boolean restart) {
4649
autoRestartService = restart;
4750
}
4851

49-
public boolean canDisplayNotification() {
50-
return true;
51-
}
52-
5352
public int startType() {
5453
return START_NOT_STICKY;
5554
}
@@ -79,18 +78,24 @@ public int onStartCommand(Intent intent, int flags, int startId) {
7978
pythonName = extras.getString("pythonName");
8079
pythonHome = extras.getString("pythonHome");
8180
pythonPath = extras.getString("pythonPath");
81+
serviceStartAsForeground = (
82+
extras.getString("serviceStartAsForeground") == "true"
83+
);
8284
pythonServiceArgument = extras.getString("pythonServiceArgument");
83-
8485
pythonThread = new Thread(this);
8586
pythonThread.start();
8687

87-
if (canDisplayNotification()) {
88+
if (serviceStartAsForeground) {
8889
doStartForeground(extras);
8990
}
9091

9192
return startType();
9293
}
9394

95+
protected int getServiceId() {
96+
return 1;
97+
}
98+
9499
protected void doStartForeground(Bundle extras) {
95100
String serviceTitle = extras.getString("serviceTitle");
96101
String serviceDescription = extras.getString("serviceDescription");
@@ -116,7 +121,7 @@ protected void doStartForeground(Bundle extras) {
116121
// for android 8+ we need to create our own channel
117122
// https://stackoverflow.com/questions/47531742/startforeground-fail-after-upgrade-to-android-8-1
118123
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a"; //TODO: make this configurable
119-
String channelName = "PythonSerice"; //TODO: make this configurable
124+
String channelName = "Background Service"; //TODO: make this configurable
120125
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,
121126
NotificationManager.IMPORTANCE_NONE);
122127

@@ -132,7 +137,7 @@ protected void doStartForeground(Bundle extras) {
132137
builder.setSmallIcon(context.getApplicationInfo().icon);
133138
notification = builder.build();
134139
}
135-
startForeground(1, notification);
140+
startForeground(getServiceId(), notification);
136141
}
137142

138143
@Override

pythonforandroid/bootstraps/common/build/templates/Service.tmpl.java

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
package {{ args.package }};
22

3-
import android.os.Build;
4-
import java.lang.reflect.Method;
5-
import java.lang.reflect.InvocationTargetException;
63
import android.content.Intent;
74
import android.content.Context;
8-
import android.app.Notification;
9-
import android.app.PendingIntent;
10-
import android.os.Bundle;
115
import org.kivy.android.PythonService;
12-
import org.kivy.android.PythonActivity;
136

147

158
public class Service{{ name|capitalize }} extends PythonService {
@@ -20,50 +13,21 @@ public int startType() {
2013
}
2114
{% endif %}
2215

23-
{% if not foreground %}
2416
@Override
25-
public boolean canDisplayNotification() {
26-
return false;
27-
}
28-
{% endif %}
29-
30-
@Override
31-
protected void doStartForeground(Bundle extras) {
32-
Notification notification;
33-
Context context = getApplicationContext();
34-
Intent contextIntent = new Intent(context, PythonActivity.class);
35-
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
36-
PendingIntent.FLAG_UPDATE_CURRENT);
37-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
38-
notification = new Notification(
39-
context.getApplicationInfo().icon, "{{ args.name }}", System.currentTimeMillis());
40-
try {
41-
// prevent using NotificationCompat, this saves 100kb on apk
42-
Method func = notification.getClass().getMethod(
43-
"setLatestEventInfo", Context.class, CharSequence.class,
44-
CharSequence.class, PendingIntent.class);
45-
func.invoke(notification, context, "{{ args.name }}", "{{ name| capitalize }}", pIntent);
46-
} catch (NoSuchMethodException | IllegalAccessException |
47-
IllegalArgumentException | InvocationTargetException e) {
48-
}
49-
} else {
50-
Notification.Builder builder = new Notification.Builder(context);
51-
builder.setContentTitle("{{ args.name }}");
52-
builder.setContentText("{{ name| capitalize }}");
53-
builder.setContentIntent(pIntent);
54-
builder.setSmallIcon(context.getApplicationInfo().icon);
55-
notification = builder.build();
56-
}
57-
startForeground({{ service_id }}, notification);
17+
protected int getServiceId() {
18+
return {{ service_id }};
5819
}
5920

6021
static public void start(Context ctx, String pythonServiceArgument) {
6122
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
6223
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
6324
intent.putExtra("androidPrivate", ctx.getFilesDir().getAbsolutePath());
6425
intent.putExtra("androidArgument", argument);
26+
intent.putExtra("serviceTitle", "{{ args.name }}");
27+
intent.putExtra("serviceDescription", "{{ name|capitalize }}");
6528
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
6629
intent.putExtra("pythonName", "{{ name }}");
30+
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
6731
intent.putExtra("pythonHome", argument);
6832
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
6933
intent.putExtra("pythonServiceArgument", pythonServiceArgument);

pythonforandroid/bootstraps/sdl2/build/src/main/java/org/kivy/android/PythonActivity.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,8 +365,32 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
365365
}
366366
}
367367

368-
public static void start_service(String serviceTitle, String serviceDescription,
369-
String pythonServiceArgument) {
368+
public static void start_service(
369+
String serviceTitle,
370+
String serviceDescription,
371+
String pythonServiceArgument
372+
) {
373+
_do_start_service(
374+
serviceTitle, serviceDescription, pythonServiceArgument, true
375+
);
376+
}
377+
378+
public static void start_service_not_as_foreground(
379+
String serviceTitle,
380+
String serviceDescription,
381+
String pythonServiceArgument
382+
) {
383+
_do_start_service(
384+
serviceTitle, serviceDescription, pythonServiceArgument, false
385+
);
386+
}
387+
388+
public static void _do_start_service(
389+
String serviceTitle,
390+
String serviceDescription,
391+
String pythonServiceArgument,
392+
boolean showForegroundNotification
393+
) {
370394
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
371395
String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath();
372396
String filesDirectory = argument;
@@ -378,6 +402,9 @@ public static void start_service(String serviceTitle, String serviceDescription,
378402
serviceIntent.putExtra("pythonName", "python");
379403
serviceIntent.putExtra("pythonHome", app_root_dir);
380404
serviceIntent.putExtra("pythonPath", app_root_dir + ":" + app_root_dir + "/lib");
405+
serviceIntent.putExtra("serviceStartAsForeground",
406+
(showForegroundNotification ? "true" : "false")
407+
);
381408
serviceIntent.putExtra("serviceTitle", serviceTitle);
382409
serviceIntent.putExtra("serviceDescription", serviceDescription);
383410
serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument);

pythonforandroid/bootstraps/service_only/build/src/main/java/org/kivy/android/PythonActivity.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,8 +380,32 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
380380
}
381381
}
382382

383-
public static void start_service(String serviceTitle, String serviceDescription,
384-
String pythonServiceArgument) {
383+
public static void start_service(
384+
String serviceTitle,
385+
String serviceDescription,
386+
String pythonServiceArgument
387+
) {
388+
_do_start_service(
389+
serviceTitle, serviceDescription, pythonServiceArgument, true
390+
);
391+
}
392+
393+
public static void start_service_not_as_foreground(
394+
String serviceTitle,
395+
String serviceDescription,
396+
String pythonServiceArgument
397+
) {
398+
_do_start_service(
399+
serviceTitle, serviceDescription, pythonServiceArgument, false
400+
);
401+
}
402+
403+
public static void _do_start_service(
404+
String serviceTitle,
405+
String serviceDescription,
406+
String pythonServiceArgument,
407+
boolean showForegroundNotification
408+
) {
385409
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
386410
String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath();
387411
String filesDirectory = argument;
@@ -393,6 +417,9 @@ public static void start_service(String serviceTitle, String serviceDescription,
393417
serviceIntent.putExtra("pythonName", "python");
394418
serviceIntent.putExtra("pythonHome", app_root_dir);
395419
serviceIntent.putExtra("pythonPath", app_root_dir + ":" + app_root_dir + "/lib");
420+
serviceIntent.putExtra("serviceStartAsForeground",
421+
(showForegroundNotification ? "true" : "false")
422+
);
396423
serviceIntent.putExtra("serviceTitle", serviceTitle);
397424
serviceIntent.putExtra("serviceDescription", serviceDescription);
398425
serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument);

pythonforandroid/bootstraps/service_only/build/templates/Service.tmpl.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,10 @@ public int startType() {
2222
}
2323
{% endif %}
2424

25-
{% if foreground %}
26-
/**
27-
* {@inheritDoc}
28-
*/
2925
@Override
30-
public boolean getStartForeground() {
31-
return true;
26+
protected int getServiceId() {
27+
return {{ service_id }};
3228
}
33-
{% endif %}
3429

3530
public static void start(Context ctx, String pythonServiceArgument) {
3631
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
@@ -41,6 +36,7 @@ public static void start(Context ctx, String pythonServiceArgument) {
4136
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
4237
intent.putExtra("serviceDescription", "");
4338
intent.putExtra("pythonName", "{{ name }}");
39+
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
4440
intent.putExtra("pythonHome", argument);
4541
intent.putExtra("androidUnpack", argument);
4642
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");

pythonforandroid/bootstraps/webview/build/src/main/java/org/kivy/android/PythonActivity.java

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -437,8 +437,32 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
437437
}
438438
}
439439

440-
public static void start_service(String serviceTitle, String serviceDescription,
441-
String pythonServiceArgument) {
440+
public static void start_service(
441+
String serviceTitle,
442+
String serviceDescription,
443+
String pythonServiceArgument
444+
) {
445+
_do_start_service(
446+
serviceTitle, serviceDescription, pythonServiceArgument, true
447+
);
448+
}
449+
450+
public static void start_service_not_as_foreground(
451+
String serviceTitle,
452+
String serviceDescription,
453+
String pythonServiceArgument
454+
) {
455+
_do_start_service(
456+
serviceTitle, serviceDescription, pythonServiceArgument, false
457+
);
458+
}
459+
460+
public static void _do_start_service(
461+
String serviceTitle,
462+
String serviceDescription,
463+
String pythonServiceArgument,
464+
boolean showForegroundNotification
465+
) {
442466
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
443467
String argument = PythonActivity.mActivity.getFilesDir().getAbsolutePath();
444468
String filesDirectory = argument;
@@ -450,6 +474,9 @@ public static void start_service(String serviceTitle, String serviceDescription,
450474
serviceIntent.putExtra("pythonName", "python");
451475
serviceIntent.putExtra("pythonHome", app_root_dir);
452476
serviceIntent.putExtra("pythonPath", app_root_dir + ":" + app_root_dir + "/lib");
477+
serviceIntent.putExtra("serviceStartAsForeground",
478+
(showForegroundNotification ? "true" : "false")
479+
);
453480
serviceIntent.putExtra("serviceTitle", serviceTitle);
454481
serviceIntent.putExtra("serviceDescription", serviceDescription);
455482
serviceIntent.putExtra("pythonServiceArgument", pythonServiceArgument);

pythonforandroid/recipes/android/src/android/_android.pyx

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -280,17 +280,29 @@ class AndroidBrowser(object):
280280
import webbrowser
281281
webbrowser.register('android', AndroidBrowser)
282282

283-
cdef extern void android_start_service(char *, char *, char *)
284-
def start_service(title=None, description=None, arg=None):
285-
cdef char *j_title = NULL
286-
cdef char *j_description = NULL
287-
if title is not None:
288-
j_title = <bytes>title
289-
if description is not None:
290-
j_description = <bytes>description
291-
if arg is not None:
292-
j_arg = <bytes>arg
293-
android_start_service(j_title, j_description, j_arg)
283+
284+
def start_service(title="Background Service",
285+
description="", arg="",
286+
as_foreground=True):
287+
# Legacy None value support (for old function signature style):
288+
if title is None:
289+
title = "Background Service"
290+
if description is None:
291+
description = ""
292+
if arg is None:
293+
arg = ""
294+
295+
# Start service:
296+
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
297+
if as_foreground:
298+
mActivity.start_service(
299+
title, description, arg
300+
)
301+
else:
302+
mActivity.start_service_not_as_foreground(
303+
title, description, arg
304+
)
305+
294306

295307
cdef extern void android_stop_service()
296308
def stop_service():

pythonforandroid/recipes/android/src/android/_android_jni.c

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -201,34 +201,6 @@ void android_get_buildinfo() {
201201
}
202202
}
203203

204-
void android_start_service(char *title, char *description, char *arg) {
205-
static JNIEnv *env = NULL;
206-
static jclass *cls = NULL;
207-
static jmethodID mid = NULL;
208-
209-
if (env == NULL) {
210-
env = SDL_ANDROID_GetJNIEnv();
211-
aassert(env);
212-
cls = (*env)->FindClass(env, JNI_NAMESPACE "/PythonActivity");
213-
aassert(cls);
214-
mid = (*env)->GetStaticMethodID(env, cls, "start_service",
215-
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
216-
aassert(mid);
217-
}
218-
219-
jstring j_title = NULL;
220-
jstring j_description = NULL;
221-
jstring j_arg = NULL;
222-
if ( title != 0 )
223-
j_title = (*env)->NewStringUTF(env, title);
224-
if ( description != 0 )
225-
j_description = (*env)->NewStringUTF(env, description);
226-
if ( arg != 0 )
227-
j_arg = (*env)->NewStringUTF(env, arg);
228-
229-
(*env)->CallStaticVoidMethod(env, cls, mid, j_title, j_description, j_arg);
230-
}
231-
232204
void android_stop_service() {
233205
static JNIEnv *env = NULL;
234206
static jclass *cls = NULL;

tests/test_distribution.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,12 @@ def test_folder_exist(self, mock_exists):
8484
:meth:`~pythonforandroid.distribution.Distribution.folder_exist` is
8585
called once with the proper arguments."""
8686

87+
mock_exists.return_value = False
8788
self.setUp_distribution_with_bootstrap(
88-
Bootstrap().get_bootstrap("sdl2", self.ctx)
89+
Bootstrap.get_bootstrap("sdl2", self.ctx)
8990
)
9091
self.ctx.bootstrap.distribution.folder_exists()
91-
mock_exists.assert_called_once_with(
92+
mock_exists.assert_called_with(
9293
self.ctx.bootstrap.distribution.dist_dir
9394
)
9495

0 commit comments

Comments
 (0)