Skip to content

Commit

Permalink
Custom Service notification (kivy#2703)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
RobertFlatt authored and ShyamQt committed Feb 17, 2023
1 parent 0fb2b16 commit f2ab978
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 23 deletions.
8 changes: 8 additions & 0 deletions doc/source/services.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,14 @@ the json module to encode and decode more complex data.

from os import environ
argument = environ.get('PYTHON_SERVICE_ARGUMENT', '')
To customize the notification icon, title, and text use three optional
arguments to service.start()::

service.start(mActivity, 'small_icon', 'title', 'content' , argument)

Where 'small_icon' is the name of an Android drawable or mipmap resource,
and 'title' and 'content' are strings in the notification.

Services support a range of options and interactions not yet
documented here but all accessible via calling other methods of the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,30 +102,47 @@ protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument)

protected void doStartForeground(Bundle extras) {
String serviceTitle = extras.getString("serviceTitle");
String serviceDescription = extras.getString("serviceDescription");
String smallIconName = extras.getString("smallIconName");
String contentTitle = extras.getString("contentTitle");
String contentText = extras.getString("contentText");
Notification notification;
Context context = getApplicationContext();
Intent contextIntent = new Intent(context, PythonActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, contextIntent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// Unspecified icon uses default.
int smallIconId = context.getApplicationInfo().icon;
if (!smallIconName.equals("")){
int resId = getResources().getIdentifier(smallIconName, "mipmap",
getPackageName());
if (resId ==0) {
resId = getResources().getIdentifier(smallIconName, "drawable",
getPackageName());
}
if (resId !=0) {
smallIconId = resId;
}
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// This constructor is deprecated
notification = new Notification(
context.getApplicationInfo().icon, serviceTitle, System.currentTimeMillis());
smallIconId, serviceTitle, System.currentTimeMillis());
try {
// prevent using NotificationCompat, this saves 100kb on apk
Method func = notification.getClass().getMethod(
"setLatestEventInfo", Context.class, CharSequence.class,
CharSequence.class, PendingIntent.class);
func.invoke(notification, context, serviceTitle, serviceDescription, pIntent);
func.invoke(notification, context, contentTitle, contentText, pIntent);
} catch (NoSuchMethodException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
}
} else {
// for android 8+ we need to create our own channel
// https://stackoverflow.com/questions/47531742/startforeground-fail-after-upgrade-to-android-8-1
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a"; //TODO: make this configurable
String channelName = "Background Service"; //TODO: make this configurable
String NOTIFICATION_CHANNEL_ID = "org.kivy.p4a" + getServiceId();
String channelName = "Background Service" + getServiceId();
NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName,
NotificationManager.IMPORTANCE_NONE);

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

Notification.Builder builder = new Notification.Builder(context, NOTIFICATION_CHANNEL_ID);
builder.setContentTitle(serviceTitle);
builder.setContentText(serviceDescription);
builder.setContentTitle(contentTitle);
builder.setContentText(contentText);
builder.setContentIntent(pIntent);
builder.setSmallIcon(context.getApplicationInfo().icon);
builder.setSmallIcon(smallIconId);
notification = builder.build();
}
startForeground(getServiceId(), notification);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,31 +17,49 @@ public int startType() {
protected int getServiceId() {
return {{ service_id }};
}

static private void _start(Context ctx, String smallIconName,
String contentTitle, String contentText,
String pythonServiceArgument) {
Intent intent = getDefaultIntent(ctx, smallIconName, contentTitle,
contentText, pythonServiceArgument);
ctx.startService(intent);
}

static public void start(Context ctx, String pythonServiceArgument) {
Intent intent = getDefaultIntent(ctx, pythonServiceArgument);
ctx.startService(intent);
_start(ctx, "", "{{ args.name }}", "{{ name|capitalize }}", pythonServiceArgument);
}

static public Intent getDefaultIntent(Context ctx, String pythonServiceArgument) {
static public void start(Context ctx, String smallIconName,
String contentTitle, String contentText,
String pythonServiceArgument) {
_start(ctx, smallIconName, contentTitle, contentText, pythonServiceArgument);
}

static public Intent getDefaultIntent(Context ctx, String smallIconName,
String contentTitle, String contentText,
String pythonServiceArgument) {
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
intent.putExtra("androidPrivate", ctx.getFilesDir().getAbsolutePath());
intent.putExtra("androidArgument", argument);
intent.putExtra("serviceTitle", "{{ args.name }}");
intent.putExtra("serviceDescription", "{{ name|capitalize }}");
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
intent.putExtra("pythonName", "{{ name }}");
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
intent.putExtra("pythonHome", argument);
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
intent.putExtra("smallIconName", smallIconName);
intent.putExtra("contentTitle", contentTitle);
intent.putExtra("contentText", contentText);
return intent;
}

@Override
protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument) {
return Service{{ name|capitalize }}.getDefaultIntent(ctx, pythonServiceArgument);
return Service{{ name|capitalize }}.getDefaultIntent(ctx, "", "", "",
pythonServiceArgument);
}

static public void stop(Context ctx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,13 @@ public static void prepare(Context ctx) {
PythonUtil.unpackAsset(ctx, "private", app_root_file, true);
PythonUtil.unpackPyBundle(ctx, ctx.getApplicationInfo().nativeLibraryDir + "/" + "libpybundle", app_root_file, false);
}

public static void start(Context ctx, String pythonServiceArgument) {
Intent intent = getDefaultIntent(ctx, pythonServiceArgument);


static private void _start(Context ctx, String smallIconName,
String contentTitle,
String contentText,
String pythonServiceArgument) {
Intent intent = getDefaultIntent(ctx, smallIconName, contentTitle,
contentText, pythonServiceArgument);
//foreground: {{foreground}}
{% if foreground %}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Expand All @@ -50,26 +53,43 @@ public static void start(Context ctx, String pythonServiceArgument) {
{% endif %}
}

static public Intent getDefaultIntent(Context ctx, String pythonServiceArgument) {
public static void start(Context ctx, String pythonServiceArgument) {
_start(ctx, "", "{{ args.name }}", "{{ name|capitalize }}", pythonServiceArgument);
}

static public void start(Context ctx, String smallIconName,
String contentTitle,
String contentText,
String pythonServiceArgument) {
_start(ctx, smallIconName, contentTitle, contentText, pythonServiceArgument);
}

static public Intent getDefaultIntent(Context ctx, String smallIconName,
String contentTitle,
String contentText,
String pythonServiceArgument) {
String appRoot = PythonUtil.getAppRoot(ctx);
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
intent.putExtra("androidPrivate", appRoot);
intent.putExtra("androidArgument", appRoot);
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
intent.putExtra("serviceDescription", "");
intent.putExtra("pythonName", "{{ name }}");
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
intent.putExtra("pythonHome", appRoot);
intent.putExtra("androidUnpack", appRoot);
intent.putExtra("pythonPath", appRoot + ":" + appRoot + "/lib");
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
intent.putExtra("smallIconName", smallIconName);
intent.putExtra("contentTitle", contentTitle);
intent.putExtra("contentText", contentText);
return intent;
}

@Override
protected Intent getThisDefaultIntent(Context ctx, String pythonServiceArgument) {
return Service{{ name|capitalize }}.getDefaultIntent(ctx, pythonServiceArgument);
return Service{{ name|capitalize }}.getDefaultIntent(ctx, "", "", "",
pythonServiceArgument);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,40 @@ public static void start(Context ctx, String pythonServiceArgument) {
intent.putExtra("androidArgument", argument);
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
intent.putExtra("serviceDescription", "");
intent.putExtra("pythonName", "{{ name }}");
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
intent.putExtra("pythonHome", argument);
intent.putExtra("androidUnpack", argument);
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
intent.putExtra("smallIconName", "");
intent.putExtra("contentTitle", "{{ name|capitalize }}");
intent.putExtra("contentText", "");
ctx.startService(intent);
}


public static void start(Context ctx, String smallIconName,
String contentTitle,
String contentText,
String pythonServiceArgument) {
String argument = ctx.getFilesDir().getAbsolutePath() + "/app";
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
intent.putExtra("androidPrivate", argument);
intent.putExtra("androidArgument", argument);
intent.putExtra("serviceEntrypoint", "{{ entrypoint }}");
intent.putExtra("serviceTitle", "{{ name|capitalize }}");
intent.putExtra("pythonName", "{{ name }}");
intent.putExtra("serviceStartAsForeground", "{{ foreground|lower }}");
intent.putExtra("pythonHome", argument);
intent.putExtra("androidUnpack", argument);
intent.putExtra("pythonPath", argument + ":" + argument + "/lib");
intent.putExtra("pythonServiceArgument", pythonServiceArgument);
intent.putExtra("smallIconName", smallIconName);
intent.putExtra("contentTitle", contentTitle);
intent.putExtra("contentText", contentText);
ctx.startService(intent);
}

public static void stop(Context ctx) {
Intent intent = new Intent(ctx, Service{{ name|capitalize }}.class);
ctx.stopService(intent);
Expand Down

0 comments on commit f2ab978

Please sign in to comment.