Kivy recipe: android notifications and alarm manager

Finally I figured out how to make notifications work!

Here are some links:


This snippet creates alarm event, which fires a notification. Used simply to notify the user, that he or she needs to make something in app. Put it in service/ and just enjoy!

from time import sleep  
from datetime import datetime, timedelta, time  
from jnius import autoclass  
from android.broadcast import BroadcastReceiver

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

service = autoclass('').mService

def android_schedule_time(elapsed_time, schedule_datetime):  
    Returns the value got through SystemClock.elapsedRealtime to python datetime object.
    :param elapsed_time: time by elapsedRealtime (milliseconds since boot)
    :return: datetime object of a boot time
    boot_time = - timedelta(milliseconds=elapsed_time)
    return (schedule_datetime - boot_time).total_seconds() * 1000

class Scheduler(object):  
        time(9, 0),
        time(13, 0),
        time(19, 00),

    def schedule_datetime(self):
        today =
        tomorrow = ( + timedelta(days=1)).date()
        candidates = [datetime.combine(today, schedule_time) for schedule_time in self.SCHEDULE_TIMES]
        candidates += [datetime.combine(tomorrow, schedule_time) for schedule_time in self.SCHEDULE_TIMES]
        candidates = [candidate for candidate in candidates if candidate >]
        return candidates[0]

    def clean_schedules(self):
        intent = Intent(Intent.ACTION_PROVIDER_CHANGED)
        pi = PendingIntent.getBroadcast(service, self.PENDING_INTENT_REQUEST_CODE, intent, 0)
        am = service.getSystemService(Context.ALARM_SERVICE)

    def create_schedule(self):
        intent = Intent(Intent.ACTION_PROVIDER_CHANGED)
        pi = PendingIntent.getBroadcast(service, self.PENDING_INTENT_REQUEST_CODE, intent, 0)
        am = service.getSystemService(Context.ALARM_SERVICE)
        schedule = android_schedule_time(SystemClock.elapsedRealtime(), self.schedule_datetime())
        am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, schedule, pi)
        br = BroadcastReceiver(self.alarm_callback, ['provider_changed'])
        br.context = service

    def alarm_callback(self, *args):
        Drawable = autoclass("{}.R$drawable".format(service.getPackageName()))

        notification_service = service.getSystemService(Context.NOTIFICATION_SERVICE)
        icon = getattr(Drawable, 'icon')

        notification_builder = NotificationBuilder(service)

        title = AndroidString("Kognitivo".encode('utf-8'))
        message = AndroidString("It's time to measure your skills!".encode('utf-8'))

        java_class = autoclass('')().getClass()
        notificationIntent = Intent(service, java_class)
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)

        intent = PendingIntent.getActivity(service, 0, notificationIntent, 0)



if __name__ == '__main__':  
    scheduler = Scheduler()
    while True:


The problem and solution mentioned by Juan Toledo on kivy users - System.currentTimeMillis() won't work because it returns a long int, so my code will work only if the smartphone uptime is less than ~22days.

Also I found out, that the alarm manager won't work if yout app is dead, so you need to execute it from service, which causes some more problems: The notifications fired from service don't have PythonActivity (as much as activity shortcut from python-for-anroid returns AndroidService or so), and if you tap on it, nothing happens. That is why I haven't used plyer also, as much it uses this shortcut. I just copypasted and modified everything I need, but I let plyer guys know, that I found the solution for that, so maybe it will show up in plyer soon.


If you get something like

I/python  (10616):  Traceback (most recent call last):  
I/python  (10616):    File "jnius_proxy.pxi", line 150, in jnius.jnius.invoke0 (jnius/jnius.c:23786)  
I/python  (10616):    File "jnius_proxy.pxi", line 120, in jnius.jnius.py_invoke0 (jnius/jnius.c:23418)  
I/python  (10616):  AttributeError: 'builtin_function_or_method' object has no attribute 'invoke'  

put instructions in global scope. Related to the fact, that Java and Python objects won't be wiped simultaneously. See more here.

comments powered by Disqus