Skip to content

Commit 8cb497d

Browse files
authored
Custom Service notification (#2703)
* add_resources * add_resource * Update build.py * stateless * multiple kinds * pep8 * --add_resource * Custom notification * Update Service.tmpl.java * Custom Notification * Custom Notification * service notification * customize notification * share code * share code * Update Service.tmpl.java
1 parent 10fa82b commit 8cb497d

File tree

5 files changed

+110
-23
lines changed

5 files changed

+110
-23
lines changed

doc/source/services.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,14 @@ the json module to encode and decode more complex data.
107107

108108
from os import environ
109109
argument = environ.get('PYTHON_SERVICE_ARGUMENT', '')
110+
111+
To customize the notification icon, title, and text use three optional
112+
arguments to service.start()::
113+
114+
service.start(mActivity, 'small_icon', 'title', 'content' , argument)
115+
116+
Where 'small_icon' is the name of an Android drawable or mipmap resource,
117+
and 'title' and 'content' are strings in the notification.
110118

111119
Services support a range of options and interactions not yet
112120
documented here but all accessible via calling other methods of the

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

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,30 +102,47 @@ protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument)
102102

103103
protected void doStartForeground(Bundle extras) {
104104
String serviceTitle = extras.getString("serviceTitle");
105-
String serviceDescription = extras.getString("serviceDescription");
105+
String smallIconName = extras.getString("smallIconName");
106+
String contentTitle = extras.getString("contentTitle");
107+
String contentText = extras.getString("contentText");
106108
Notification notification;
107109
Context context = getApplicationContext();
108110
Intent contextIntent = new Intent(context, PythonActivity.class);
109111
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
110112
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
111113

112-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
114+
// Unspecified icon uses default.
115+
int smallIconId = context.getApplicationInfo().icon;
116+
if (!smallIconName.equals("")){
117+
int resId = getResources().getIdentifier(smallIconName, "mipmap",
118+
getPackageName());
119+
if (resId ==0) {
120+
resId = getResources().getIdentifier(smallIconName, "drawable",
121+
getPackageName());
122+
}
123+
if (resId !=0) {
124+
smallIconId = resId;
125+
}
126+
}
127+
128+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
129+
// This constructor is deprecated
113130
notification = new Notification(
114-
context.getApplicationInfo().icon, serviceTitle, System.currentTimeMillis());
131+
smallIconId, serviceTitle, System.currentTimeMillis());
115132
try {
116133
// prevent using NotificationCompat, this saves 100kb on apk
117134
Method func = notification.getClass().getMethod(
118135
"setLatestEventInfo", Context.class, CharSequence.class,
119136
CharSequence.class, PendingIntent.class);
120-
func.invoke(notification, context, serviceTitle, serviceDescription, pIntent);
137+
func.invoke(notification, context, contentTitle, contentText, pIntent);
121138
} catch (NoSuchMethodException | IllegalAccessException |
122139
IllegalArgumentException | InvocationTargetException e) {
123140
}
124141
} else {
125142
// for android 8+ we need to create our own channel
126143
// https://stackoverflow.com/questions/47531742/startforeground-fail-after-upgrade-to-android-8-1
127-
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a"; //TODO: make this configurable
128-
String channelName = "Background Service"; //TODO: make this configurable
144+
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a" + getServiceId();
145+
String channelName = "Background Service" + getServiceId();
129146
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,
130147
NotificationManager.IMPORTANCE_NONE);
131148

@@ -135,10 +152,10 @@ protected void doStartForeground(Bundle extras) {
135152
manager.createNotificationChannel(chan);
136153

137154
Notification.Builder builder = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);
138-
builder.setContentTitle(serviceTitle);
139-
builder.setContentText(serviceDescription);
155+
builder.setContentTitle(contentTitle);
156+
builder.setContentText(contentText);
140157
builder.setContentIntent(pIntent);
141-
builder.setSmallIcon(context.getApplicationInfo().icon);
158+
builder.setSmallIcon(smallIconId);
142159
notification = builder.build();
143160
}
144161
startForeground(getServiceId(), notification);

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

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,49 @@ public int startType() {
1717
protected int getServiceId() {
1818
return {{ service_id }};
1919
}
20+
21+
static private void _start(Context ctx, String smallIconName,
22+
String contentTitle, String contentText,
23+
String pythonServiceArgument) {
24+
Intent intent = getDefaultIntent(ctx, smallIconName, contentTitle,
25+
contentText, pythonServiceArgument);
26+
ctx.startService(intent);
27+
}
2028

2129
static public void start(Context ctx, String pythonServiceArgument) {
22-
Intent intent = getDefaultIntent(ctx, pythonServiceArgument);
23-
ctx.startService(intent);
30+
_start(ctx, "", "{{ args.name }}", "{{ name|capitalize }}", pythonServiceArgument);
2431
}
2532

26-
static public Intent getDefaultIntent(Context ctx, String pythonServiceArgument) {
33+
static public void start(Context ctx, String smallIconName,
34+
String contentTitle, String contentText,
35+
String pythonServiceArgument) {
36+
_start(ctx, smallIconName, contentTitle, contentText, pythonServiceArgument);
37+
}
38+
39+
static public Intent getDefaultIntent(Context ctx, String smallIconName,
40+
String contentTitle, String contentText,
41+
String pythonServiceArgument) {
2742
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
2843
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
2944
intent.putExtra("androidPrivate", ctx.getFilesDir().getAbsolutePath());
3045
intent.putExtra("androidArgument", argument);
3146
intent.putExtra("serviceTitle", "{{ args.name }}");
32-
intent.putExtra("serviceDescription", "{{ name|capitalize }}");
3347
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
3448
intent.putExtra("pythonName", "{{ name }}");
3549
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
3650
intent.putExtra("pythonHome", argument);
3751
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
3852
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
53+
intent.putExtra("smallIconName", smallIconName);
54+
intent.putExtra("contentTitle", contentTitle);
55+
intent.putExtra("contentText", contentText);
3956
return intent;
4057
}
4158

4259
@Override
4360
protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument) {
44-
return Service{{ name|capitalize }}.getDefaultIntent(ctx, pythonServiceArgument);
61+
return Service{{ name|capitalize }}.getDefaultIntent(ctx, "", "", "",
62+
pythonServiceArgument);
4563
}
4664

4765
static public void stop(Context ctx) {

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

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,13 @@ public static void prepare(Context ctx) {
3434
PythonUtil.unpackAsset(ctx, "private", app_root_file, true);
3535
PythonUtil.unpackPyBundle(ctx, ctx.getApplicationInfo().nativeLibraryDir + "/" + "libpybundle", app_root_file, false);
3636
}
37-
38-
public static void start(Context ctx, String pythonServiceArgument) {
39-
Intent intent = getDefaultIntent(ctx, pythonServiceArgument);
40-
37+
38+
static private void _start(Context ctx, String smallIconName,
39+
String contentTitle,
40+
String contentText,
41+
String pythonServiceArgument) {
42+
Intent intent = getDefaultIntent(ctx, smallIconName, contentTitle,
43+
contentText, pythonServiceArgument);
4144
//foreground: {{foreground}}
4245
{% if foreground %}
4346
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -50,26 +53,43 @@ public static void start(Context ctx, String pythonServiceArgument) {
5053
{% endif %}
5154
}
5255

53-
static public Intent getDefaultIntent(Context ctx, String pythonServiceArgument) {
56+
public static void start(Context ctx, String pythonServiceArgument) {
57+
_start(ctx, "", "{{ args.name }}", "{{ name|capitalize }}", pythonServiceArgument);
58+
}
59+
60+
static public void start(Context ctx, String smallIconName,
61+
String contentTitle,
62+
String contentText,
63+
String pythonServiceArgument) {
64+
_start(ctx, smallIconName, contentTitle, contentText, pythonServiceArgument);
65+
}
66+
67+
static public Intent getDefaultIntent(Context ctx, String smallIconName,
68+
String contentTitle,
69+
String contentText,
70+
String pythonServiceArgument) {
5471
String appRoot = PythonUtil.getAppRoot(ctx);
5572
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
5673
intent.putExtra("androidPrivate", appRoot);
5774
intent.putExtra("androidArgument", appRoot);
5875
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
5976
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
60-
intent.putExtra("serviceDescription", "");
6177
intent.putExtra("pythonName", "{{ name }}");
6278
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
6379
intent.putExtra("pythonHome", appRoot);
6480
intent.putExtra("androidUnpack", appRoot);
6581
intent.putExtra("pythonPath", appRoot + ":" + appRoot + "/lib");
6682
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
83+
intent.putExtra("smallIconName", smallIconName);
84+
intent.putExtra("contentTitle", contentTitle);
85+
intent.putExtra("contentText", contentText);
6786
return intent;
6887
}
6988

7089
@Override
7190
protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument) {
72-
return Service{{ name|capitalize }}.getDefaultIntent(ctx, pythonServiceArgument);
91+
return Service{{ name|capitalize }}.getDefaultIntent(ctx, "", "", "",
92+
pythonServiceArgument);
7393
}
7494

7595

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,40 @@ public static void start(Context ctx, String pythonServiceArgument) {
3434
intent.putExtra("androidArgument", argument);
3535
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
3636
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
37-
intent.putExtra("serviceDescription", "");
3837
intent.putExtra("pythonName", "{{ name }}");
3938
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
4039
intent.putExtra("pythonHome", argument);
4140
intent.putExtra("androidUnpack", argument);
4241
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
4342
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
43+
intent.putExtra("smallIconName", "");
44+
intent.putExtra("contentTitle", "{{ name|capitalize }}");
45+
intent.putExtra("contentText", "");
4446
ctx.startService(intent);
4547
}
46-
48+
49+
public static void start(Context ctx, String smallIconName,
50+
String contentTitle,
51+
String contentText,
52+
String pythonServiceArgument) {
53+
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
54+
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
55+
intent.putExtra("androidPrivate", argument);
56+
intent.putExtra("androidArgument", argument);
57+
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
58+
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
59+
intent.putExtra("pythonName", "{{ name }}");
60+
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
61+
intent.putExtra("pythonHome", argument);
62+
intent.putExtra("androidUnpack", argument);
63+
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
64+
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
65+
intent.putExtra("smallIconName", smallIconName);
66+
intent.putExtra("contentTitle", contentTitle);
67+
intent.putExtra("contentText", contentText);
68+
ctx.startService(intent);
69+
}
70+
4771
public static void stop(Context ctx) {
4872
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
4973
ctx.stopService(intent);

0 commit comments

Comments
 (0)