Monday 19 September 2016

How to Schedule Notification in Android using Xamarin - Part2 (Wakeful Broadcast Receiver)

You are recommended to read Part 1 if you haven't.
Part 1 - How to schedule Notification in Android using Xamarin - with Broadcast Receiver.

Part - 2:
Well, after the experiment of using Notification with Broadcast Receiver and Alarm Manager, I knew that my next steps is to make sure my notification should work in various scenarios, such as when my app is in the foreground, in background, or the mobile is in idle, and so on. Am I still able to receive the notification I have scheduled in all the different circumstances?


Concept:
1st of all, no different in MainActivity. You may copy the sample source code written in Part 1. Basically, we still need a Pending Intent that going to perform a Broadcast. We still need to set the pending intent into Alarm Manager. And, schedule it to a future time.

Secondly, instead of extending the AlarmReceiver with Broadcast Receiver, this time we use 'WakefulBroadcastReceiver'. This will wake the CPU so that message can be handled before going back to sleep.

As the WakefulBroadcastReceiver instance is just an extended BroadcastReceiver instance, we cannot execute long-running of asynchronous tasks. If we wish, we need to perform to start a task in a service using the static StartWakefulService() method.

Sample source code:
Here is the example of using WakefulBroadcast Receiver.
AlarmReceiver.cs - create a new intent - which is a service typed intent.

[BroadcastReceiver]
    public class AlarmReceiver : WakefulBroadcastReceiver
    {
        public AlarmReceiver()
        {
        }

        //Before we prevent the CPU from going to sleep, we need permission: Permission.WakeLock.
        //The recommended way to get hold of a wake lock is to use an instance of WakefulBroadcastReceive and invoke the StartWakefulService() method:
        public override void OnReceive(Context context, Intent intent)
        {
            var serviceIntent = new Intent(context, typeof(ListenerService));

            //Get the string value from the sender. 
            var title = intent.GetStringExtra("title");
            var message = intent.GetStringExtra("message");

            //Set them to service intent. 
            serviceIntent.PutExtra("title", title);
            serviceIntent.PutExtra("message", message);

            StartWakefulService(context, serviceIntent);
        }
    }
 



ListenerService.cs - service
[Service]
    public class ListenerService : IntentService
    {
        protected override void OnHandleIntent(Intent intent)
        {
            try
            {
                //perform the task
                Console.WriteLine("IN On HandleIntent: " + intent.Action);
                PublishNotification(this, intent);
            }
            finally
            {
                WakefulBroadcastReceiver.CompleteWakefulIntent(intent);
            }
        }

        private void PublishNotification(Context context, Intent intent)
        {
            var message = intent.GetStringExtra("message");
            var title = intent.GetStringExtra("title");

            var resultIntent = new Intent(context, typeof(SecondActivity));
            resultIntent.PutExtra("msg", "You clicked on the local notification!");

            //Specify how this intent is handled. 
            resultIntent.SetFlags(ActivityFlags.NewTask | ActivityFlags.ClearTask);

            var PI = PendingIntent.GetActivity(context, 0, resultIntent, PendingIntentFlags.CancelCurrent);

            var builder = new Notification.Builder(context)
                    .SetContentTitle(title)
                    .SetContentText(message)
                    .SetLargeIcon(BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.icon))
                    .SetSmallIcon(Resource.Drawable.icon)
                    .SetPriority(1)
                    .SetAutoCancel(true)
                    .SetDefaults(NotificationDefaults.All);

            //Create Image notification.
            Notification.BigPictureStyle picStyle = new Notification.BigPictureStyle();
            picStyle.BigPicture(BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.icon));
            picStyle.SetSummaryText("This is image notification!! Hoho!");
            builder.SetStyle(picStyle);

            builder.SetContentIntent(PI);
            var notification = builder.Build();

            var manager = NotificationManager.FromContext(context);

            DateTime now = DateTime.Now;
            var notificationID = now.Millisecond;

            manager.Notify(notificationID, notification);
        }
    }
  

3 comments:

  1. Hi +Toh Wei Lim thanks for the detailed post. I have a query by any chance can we get a notification when app is killed from background. Thanks

    ReplyDelete
    Replies
    1. Hi Sorry for the late reply. I hope you already have the solution. Else, my comments on your will question will be:

      If the app is killed from background, it is still possible to receive the local notification. Try something with 'WakefulBroadcastReceiver'. If you are doing local notification, then all your notification data are kept by Alarm Manager, not your app. As long as your alarm manager service is still running, the user should still able to receive notification when you app is killed. Hope this help.

      Delete
  2. StartWakefulService is deprecated

    ReplyDelete

How to run unit test for your Xamarin Application in AppCenter?

How to run unit test for your Xamarin application in AppCenter?  When we talk about Building and Distributing your Xamarin app, you m...