11

I've made an app that always worked until Android 6.0. I think it's the Doze feature that it's not allowing my Alarm to fire.

I use sharedpreferences to handle the options:

//ENABLE NIGHT MODE TIMER
    int sHour = blockerTimerPreferences.getInt("sHour", 00);
    int sMinute = blockerTimerPreferences.getInt("sMinute", 00);

    Calendar sTime = Calendar.getInstance();
    sTime.set(Calendar.HOUR_OF_DAY, sHour);
    sTime.set(Calendar.MINUTE, sMinute);

    Intent enableTimer = new Intent(context, CallReceiver.class);
    enableTimer.putExtra("activate", true);
    PendingIntent startingTimer = PendingIntent.getBroadcast(context, 11002233, enableTimer, PendingIntent.FLAG_UPDATE_CURRENT);
    AlarmManager sAlarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
    sAlarm.setRepeating(AlarmManager.RTC_WAKEUP,
            sTime.getTimeInMillis(),
            AlarmManager.INTERVAL_DAY, startingTimer);

Any clue of whats wrong here?

This is an app to block calls. Thank you!

EDIT: I have 3 files (more but...) like:

MainActivity (All code)
CallReceiver (Broadcast that triggers the alarm again (reboot etc))
CallReceiverService (Handles the call / phone state)
FilipeOS
  • 801
  • 1
  • 11
  • 42
  • 1
    Use `adb shell dumpsys alarm` to confirm that your alarm is scheduled. Note that `setRepeating()` is inexact on Android 4.4+. "This is causing battery drain too" -- that seems unlikely. Code that does not run should consume no battery. – CommonsWare Feb 25 '16 at 14:20
  • Hi @CommonsWare, 52 wakes and 52 alarms... It's always firering the alarms. `setRepeating()` will fire in that minute, no issue I think. – FilipeOS Feb 25 '16 at 14:23
  • @FilipeOS Did you make it work? Can we implement alarmManager.setRepeating() in the doze mode? – devgeek Sep 08 '17 at 12:44
  • @devgeek only like this and creating a service to check on boot etc. setExactAndAllowWhileIdle on >M and on old versions setExact – FilipeOS Sep 08 '17 at 18:23
  • setExact wont repeat. What if I need to make it repeat? @FilipeOS – devgeek Sep 11 '17 at 07:15

2 Answers2

14

The Doze mode will delay your alarm until the next maintenance window. To avoid the Doze mode to block your alarm, you can use setAndAllowWhileIdle(), setExactAndAllowWhileIdle() or setAlarmClock(). You will have about 10s to execute your code, and set your next alarm (not more than once per 15min for methods with _AndAllowWhileIdle though)

If you want to test the Doze mode, you can use ADB command:

  1. Configure a hardware device or virtual device with an Android 6.0 (API level 23) or higher system image.

  2. Connect the device to your development machine and install your app.

  3. Run your app and leave it active.
  4. Shut off the device screen. (The app remains active.) Force the system to cycle through Doze modes by running the following commands:

    adb shell dumpsys battery unplug

    adb shell dumpsys deviceidle step

  5. You may need to run the second command more than once. Repeat it until the device state changes to idle.

  6. Observe the behavior of your app after you reactivate the device. Make sure the app recovers gracefully when the device exits Doze.

Edit: Add setAlarmClock example

Don't forget to check the SDK level (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)

AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, MyAlarmReceiver.class); //or just new Intent() for implicit intent 
//set action to know this come from the alarm clock
intent.setAction("from.alarm.clock");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//Alarm fire in 5s.
am.setAlarmClock(new AlarmManager.AlarmClockInfo(System.currentTimeMillis() + 5000, pi), pi);
xiaomi
  • 6,553
  • 3
  • 29
  • 34
  • 1
    Hi @xiaomi , just replace `setRepeating` for the `setAlarmClock`? With the same params? Can you please make an example? Thank you! – FilipeOS Feb 26 '16 at 18:49
  • I edit my answer, but this is not very different of the others set alarm methods. – xiaomi Feb 26 '16 at 19:21
  • This is just an example to fire an alarm after 5s. Choose the time you want. – xiaomi Feb 26 '16 at 19:33
  • Hi @xiaomi, that `intent.setAction("from.alarm.clock");` it's showing the alarm icon on my phone, if I delete, any issue? – FilipeOS Feb 29 '16 at 10:31
  • Ah I didn't see that setAlarmClock will bring the clock icon into the status bar. Btw the set action is only for you when you check your receiver intent.getAction(). To remove the icon you will have to use another method than setAlarmClock() – xiaomi Feb 29 '16 at 10:38
  • Hi @xiaomi, can you please tell me one? Since this is very annoying. It works but I think no one will like that icon there.. – FilipeOS Feb 29 '16 at 12:32
  • Just use setAndAllowWhileIdle instead – xiaomi Feb 29 '16 at 12:33
  • @xiaomi What if we need to implement alarmManager.setRepeating() in the doze mode? How can we implement that? Can we use setAlarmClock like u mentioned above? – devgeek Sep 08 '17 at 12:30
2

If the device is in doze mode, you need to use one of these API: setExactAndAllowWhileIdle or setAndAllowWhileIdle.

Note that there is no API for waking the device up while in doze mode for a repeating alarm, so if you need a repeating alarm to wake the device while in doze, you have to use the APIs above and re-arm the timer at every occurrence of the timer firing.

Francesc
  • 25,014
  • 10
  • 66
  • 84