Kivy recipe: service customization

Default android service started with kivy is a foreground service, so that's why it will have an icon in tray. But! You have no possibility to change specify any parameters for that, so here is how you can customize this icon (based on

Note that this will cause weird side effect: tapping on the icon won't call the app. No idea how to make it work :(

Register drawables

Android Drawable class needs registered drawables, and that is not the same as kivy's data folder. I use buildozer, so I don't call directly, and... I have just put drawables in the separate folder and rsync them before packaging the apk. Not the best way, but it works. Here is how it should look like (I do it before packaging command in my makefile):

    mkdir -p .buildozer/android/platform/python-for-android/dist/kognitivo/res/drawable/
    rsync -rav ./drawable/ .buildozer/android/platform/python-for-android/dist/kognitivo/res/drawable/

Exclude drawables from packaging, you don't need that in the package itself (buildozer.spec):

source.exclude_patterns = make/*, build/*, drawable/*  

Note that filenames without extensions will be used in registering drawables, so make it easy to deal with :)

Update service

To update the code use something like this:

    Context = autoclass('android.content.Context')
    Intent = autoclass('android.content.Intent')
    PendingIntent = autoclass('')
    AndroidString = autoclass('java.lang.String')
    NotificationBuilder = autoclass('$Builder')

    service = autoclass('').mService
    Drawable = autoclass("{}.R$drawable".format(service.getPackageName()))
    PythonService = autoclass('')
    service = PythonService.mService
    text = AndroidString("Kognivisor".encode('utf-8'))
    message = AndroidString("Kognitivo's small friend".encode('utf-8'))
    small_icon = getattr(Drawable, 'tray_small')

    large_icon_bitmap = get_scaled_icon('icon_filename_without_extension')

    contentIntent = PendingIntent.getActivity(service, 0, Intent(service, service.getClass()), 0)
    notification_builder = NotificationBuilder(service)

    notification = notification_builder.getNotification()

    notification_service = service.getSystemService(Context.NOTIFICATION_SERVICE)
    notification_service.notify(1, notification)

Note that the icons you use for service should be rescaled for different dpis and suchs stuff, that sucks so I just rescale it on the fly with small function like this:

def get_scaled_icon(icon):  
    Dimen = autoclass("android.R$dimen")
    Bitmap = autoclass("")

    scaled_icon = getattr(Drawable, icon)
    scaled_icon = cast("",
    scaled_icon = scaled_icon.getBitmap()

    res = service.getResources()
    height = res.getDimension(Dimen.notification_large_icon_height)
    width = res.getDimension(Dimen.notification_large_icon_width)
    return Bitmap.createScaledBitmap(scaled_icon, width, height, False)

Good luck!

comments powered by Disqus