0

I am working on a simple app that whole purpose is to create a notification on specific days. I am new to the Xamarin and Android stuff so it is possible that I completely messed something up but - the notifications doesn't arrive on scheduled time.

public class MainActivity : AppCompatActivity
{
    private static readonly int NOTIFICATION_ID = 1000;
    private static readonly string CHANNEL_ID = "location_notification";
    private int _count = 0;
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        DateTime curDate = DateTime.Now;
        Xamarin.Essentials.Platform.Init(this, savedInstanceState);

        SetContentView(Resource.Layout.activity_main);
        CreateNotificationChannel();
        ScheduleAlarm(9, 1, 18);
        ScheduleAlarm(9, 1, 19);
        ScheduleAlarm(9, 1, 20);
        ScheduleAlarm(10, 1, 8);
        ScheduleAlarm(10, 1, 9);
        ScheduleAlarm(10, 1, 10);
        var button = FindViewById<Button>(Resource.Id.button);
        button.Click += Button_Click;
    }

    private void Button_Click(object sender, EventArgs e)
    { //test notification logic here}

    private void ScheduleAlarm(int day, int month, int hour)
    {
        Intent alarmIntent = new Intent(this, typeof(AlarmReceiver));
        alarmIntent.SetAction("com.team29.app.ALARM_ACTION");
        PendingIntent pendingIntent;
        if (Build.VERSION.SdkInt >= BuildVersionCodes.S)
        {
            pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, PendingIntentFlags.Immutable);
        }
        else
        {
            pendingIntent = PendingIntent.GetBroadcast(this, 0, alarmIntent, 0);
        }

        AlarmManager alarmManager = (AlarmManager)GetSystemService(Context.AlarmService);

        Calendar calendar = Calendar.Instance;
        //calendar.Add(CalendarField.Minute, 3);
        calendar.Set(CalendarField.DayOfMonth, day);
        calendar.Set(CalendarField.Month, (month-1));
        calendar.Set(CalendarField.HourOfDay, hour);
        calendar.Set(CalendarField.Minute, 30);
        calendar.Set(CalendarField.Second, 0);
        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
            .SetContentTitle("Calendar check")
            .SetContentText($"Day:{calendar.Get(CalendarField.DayOfMonth)}.{calendar.Get(CalendarField.Month)}. {calendar.Get(CalendarField.HourOfDay)}/{calendar.Get(CalendarField.Hour)}:{calendar.Get(CalendarField.Minute)}.")
            .SetSmallIcon(Resource.Drawable.icon_transparent);

        Notification notification = builder.Build();
        NotificationManager notificationManager =
            GetSystemService(Context.NotificationService) as NotificationManager;

        const int notificationId = 11;
        notificationManager.Notify(notificationId, notification);

        alarmManager.SetRepeating(AlarmType.RtcWakeup, calendar.TimeInMillis, AlarmManager.IntervalDay, pendingIntent);
    }

    void CreateNotificationChannel()
    {
        if (Build.VERSION.SdkInt < BuildVersionCodes.O)
        {
            return;
        }

        var channelName = Resources.GetString(Resource.String.channel_name);
        var channelDescription = GetString(Resource.String.channel_description);
        var channel = new NotificationChannel(CHANNEL_ID, channelName, NotificationImportance.Default)
        {
            Description = channelDescription
        };

        var notificationManager = (NotificationManager)GetSystemService(NotificationService);
        notificationManager.CreateNotificationChannel(channel);
    }

and this is my .Resources.AlarmReceiver.cs:

[BroadcastReceiver(Enabled = true, Exported = false)]
[IntentFilter(new[] { "com.team29.app.ALARM_ACTION" })]
public class AlarmReceiver : BroadcastReceiver
{
    public override void OnReceive(Context context, Intent intent)
    {
        Calendar notifCalendar = Calendar.Instance;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "location_notification")
            .SetSmallIcon(Resource.Drawable.icon_transparent)
            .SetContentTitle("Test notification")
            .SetContentText($"Today is {notifCalendar.Get(CalendarField.DayOfMonth)}.{notifCalendar.Get(CalendarField.Month)}.")
            .SetPriority(NotificationCompat.PriorityHigh);
        Notification notification = builder.Build();
        NotificationManagerCompat notificationManager = NotificationManagerCompat.From(context);
        const int notificationId = 118;
        notificationManager.Notify(notificationId, notification);
    }
}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.team29.app" android:installLocation="preferExternal">
    <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="33" />
    <application android:allowBackup="true" android:icon="@drawable/icon" android:label="AppName" android:supportsRtl="true" android:theme="@style/AppTheme">
    <receiver android:name=".Resources.AlarmReceiver" android:exported="false">
      <intent-filter>
        <action android:name="com.team29.app.ALARM_ACTION" />
      </intent-filter>
    </receiver>
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
</manifest>

As you can see, I added debug notification into the ScheduleAlarm as well, just to check if there is some mismatch there. Also when I tried simply calendar.Add and added the 3 minutes, it worked. It maybe took about a minute longer than 3, but the notification arrived. But when I switched from Add to Set, it won't. Now this was January 9th. On the second day, January 10th, a notification arrived at 10:33 and then another one at 12:35. I don't know if there was one in between at 11:30 because as they are set currently, they overwrite each other. I was working with emulator in the beginning, but then I switched to phone as I found that the scheduled notifications don't seem to work on the emulator. There is probably something I am missing or something I used wrongly. I tried browsing but found nothing that would help me yet. Can someone help me please? Thank you.

1
  • Okay it seems I found what was the problem: 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. So I replaced the SetRepeating with SetExact and voila, my notification has arrived precisely when it meant to. Now just to figure out the repeating schedule... Commented Jan 12 at 18:03

0