Search code examples
androidkotlinandroid-notificationsalarmmanager

Missing notifications using AlarmManager


I am facing a problem when scheduling multiple (up to 14) notifications using the AlarmManager. The problem is that the notifications are randomly missing (especially when the debug cable isn’t plugged). For example the first three notifications are triggered and after these notifications none of the scheduled notifications get triggered anymore, until you reschedule the notifications. It seems it’s because of the amount of notifications, but I am not 100% sure.

Below you can find my functions for scheduling notifications (alarm and bedtime notifications);

private fun createNotificationChannel(name: String, descriptionText: String, id: String, setSound:Boolean)
  {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
      val importance = NotificationManager.IMPORTANCE_DEFAULT
      val channel = NotificationChannel(id, name, importance).apply {
        description = descriptionText
      }
      val audioAttributes = AudioAttributes.Builder()
        .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
        .setUsage(AudioAttributes.USAGE_NOTIFICATION)
        .build()
      if (setSound)
      {
        channel.setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + m_context.packageName + "/" + m_ringtone), audioAttributes)
      }
      (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).createNotificationChannel(channel)
    }
  }

  private fun createBedTimeNotificationChannel()
  {
    createNotificationChannel(BEDTIME_NOTIFICATION_CHANNEL_NAME, BEDTIME_NOTIFICATION_CHANNEL_DESCRIPTION, BEDTIME_NOTIFICATION_CHANNEL, false)
  }

  private fun createWakeUpNotificationChannel()
  {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
    {
      for (channel in (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).notificationChannels)
      {
        if (channel.id.contains(WAKE_UP_ALARM_NOTIFICATION_CHANNEL))
        {
          (m_context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager).deleteNotificationChannel(channel.id)
        }
      }
      m_randomNumber = Random().nextLong()
      createNotificationChannel(WAKE_UP_NOTIFICATION_CHANNEL_NAME, WAKE_UP_NOTIFICATION_CHANNEL_DESCRIPTION, WAKE_UP_ALARM_NOTIFICATION_CHANNEL + m_randomNumber, true)
    }
  }

  fun configureAlarmNotification(ringtone: Int, alarmTime: Int, snooze: Boolean, days: BooleanArray)
  {
    m_ringtone = ringtone
    createWakeUpNotificationChannel()
    for ((index, alarmOn) in days.withIndex())
    {
      if (alarmOn)
      {
        val builder = getWakeUpAlarmBuilder()

        val intent = Intent(m_context, CMainActivity::class.java)
        val activity = PendingIntent.getActivity(m_context, WAKE_UP_NOTIFICATION_ID_START + index + 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        builder.setContentIntent(activity)

        if (snooze)
        {
          val snoozeIntent = Intent(m_context, CSleepPlannerService::class.java).apply {
            putExtra(ACTION, ACTION_SNOOZE)
            putExtra(NOTIFICATION_ID, WAKE_UP_NOTIFICATION_ID_START + index + 1)
            putExtra(NOTIFICATION, builder.build())
          }

          val snoozePendingIntent: PendingIntent = PendingIntent.getBroadcast(m_context, SNOOZE_PRESSED_NOTIFICATION_ID + index + 1, snoozeIntent, 0)
          builder.addAction(R.drawable.alarm_bel_icon, m_context.getString(R.string.snooze), snoozePendingIntent)
        }

        val notification = builder.build()
        val calendar = Calendar.getInstance()
        val currentTimeInMillis = calendar.timeInMillis

        calendar[Calendar.DAY_OF_WEEK] = convertWeekday(index)
        calendar[Calendar.HOUR_OF_DAY] = alarmTime / 60
        calendar[Calendar.MINUTE] = alarmTime % 60
        calendar[Calendar.SECOND] = 0

        if (calendar.timeInMillis <= currentTimeInMillis)
        {
          calendar.timeInMillis += NUMBER_OF_MILLIS_IN_WEEK
        }

        val pendingIntent = getPendingIntent(calendar.timeInMillis, WAKE_UP_NOTIFICATION_ID_START + index + 1, notification, ACTION_NOTIFICATION, PendingIntent.FLAG_UPDATE_CURRENT)
        (m_context.getSystemService(ALARM_SERVICE) as AlarmManager).setExact(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
      }
    }

    val calendar = Calendar.getInstance()
    m_alarmWithSoundEnabledWithinADay.postValue((m_preferences.isAlarmWithSoundEnabled() && isAlarmEnabled(calendar[Calendar.HOUR_OF_DAY] * 60 + calendar[Calendar.MINUTE], m_preferences.getAlarmTime(), calendar[Calendar.DAY_OF_WEEK])))
  }

  fun configureBedTimeNotification(bedTime: Int, bedTimeSetting: Int, days: BooleanArray)
  {
    for ((index, alarmOn) in days.withIndex())
    {
      if (alarmOn)
      {
          val builder = NotificationCompat.Builder(m_context, BEDTIME_NOTIFICATION_CHANNEL).apply {
            setContentTitle(m_context.getString(R.string.bedtime_notification_tile))
            when (BedTimeNotificationSetting_e.fromInt(bedTimeSetting))
            {
              BedTimeNotificationSetting_e.AT_BED_TIME -> setContentText(m_context.getString(R.string.bedtime_notification_at_bedtime))
              BedTimeNotificationSetting_e.TEN_MINUTES_BEFORE -> setContentText(m_context.getString(
                  R.string.bedtime_notification_description_ten
                ))
              BedTimeNotificationSetting_e.THIRTY_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_thirty))
              BedTimeNotificationSetting_e.FORTYFIVE_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_fortyfive))
              BedTimeNotificationSetting_e.SIXTY_MINUTES_BEFORE -> setContentText(m_context.getString(R.string.bedtime_notification_description_sixty))
            }
            setAutoCancel(true)
            setSmallIcon(R.drawable.alarm_icon)
            priority = NotificationCompat.PRIORITY_HIGH
          }

        val intent = Intent(m_context, CMainActivity::class.java)
        val activity = PendingIntent.getActivity(m_context, BEDTIME_NOTIFICATION_ID_START + index + 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        builder.setContentIntent(activity)
        val notification = builder.build()

        val calendar = Calendar.getInstance()
        val currentTimeInMillis = calendar.timeInMillis

        calendar[Calendar.DAY_OF_WEEK] = convertWeekday(index)
        calendar[Calendar.HOUR_OF_DAY] = bedTime / 60
        calendar[Calendar.MINUTE] = bedTime % 60
        calendar[Calendar.SECOND] = 0

        var newBedTime = calendar.timeInMillis - (bedTimeSetting * 60 * 1000)

        if (newBedTime <= currentTimeInMillis)
        {
          newBedTime += NUMBER_OF_MILLIS_IN_WEEK
        }

        val pendingIntent = getPendingIntent(newBedTime, BEDTIME_NOTIFICATION_ID_START + index + 1, notification, ACTION_NOTIFICATION, PendingIntent.FLAG_UPDATE_CURRENT)
        (m_context.getSystemService(ALARM_SERVICE) as AlarmManager).setExact(AlarmManager.RTC_WAKEUP, newBedTime, pendingIntent)
      }
    }
  }

  private fun getPendingIntent(calendarTime: Long = 0, notificationId: Int, notification: Notification? = null, action: String, flag: Int) : PendingIntent?
  {
    val notificationIntent = Intent(m_context, this::class.java)
    notificationIntent.putExtra(ACTION, action)
    notificationIntent.putExtra(NOTIFICATION_ID, notificationId)
    notificationIntent.putExtra(NOTIFICATION, notification)
    notificationIntent.putExtra(ALARM_TIME, calendarTime)
    return PendingIntent.getBroadcast(m_context, notificationId, notificationIntent, flag)
  }

What could be the cause of this?


Solution

  • I fixed the issue for setting the wakeup notifications by using the function setAlarmClock from AlarmManager.