Search code examples
c#androidxamarinbroadcastreceiver

Run BroadcastReceiver even when app is swiped out from recent list


I am making a reminder app on Xamarin Android using c#. Currently when a notification is pushed out, I won't receive the notification if the app is swiped out.

I have seen loads of questions like this, but none of them have helped me.

Here is my BroadCastReceiver:

using Android.App;
using Android.Content;
using Newtonsoft.Json;
using ReminderApp.HelperRepository;
using System;
using ReminderApp.Models;
using Android.Graphics;
using Android.Support.V4.Content;
using Android.Media;

namespace ReminderApp.Notifications
{
    [BroadcastReceiver(Enabled = true)]
    public class ReminderNotifications : BroadcastReceiver
    {
        Reminder reminder;
        public ReminderNotifications()
        {
        }

        public override void OnReceive(Context context, Intent intent)
        {
            string CHANNEL_ID = "dan51";

            var channel = new NotificationChannel(CHANNEL_ID, "FCM Notifications", NotificationImportance.Max)
            {
                Description = "Firebase Cloud Messages appear in this channel"
            };

            long[] urgentVibrationPattern = { 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100, 100 };

            var alarmAttributes = new AudioAttributes.Builder()
                .SetContentType(AudioContentType.Sonification)
                .SetUsage(AudioUsageKind.Notification).Build();

            Android.Net.Uri infoAlarmUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);

            channel.EnableLights(true);
            channel.LightColor = Color.Red;
            channel.SetSound(infoAlarmUri, alarmAttributes);
            channel.EnableVibration(true);
            channel.SetVibrationPattern(urgentVibrationPattern);
            channel.SetBypassDnd(true);
            channel.LockscreenVisibility = NotificationVisibility.Public;

            string date = intent.GetStringExtra("date");
            string time = intent.GetStringExtra("time");


            reminder = ReminderHelper.SelectReminderByDateAndTime(context, date, time);
            if (reminder != null)
            {
                int NOTIFY_ID = 0 + new Random().Next();
                Intent newIntent = new Intent(context, typeof(ReminderContent));
                newIntent.PutExtra("reminder", JsonConvert.SerializeObject(reminder));

                Android.Support.V4.App.TaskStackBuilder stackBuilder = Android.Support.V4.App.TaskStackBuilder.Create(context);
                stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(ReminderContent)));
                stackBuilder.AddNextIntent(newIntent);

                PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);
                Bitmap icon = BitmapFactory.DecodeResource(context.Resources, Resource.Drawable.new_noti_celeb);

                Notification.Builder builder = new Notification.Builder(context, CHANNEL_ID)
                .SetAutoCancel(true)
                .SetContentIntent(resultPendingIntent)
                .SetContentTitle("Reminder!!")
                .SetSmallIcon(Resource.Drawable.new_noti_celeb)
                .SetLargeIcon(icon)
                .SetColor(ContextCompat.GetColor(context, Resource.Color.material_deep_teal_500))
                .SetContentText("Click for details..")
                .SetVisibility(NotificationVisibility.Public)
                .SetDeleteIntent(resultPendingIntent);
                NotificationManager notificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService);
                notificationManager.CreateNotificationChannel(channel);
                notificationManager.Notify(NOTIFY_ID, builder.Build());
            }
            if (reminder != null)
            {
                MediaPlayer player = MediaPlayer.Create(context, Resource.Drawable.notification_sound);
                player.Start();
            }
        }
    }
}

Here is my code to start timer till notification when a reminder is added:

public void ScheduleReminder(Reminder reminder)
        {
            AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
            Intent myIntent;
            PendingIntent pendingIntent;
            myIntent = new Intent(this, typeof(ReminderNotifications));
            myIntent.PutExtra("date", reminder.Date);
            myIntent.PutExtra("time", reminder.Time);

            var t = reminder.Time.Split(':');
            var ampm = t[1].Split(' ')[1];
            var hrr = Convert.ToDouble(t[0]);
            var min = Convert.ToDouble(t[1].Split(' ')[0]);

            string dateString = Convert.ToString(reminder.Date + " " + hrr + ":" + min + ":00 " + ampm);

            DateTimeOffset dateOffsetValue = DateTimeOffset.Parse(dateString);
            var millisec = dateOffsetValue.ToUnixTimeMilliseconds();

            pendingIntent = PendingIntent.GetBroadcast(this, new Random().Next(), myIntent, 0);
            manager.Set(AlarmType.RtcWakeup, millisec, pendingIntent);
        }

Any help Appreciated!


Solution

  • Well this worked for me:

    using Android.App;
    using Android.Content;
    using Newtonsoft.Json;
    using ReminderApp.HelperRepository;
    using System;
    using ReminderApp.Models;
    using Android.Graphics;
    using Android.Support.V4.Content;
    using Android.Media;
    using Android.OS;
    
    namespace ReminderApp.Notifications
    {
        [Service]
        public class ReminderNotifications : Service
        {
            Reminder reminder;
            public ReminderNotifications()
            {
            }
    
            public override IBinder OnBind(Intent intent)
            {
                throw new NotImplementedException();
            }
    
            public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
            {
                string CHANNEL_ID = "dan51";
    
                var channel = new NotificationChannel(CHANNEL_ID, "FCM Notifications", NotificationImportance.Max)
                {
                    Description = "Firebase Cloud Messages appear in this channel"
                };
    
                long[] urgentVibrationPattern = { 100, 30, 100, 30, 100, 200, 200, 30, 200, 30, 200, 200, 100, 30, 100, 30, 100, 100 };
    
                var alarmAttributes = new AudioAttributes.Builder()
                    .SetContentType(AudioContentType.Sonification)
                    .SetUsage(AudioUsageKind.Notification).Build();
    
                Android.Net.Uri infoAlarmUri = RingtoneManager.GetDefaultUri(RingtoneType.Notification);
    
                channel.EnableLights(true);
                channel.LightColor = Color.Red;
                channel.SetSound(infoAlarmUri, alarmAttributes);
                channel.EnableVibration(true);
                channel.SetVibrationPattern(urgentVibrationPattern);
                channel.SetBypassDnd(true);
                channel.LockscreenVisibility = NotificationVisibility.Public;
    
                string date = intent.GetStringExtra("date");
                string time = intent.GetStringExtra("time");
    
    
                reminder = ReminderHelper.SelectReminderByDateAndTime(this, date, time);
                if (reminder != null)
                {
                    int NOTIFY_ID = 0 + new Random().Next();
                    Intent newIntent = new Intent(this, typeof(ReminderContent));
                    newIntent.PutExtra("reminder", JsonConvert.SerializeObject(reminder));
    
                    Android.Support.V4.App.TaskStackBuilder stackBuilder = Android.Support.V4.App.TaskStackBuilder.Create(this);
                    stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(ReminderContent)));
                    stackBuilder.AddNextIntent(newIntent);
    
                    PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);
                    Bitmap icon = BitmapFactory.DecodeResource(this.Resources, Resource.Drawable.new_noti_celeb);
    
                    Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID)
                    .SetAutoCancel(true)
                    .SetContentIntent(resultPendingIntent)
                    .SetContentTitle("Reminder!!")
                    .SetSmallIcon(Resource.Drawable.new_noti_celeb)
                    .SetLargeIcon(icon)
                    .SetColor(ContextCompat.GetColor(this, Resource.Color.material_deep_teal_500))
                    .SetContentText("Click for details..")
                    .SetVisibility(NotificationVisibility.Public)
                    .SetDeleteIntent(resultPendingIntent);
                    NotificationManager notificationManager = (NotificationManager)this.GetSystemService(Context.NotificationService);
                    notificationManager.CreateNotificationChannel(channel);
                    notificationManager.Notify(NOTIFY_ID, builder.Build());
    
                    PowerManager pm = (PowerManager)this.GetSystemService(Context.PowerService);
                    bool isScreenOn = pm.IsInteractive;
                    if (!isScreenOn)
                    {
                        PowerManager.WakeLock wl = pm.NewWakeLock(WakeLockFlags.ScreenDim | WakeLockFlags.AcquireCausesWakeup, "myApp:notificationLock");
                        wl.Acquire(1);
                    }
                    MediaPlayer player = MediaPlayer.Create(this, Resource.Drawable.notification_sound);
                    player.Start();
                }
                return StartCommandResult.NotSticky;
            }
        }
    }
    

    and in my ScheduleReminder function, I changed GetBroadcast to GetService!

    Only problem with this is that it gives like a 30 second delay before pushing the notification. If anybody has a better solution, please post it!