Xamarin Android Weekly repeating Alarm is not firing

319 Views Asked by At

I am trying to schedule Weekly notification. For a specific day and time, repeated weekly But it is not working. Here is my code for scheduling alarm

var id = Convert.ToInt32(string.Format("{0}{1}{2}", task.Id, hour, minutes));
var intent = new Intent(context, typeof(AlarmReceiver));
intent.PutExtra(AndroidConstants.NotificationId, id);
intent.PutExtra(AndroidConstants.NotificationMessage, $"{context.Resources.GetString(Resource.String.general_push_reminder_body)} {task.Name}");
intent.PutExtra(AndroidConstants.NotificationTitle, context.Resources.GetString(Resource.String.general_push_reminder_title));

var pendingIntent = PendingIntent.GetBroadcast(context, id, intent, PendingIntentFlags.CancelCurrent);
Calendar calendar = Calendar.Instance;
calendar.Set(CalendarField.DayOfWeek, (int)day);
calendar.Set(CalendarField.HourOfDay, hour);
calendar.Set(CalendarField.Minute, minutes);
calendar.Set(CalendarField.Second, 0);

if (calendar.Before(Calendar.Instance))
{
    Log.Info("Task", $"Adding 7 days as scheduled time is past");
    calendar.Add(CalendarField.DayOfYear, 7);
}
var alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarmManager.SetRepeating(AlarmType.RtcWakeup, calendar.TimeInMillis, 7 * AlarmManager.IntervalDay, pendingIntent);

Here is my receiver

[BroadcastReceiver(Enabled = true)]
    public class AlarmReceiver : BroadcastReceiver
    {
        public override void OnReceive(Context context, Intent intent)
        {
            try
            {
                Log.Info("Task", $"Alarm manager received");
                var title = intent.GetStringExtra(AndroidConstants.NotificationTitle);
                var message = intent.GetStringExtra(AndroidConstants.NotificationMessage);
                var id = intent.GetIntExtra(AndroidConstants.NotificationId, 0);
                Log.Info("Task", $"Showing Notification with id {id} {title} and {message}");
                NotificationHandler.ShowNotification(context, id, title, message);
            }
            catch (Exception ex)
            {
                Log.Error("Task", ex.ToString());
            }
        }

There is no exception. I have tried several options but the AlarmReceiver is not firing at all.

If I select today's day and give time after current time, still the if block for adding time for past is fired and an extra 7 day is added.

1

There are 1 best solutions below

3
On

I think that the issue is in alarmManager.SetRepeating(...).

If you see the docs of Android.App.AlarmManager.SetRepeating it states that the second parameter:

triggerAtMillis: time in milliseconds that the alarm should first go off, using the appropriate clock (depending on the alarm type).

You are passing calendar.TimeInMillis which according to the docs gives you:

the current time as UTC milliseconds from the epoch

which is not what you want.

I'd rather not use Calendar and use DateTime instead because it's easier to use and do the difference between the desired datetime and the current datetime in milliseconds, i.e.:

// here I hardcode the values but you should set whatever you want or get it from the user
DayOfWeek desiredDayOfWeek = DayOfWeek.Saturday;
int desiredHour = 1, desiredMinute = 30, desiredSecond = 0;

// Calculate which will be the desired date time in which the alarm will go off for the first time
var differenceInNumberOfDaysBetweenDayOfWeek = desiredDayOfWeek - DateTime.Today.DayOfWeek;
var nextDayOfWeek = differenceInNumberOfDaysBetweenDayOfWeek >= 0
                        ? DateTime.Today.AddDays(differenceInNumberOfDaysBetweenDayOfWeek)
                        : DateTime.Today.AddDays(differenceInNumberOfDaysBetweenDayOfWeek + 7);
var desiredDateTime = new DateTime(nextDayOfWeek.Year, nextDayOfWeek.Month, nextDayOfWeek.Day, desiredHour, desiredMinute, desiredSecond);

// this are the milliseconds left to arrive to the desired date time for the alarm to go off
var desiredMillisToArriveToDateTime = (desiredDateTime - DateTime.Now).Milliseconds;

var alarmManager = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarmManager.SetRepeating(AlarmType.RtcWakeup, desiredMillisToArriveToDateTime, 7 * AlarmManager.IntervalDay, pendingIntent);

HIH