1

I'm trying to add alarms to my app that trigger a notification; the problem is, whenever I add a new alarm, the previous one doesn't work.

I think it is because of the request code passed (all alarms have the same code(0)), but I don't know how to pass a new request code each time.

This is my setAlarm() function:

    private fun setAlarm() {
        alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
        val intent = Intent(this, AlarmReceiver::class.java)
        pendingIntent = PendingIntent.getBroadcast(this, 0, intent, 0)

        alarmManager.setRepeating(
            AlarmManager.RTC_WAKEUP,
            calender.timeInMillis,
            AlarmManager.INTERVAL_DAY,
            pendingIntent
        )
        Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()

    }

And this is my alarm receiver class:

    private lateinit var pendingIntent: PendingIntent
    override fun onReceive(p0: Context?, p1: Intent?) {

        val intent = Intent(p0, MainActivity::class.java)
        p1!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        pendingIntent = PendingIntent.getActivity(p0, 0, intent, 0)

        val builder = NotificationCompat.Builder(p0!!, "androidAlarm")
            .setSmallIcon(drawable.notification_bg)
            .setContentTitle("Your reminder!")
            .setContentText("Your work has to be done now!")
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .setContentIntent(pendingIntent)


        val notificationManager = NotificationManagerCompat.from(p0)
        if (ActivityCompat.checkSelfPermission(
                p0,
                Manifest.permission.POST_NOTIFICATIONS
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            // TODO: Consider calling
            //    ActivityCompat#requestPermissions
            // here to request the missing permissions, and then overriding
            //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
            //                                          int[] grantResults)
            // to handle the case where the user grants the permission. See the documentation
            // for ActivityCompat#requestPermissions for more details.
            return
        }
        notificationManager.notify(123, builder.build())
    }

}

I also have no idea how I can repeat an alarm if the user wants to.

I tried using System.currentTimeMillis() in the request code parameter, but it didn't help.

I searched a lot but didn't find much.

This is the code I used when I tried System.currentTimeMillis():

private fun setAlarm() {
    calender = Calendar.getInstance()
    alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager

    val intent = Intent(this, AlarmReceiver::class.java)
    pendingIntent = PendingIntent.getBroadcast(this, System.currentTimeMillis().toInt(), intent, 0)
    alarmManager.setRepeating(
        AlarmManager.RTC_WAKEUP,
        calender.timeInMillis,
        AlarmManager.INTERVAL_DAY,
        pendingIntent)
    Toast.makeText(this, "alarm set", Toast.LENGTH_SHORT).show()

}

And this is the receiver class:

class AlarmReceiver : BroadcastReceiver() {
private lateinit var pendingIntent: PendingIntent
override fun onReceive(p0: Context?, p1: Intent?) {
    val id = System.currentTimeMillis().toInt()
    val intent = Intent(p0, MainActivity::class.java)
    p1!!.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    pendingIntent = PendingIntent.getBroadcast(p0, System.currentTimeMillis().toInt(), intent, 0)


    val builder = NotificationCompat.Builder(p0!!, "androidAlarm")
        .setSmallIcon(drawable.notification_bg)
        .setContentTitle("Your reminder!")
        .setContentText("Your work has to be done now!")
        .setPriority(NotificationCompat.PRIORITY_HIGH)
        .setDefaults(NotificationCompat.DEFAULT_ALL)
        .setContentIntent(pendingIntent)


    val notificationManager = NotificationManagerCompat.from(p0)
    if (ActivityCompat.checkSelfPermission(
            p0,
            Manifest.permission.POST_NOTIFICATIONS
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        // TODO: Consider calling
        //    ActivityCompat#requestPermissions
        // here to request the missing permissions, and then overriding
        //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
        //                                          int[] grantResults)
        // to handle the case where the user grants the permission. See the documentation
        // for ActivityCompat#requestPermissions for more details.
        return
    }
    notificationManager.notify(123, builder.build())
    Log.e("notification: ", "received a notification: ${pendingIntent.toString()}")
}

}

I am using setRepeating because set and setExact don't work, they trigger the alarm as soon as I add it regardless of the time it is set in.

Just for instance, my main goal is to be able to create more than one alarm with different times to be triggered at, and also have the ability to repeat a certain alarm daily if the user wants to

  • ```pendingIntent = PendingIntent.getBroadcast(this, (int) System.currentTimeMillis(), intent, 0)``` does not work? – Enowneb Mar 27 '23 at 04:19
  • no It doesn't . – Haitham Shalabi Mar 27 '23 at 13:48
  • Can you include the code that you have tried with ```PendingIntent.getBroadcast(this, (int) System.currentTimeMillis(), intent, 0)```? And as you have ```setRepeating()```, the ```AlarmReceiver``` should be called again the next day. And is it not triggering as expected for the next day? – Enowneb Mar 27 '23 at 14:11
  • I included the code, the problem is that whenever I add a new one, the older one is lost, so it doesn't trigger or repeat again tomorrow. – Haitham Shalabi Mar 27 '23 at 14:21

2 Answers2

0

There are some concepts that have to be clear when using Alarm.

Set multiple alarms

In order to have different alarms, when creating PendingIntent, you can have different requestCode:

public static PendingIntent getBroadcast (Context context, 
                int requestCode, 
                Intent intent, 
                int flags)

So for example, you should the following 2 different PendingIntent:

val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntentFirst = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val pendingIntentSecond = PendingIntent.getBroadcast(this, 2, intent, PendingIntent.FLAG_UPDATE_CURRENT)

And apart from requestCode that can identify different PendingIntent, there are more attributes to compare whether 2 PendingIntent are equal or not. You can refer to here for details.

AlarmManager.setRepeating() is inexact

Starting from API 19 (That should be Android 4.4), the alarm set by AlarmManager.setRepeating() are inexact:

Note: as of API 19, all repeating alarms are inexact. If your application needs precise delivery times then it must use one-time exact alarms, rescheduling each time as described above. Legacy applications whose targetSdkVersion is earlier than API 19 will continue to have all of their alarms, including repeating alarms, treated as exact.

val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
val pendingIntentFirst = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val pendingIntentSecond = PendingIntent.getBroadcast(this, 2, intent, PendingIntent.FLAG_UPDATE_CURRENT)
// Set the first alarm to start after 1 minute, repeat the alarm for every 1 minute
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calender.timeInMillis + 60 * 1000, 60 * 1000, pendingIntentFirst)
// Set the second alarm to start after 2 minutes, repeat the alarm for every 1 minute
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calender.timeInMillis + 120 * 1000, 60 * 1000, pendingIntentSecond)

With the above, you will observe that both the Alarm will be triggered simultaneously after 2 minutes. And then both of them are repeating every 1 minute.

For your case, it could probably be the alarms are triggered at the same time, so you may end up thinking that the AlarmReceiver class only run once.


So in order to have multiple alarms, you should be using AlarmManager.setExact() function:

public void setExact (int type, 
                long triggerAtMillis, 
                PendingIntent operation)

Schedule an alarm to be delivered precisely at the stated time.

Note: only alarms for which there is a strong demand for exact-time delivery (such as an alarm clock ringing at the requested time) should be scheduled as exact. Applications are strongly discouraged from using exact alarms unnecessarily as they reduce the OS's ability to minimize battery use.

As the setExact() function is one-time, you have to manually reschedule the Alarm in your AlarmReceiver Broadcast class.

So for example,

val alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
val intent = Intent(this, AlarmReceiver::class.java)
// You may find intent.putExtra() useful if you need to pass thing to your AlarmReceiver
val pendingIntentFirst = PendingIntent.getBroadcast(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val pendingIntentSecond = PendingIntent.getBroadcast(this, 2, intent, PendingIntent.FLAG_UPDATE_CURRENT)
// Set the first alarm to start after 1 minute
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calender.timeInMillis + 60 * 1000, pendingIntentFirst)
// Set the second alarm to start after 2 minutes
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calender.timeInMillis + 120 * 1000,pendingIntentSecond)

And in your AlarmReceiver class:

class AlarmReceiver : BroadcastReceiver() {
    ...
    override fun onReceive(p0: Context?, p1: Intent?) {
        // Your function here
        // After running your function, you will have to reschedule the alarm here
        val calendar = Calendar.getInstance()
        val alarmManager = context.getSystemService(ALARM_SERVICE) as AlarmManager
        val intent = Intent(this, AlarmReceiver::class.java)
        val pendingIntentFirst = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        // Repeat after 1 minute
        alarmManager.setExact(AlarmManager.RTC_WAKEUP, calender.timeInMillis + 60 * 1000, pendingIntentFirst)
    }
}
Enowneb
  • 943
  • 1
  • 2
  • 11
0

So after more than a week, it turned out that the request code isn't being unique by using System.currentTimeMillis(), or calender.timeInMillis, I tried this:

val pendingIntent = (PendingIntent.getBroadcast(this, (0..19992).random(), intent, 0))

and the request code is now being unique every single time and I can add different alarms at different times