Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android O and background limits prevents simple alarm notification

My own app uses the exact same technique as shown by Google I/O app of 2016. see source

I need to remind users at a very specific point in time - using a notification.

For this, I use the AlarmManager to wake the device at the correct point in time:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        am.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    } else {
        am.set(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
    }

The pendingIntent is created like this:

    final Intent intent = new Intent(MyAlarmService.ACTION_NOTIFY_RIDE, null, this, MyAlarmService.class);
    pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);

Now, my MyAlarmService class is a simple IntentService handling the wake-up just for the purpose of create a notification for the user.

The message I get in the log is the following:

W/ActivityManager: Background start not allowed: service Intent { act=xxx.xxx.xxx.action.NOTIFY_RIDE flg=0x4 cmp=xxx.xxx.xxx./xxx.xxx.xxx.service.MyAlarmService (has extras) } 

Now, Google's own implementation is obviously broken - even though I do not want to do any heavy background work, I cannot use this technique anymore. But HOW am I supposed to wake up the user at a very specific point in time then? (think of my App as an alarm clock)

like image 667
Zordid Avatar asked Jul 10 '17 15:07

Zordid


2 Answers

The answer to my question is plain and simple:

Instead of using a service to display the notification (as Google does in its IO Schedule app!), use a BroadcastReceiver!

I have no idea why Google did use an IntentService, but now on Android O, this is simply not working anymore due to background execution limits.

A BroadcastReceiver though obviously still can run for a brief moment and display a notification.

Bonus points if somebody could tell me why Google used an IntentService in the first place... this took me ages to figure out, because I thought Google knows what they are doing... :(

like image 140
Zordid Avatar answered Oct 21 '22 01:10

Zordid


But HOW am I supposed to wake up the user at a very specific point in time then? (think of my App as an alarm clock)

First, your code will not be exact. If the device is in Doze mode, I would expect at best +/- 10 minutes. If you want exact timing, and your app really is an alarm clock, use setAlarmClock().

For your existing code, use getForegroundService() instead of getService() on API Level 26+.

like image 8
CommonsWare Avatar answered Oct 21 '22 01:10

CommonsWare