3

I am using AlarmManager to set 2 different repeating alarms. One alarm is fired every hour at minute 59. This alarm always works correctly. But, the other alarm, which is scheduled every 5 minutes starts working properly during 1 or 2 hours. After that time, my AlarmManager schedules the alarm but it is never fired anymore.

I am using setExactAndAllowWhileIdle() method to schedule the alarms.

In order to check whether the alarm was scheduled and activated or not, I am using this method after calling setExactAndAllowWhileIdle():

fun isAlarmActive(frameType: FrameType): Boolean{
        val alarmIntent = getAlarmIntent(frameType)
        alarmIntent.action = CUSTOM_INTENT
        return PendingIntent.getBroadcast(ctx, 0, alarmIntent, PendingIntent.FLAG_NO_CREATE) != null
    }

I tested this method by scheduling and commenting out the line where I execute setExactAndAllowWhileIdle() and then contrasting its output with "adb shell dumpsys alarm" output.

I left the program working during 24 hours. After checking out my logs, I saw that the alarm was working during 2 hours, and when it stopped to work, it was activated but not fired anymore...

And my app doesn't get killed because despite this alarm stops being fired, the other one still contiues working and I'm following exactly same mechanism as the code below.

This is MyAlarmManager class:

class MyAlarmManager(private val ctx: Context) {

    private val TAG = "MyAlarmManager"
    val CUSTOM_INTENT = "com.test.intent.action.ALARM"

    private val mAlarmManager = ctx.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    fun setAlarm(frameType: FrameType, delayInMinutes: Int, force: Boolean) {
        LogsHandler.writeLogs(TAG, "setAlarm()")
        checkAlarmsToCancel(frameType)
        val triggerAt = getTriggerTime(delayInMinutes, force)
        mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAt.timeInMillis, getPendingIntent(frameType))
        LogsHandler.writeLogs(TAG, "Se ha programado la alarma de tipo $frameType a la hora: ${Date(triggerAt.timeInMillis)}")

        if(isAlarmActive(frameType))
            LogsHandler.writeLogs(TAG, "La alarma está activada")
         else
            LogsHandler.writeLogs(TAG, "La alarma NO está activada")
    }
    private fun getAlarmIntent(frameType: FrameType) :Intent{
        return when(frameType){
            FrameType.PRESENCE -> Intent(ctx, StartPresenceReportService::class.java)
            FrameType.STEPS -> Intent(ctx, StartStepsCountReportService::class.java)
            FrameType.LOCATION -> Intent(ctx, StartLocationDeliveryService::class.java)
        }
    }

    private fun getPendingIntent(frameType: FrameType): PendingIntent {
        val alarmIntent = getAlarmIntent(frameType)
        alarmIntent.action = CUSTOM_INTENT
        return PendingIntent.getBroadcast(ctx, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)
    }

}


This is my BroadcastReceiver:

class StartLocationDeliveryService: BroadcastReceiver() {

    private var TAG = "StartLocationDeliveryService"

    override fun onReceive(context: Context, intent: Intent) {

        //Irrelevant code
        LocationDeliveryService().executeWork(context, intent)
    }
}

This is LocationDeliveryService:

class LocationDeliveryService {
    private var TAG = "LocationDeliveryService"

    fun executeWork(context: Context, intent: Intent) {

        //Business logical operations
        MyAlarmManager(context).setAlarm(FrameType.LOCATION, minutesBetweenLocationDeliveryMsgs, false)
    }
}
Asteroid
  • 718
  • 7
  • 21

1 Answers1

4

I solved this problem by my own. It wasn't a programming problem, it was related to Android and its Doze mode. Wear OS has a restriction that says we can only schedule an alarm every 9 minutes.

So I launched a test, repeating my alarms every 10 minutes, and the problem was gone! Hope my solution can help someone else!