Scheduled Notifications in Android using Alarm Manager


Notification-Android-Wear

Few months ago, I wrote an article for DNC Magazine titled “Hello Xamarin.Forms!” which was later republished online on DotnetCurry.com. This article demoed all awesomeness of Xamarin.Forms with a simple Vehicle Service Reminder app as an example. One of the aspects of the app is to remind users when their vehicle was due for service. While I showed how to go about doing that in iOS and Windows Phone, I left the Android part as an action item for the readers. While some of you may have got it already, if you haven’t, here’s how you do it –

In Android, unlike in iOS, local notifications does not take the fireDate as a parameter while configuring Notifications. So we have to split this task into two –

  • Use system alarm services to wake your app up at a specified time (Using Alarm Manager)
  • Write the code to notify users in the “OnReceive()” method of the Broadcast Receiver

Using Alarm Manager

AlarmManager class is used to schedule your application to be run at some point in the future. Create an Alarm Intent, specify the broadcast receiver and finally set the time when you intend to wake your app up.

public void Remind (DateTime dateTime, string title, string message)
{

	Intent alarmIntent = new Intent(Forms.Context, typeof(AlarmReceiver));
	alarmIntent.PutExtra ("message", message);
	alarmIntent.PutExtra ("title", title);

	PendingIntent pendingIntent = PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
	AlarmManager alarmManager = (AlarmManager) Forms.Context.GetSystemService(Context.AlarmService);

	//TODO: For demo set after 5 seconds.
	alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime () + 5 * 1000, pendingIntent);

}

Notifying Users

Now that the AlarmManager will ensure that your app is run at a specified time, you will have to write the code to notify users in the “OnReceive()” method of the Broadcast Receiver. In this case the broadcast receiver is the AlarmReceiver – a custom class subclassed from BroadcastRecevier.

[BroadcastReceiver]
public class AlarmReceiver : BroadcastReceiver
{
	public override void OnReceive (Context context, Intent intent)
	{

		var message = intent.GetStringExtra ("message");
		var title = intent.GetStringExtra ("title");

		var notIntent = new Intent (context, typeof(MainActivity));
		var contentIntent = PendingIntent.GetActivity (context, 0, notIntent, PendingIntentFlags.CancelCurrent);
		var manager = NotificationManagerCompat.From (context);

					var style = new NotificationCompat.BigTextStyle();
					style.BigText(message);

					int resourceId;
					if (App.SelectedModel.VehicleType == "Car")
						resourceId = Resource.Drawable.Car;
					else if (App.SelectedModel.VehicleType == "Bike")
						resourceId = Resource.Drawable.Bike;
					else
						resourceId = Resource.Drawable.Other;

					var wearableExtender = new NotificationCompat.WearableExtender()
			.SetBackground(BitmapFactory.DecodeResource(context.Resources, resourceId))
						;

					//Generate a notification with just short text and small icon
		var builder = new NotificationCompat.Builder (context)
						.SetContentIntent (contentIntent)
						.SetSmallIcon (Resource.Drawable.ic_launcher)
						.SetContentTitle(title)
						.SetContentText(message)
						.SetStyle(style)
						.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis())
						.SetAutoCancel(true)
						.Extend(wearableExtender);

					var notification = builder.Build();
					manager.Notify(0, notification);
	}
}

The code above uses NotificationCompat.Builder and sets the WearableExtender which will ensure the notifications are also sent to the connected Android Wear device. To know more about wearable programming using Xamarin, don’t forget to check out the post on Tips for your First Wear App.

You can download the full source from my GitHub repo.

Advertisements

5 thoughts on “Scheduled Notifications in Android using Alarm Manager

  1. Hello Nish,

    nice article! I have a question to ask: is it possible to schedule repeated notification? For example every day at 13:00 pm? Not just only once.

    Thanks very much.

  2. Alarm Manager has a method “SetInexactRepeating” which can be used to schedule a repeated notification. We can mention the time for the first alarm to go off (in milliseconds since last boot) in the second time intervals at which this should keep on firing (n milliseconds since last boot) as third parameters respectively.

    Please check my implementation to fire an alarm everyday morning @ 12:00:01 next day onwards

    Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));

    PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
    AlarmManager alarmManager = (AlarmManager) GetSystemService(Context.AlarmService);
    var tomorrowMorningTime= new DateTime(DateTime.Now.AddDays(1).Year,DateTime.Now.AddDays(1).Month,DateTime.Now.AddDays(1).Day,0,0,1);
    var timeDifference = tomorrowMorningTime – DateTime.Now;
    var millisecondsInOneDay = 86400000;
    alarmManager.SetInexactRepeating (AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime () + (long)timeDifference.TotalMilliseconds, (long)millisecondsInOneDay, pendingIntent);

  3. From the docs:
    https://developer.android.com/reference/android/app/AlarmManager.html#setRepeating(int, long, long, android.app.PendingIntent)
    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.

    The worst case scenario is that your alarm didn’t trigger after the first time, and you have skipped a day.

    The safest bet, in my opinion, is to use Set (like the one Nish uses), to try to reduce as much the use of device wakelocks and also minimize the amount of battery usage.
    There’s no way your app is going to trigger your action repeatedly at the time specified if using API greater than 19.

    The alarm’s precision is best described in this other method:
    https://developer.android.com/reference/android/app/AlarmManager.html#set(int, long, android.app.PendingIntent)

    Hope this helps, really nice article
    Best Regards

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s