Today I Learned How to Create a Local Notification in Xamarin Android

In Android you can schedule a notification that shows immediately using the NotificationManager.  However, if you are like me, awesome, and want to schedule a notification for a future date you need to use the Android AlarmManager.  The alarm manager lets you schedule an Intent to occur at a later date.

Quick aside, do you know what an Intent is in Android?  I kind of understand them but not as in-depth as I would like.  Please forgive any errors I make when I setup the alarm intent below.

Without any further hesitation here is the code to schedule a local notification stolen from the SaturdayMP.XPlugins.Notifications:

public Guid Create(string title, string message, DateTime scheduleDate, Dictionary<string, string> extraInfo)
{
  // Create the unique identifier for this notifications.
  var notificationId = Guid.NewGuid();

  // Create the intent to be called when the alarm triggers. Make sure
  // to add the id so we can find it later if the user wants to update or
  // cancel.
  var alarmIntent = new Intent(Application.Context, typeof(NotificationAlarmHandler));
  alarmIntent.SetAction($"{notificationId:N}");
  alarmIntent.PutExtra("title", title);
  alarmIntent.PutExtra("message", message);

  var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);

  // Figure out the alaram in milliseconds.
  var utcTime = TimeZoneInfo.ConvertTimeToUtc(scheduleDate);
  var epochDif = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
  var notifyTimeInInMilliseconds = utcTime.AddSeconds(-epochDif).Ticks/10000;
  
  // Set the notification.
  var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
  alarmManager?.Set(AlarmType.RtcWakeup, notifyTimeInInMilliseconds, pendingIntent);

  // All done.
  return notificationId;
}

First thing to notice is the GUID. This is not required when scheduling a notification but can be useful later when you need to find and cancel it.

// Create the unique identifier for this notifications.
var notificationId = Guid.NewGuid();

Next you need to create the intent you want to occur.  This is the notification as well as what happens when the user clicks on the notification when it appears.  When creating the intent set the class you want to be executed.  In this case it’s the NotificationAlarmHandler.

var alarmIntent = new Intent(Application.Context, typeof(NotificationAlarmHandler));

The title and message are displayed when the notification is displayed.  The action is set to the GUID so we can find the notification at a later and cancel it.

alarmIntent.SetAction($"{notificationId:N}");
alarmIntent.PutExtra("title", title);
alarmIntent.PutExtra("message", message);

Then you need to wrap the intent in a pending intent.  What is the different between an Intent and PendingIntent?  Well a pending intent is an intent that will occur sometime in the future.  Just like it sounds.  Actually a PendingIntent is a reference to the actual Intent so if your application is shut down your scheduled intent is not destroyed.  Remember I don’t really understand Intents very well.

var pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);

Next we need to translate C# dates to Android dates.  Don’t ask me for the details.  I found this code in edsnider/Xamarin.Plugins project.  Something to do with the Unix epoch.

// Figure out the alaram in milliseconds. var utcTime = TimeZoneInfo.ConvertTimeToUtc(scheduleDate);
var epochDif = (new DateTime(1970, 1, 1) - DateTime.MinValue).TotalSeconds;
var notifyTimeInInMilliseconds = utcTime.AddSeconds(-epochDif).Ticks/10000;

Finally we are at the moment we can actually schedule the notification.  Man that took longer than it should have.  Let me catch my breath.  I think I suffer from Panda Asthma.

Now that I have my breath back let’s schedule the notification.  This part is straight forward. Just get an instance of the AlarmManager and then schedule our pending intent. Ask the alarm to  wake up our application, if it’s asleep, at our scheduled time.

// Set the notification.
var alarmManager = Application.Context.GetSystemService(Context.AlarmService) as AlarmManager;
alarmManager?.Set(AlarmType.RtcWakeup, notifyTimeInInMilliseconds, pendingIntent);

That’s it.  The shows over.  Go home.

P.S. – Today’s programming song is about communication.  Make sure you communicate with those important to you.  Also yelling “Say something, I’m giving up on you” at your phone when your notification code is not working is therapeutic.

This entry was posted in Goal App, Today I Learned. Bookmark the permalink.