2

I'm trying to make alarm program, that will start a page when it goes of. Main problem here is that it is not trowing an error but method OnRecieve() of AlarmReciever class is not starting in time. Also i dunno how to check whether pendingIntent is cancelled or not. And how to get this pendingIntent to cancel if program is restarted.

There some code i tried:

MainPage:

using Android.App;
using Android.Content;

namespace TAlarm;

public partial class MainPage : ContentPage
{
    public PendingIntent pendingIntent;
    Android.Content.Intent intent;
    public AlarmManager alarmManager;

    public MainPage()
    {
        InitializeComponent();
    }

    private void OnTimerClicked(object sender, EventArgs e)
    {
        TimeSpan time = timePicker.Time;

        intent = new Android.Content.Intent(Android.App.Application.Context, typeof(AlarmReceiver));

        pendingIntent = PendingIntent.GetBroadcast(Android.App.Application.Context, 0, intent, PendingIntentFlags.Immutable);

        intent.PutExtra("pendingIntent", pendingIntent);

        alarmManager = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);

        DateTime startTime = DateTime.Today.AddHours(time.Hours).AddMinutes(time.Minutes);
        long interval = 60 * 1000;//AlarmManager.IntervalDay;  60 * 

        alarmManager.SetRepeating(AlarmType.RtcWakeup, startTime.Ticks, interval, pendingIntent);

        text.Text = "Lets start!";

    }

    private void Button_Clicked(object sender, EventArgs e)
    {
        var isPendingIntentValid = (pendingIntent != null);

        if (isPendingIntentValid)
        {
            textMain.Text = "The PendingIntent is still valid";
        }
        else
        {
            textMain.Text = "The PendingIntent is no longer valid";
        }
    }

    private void OnCancelButtonClicked(object sender, EventArgs e)
    {
        // Cancel the PendingIntent
        alarmManager.Cancel(pendingIntent);

    }

}

AlarmReciever:

using Android.Content;

namespace TAlarm
{
    class AlarmReceiver : BroadcastReceiver
    {
        public override async void OnReceive(Context context, Intent intent)
        {
            var m = (MainPage)Microsoft.Maui.Controls.Application.Current.MainPage;

            var nextPage = new NewPage();

            var navigationPage = new NavigationPage();

            await navigationPage.PushAsync(nextPage);

            m.alarmManager.Cancel(m.pendingIntent);
        }

    }
}

I've tried to change:

var navigationPage = new NavigationPage();

into:

var navigationPage = Microsoft.Maui.Controls.Application.Current.MainPage as NavigationPage;

But nothing changed.
So this code should start nextPage when alarm goes off.

All kind of help will be appreciated!

Update: here is added receiver in AndoidManifest.xml:

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" >
        <receiver android:name=".AlarmReceiver" />
    </application>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
    <!--<uses-permission android:name="android.permission.REQUEST_SCHEDULE_EXACT_ALARM"
                     android:maxSdkVersion="29" />-->
</manifest>
  • It seems you didn't register the AlarmReceiver with the `[BroadcastReceiver]` and I didn't see the intent filter for it. Did you regiser it in the AndroidManifest.xml? Can you debug to check the if the OnReceive method triggered or not? – Liyun Zhang - MSFT Apr 26 '23 at 09:43
  • When i'm debugging OnReceive is not triggering. And also i havent registered [BroadcastReceiver] in AndroidManifest.xml, because i had error. How to do it correct in c#? – Pavlo Horvat Apr 26 '23 at 09:56
  • You need to [register the BroadcastReceiver](https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/broadcast-receivers#statically-registering-a-broadcast-receiver-with-an-intent-filter) at first. And the intent filter is the condition when the onreceived method should be triggered. – Liyun Zhang - MSFT Apr 26 '23 at 10:04
  • I've addedd receiver in AndroidManifest.xml and some changes to time: intent.PutExtra("alarmMillis", currentTimeMillis + timeInMillis); timeInMillis is difference in time: alarmTime - DateTime.Now and also currentTimeMillis + timeInMillis is now in SetInexactRepeating(). But it still isn't working in time. – Pavlo Horvat Apr 26 '23 at 18:32
  • Was the OnReceived method triggered? And did you try to test without the alarm manager? – Liyun Zhang - MSFT Apr 27 '23 at 04:22
  • I've tried this: `intent = new Intent(); intent.SetAction(".AlarmReceiver"); Android.App.Application.Context.SendBroadcast(intent);` But OnReceive() also hasn't triggered. – Pavlo Horvat Apr 27 '23 at 18:41

1 Answers1

1

I have create a sample and make the broadcast recevier work.

The BroadcastReceiver:

 [BroadcastReceiver(Exported =true,Enabled =true)]
   public class AlarmReceiver : BroadcastReceiver
    {
        public override async void OnReceive(Context context, Intent intent)
        { //I added a breakpoint here

        }

    }

And the Alarmanager:

private void Button_Clicked(object sender, EventArgs e)
    {
        var intent = new Android.Content.Intent(Android.App.Application.Context, typeof(AlarmReceiver));
        var pendingIntent = PendingIntent.GetBroadcast(Android.App.Application.Context, 0, intent, PendingIntentFlags.Immutable);
        intent.PutExtra("pendingIntent", pendingIntent);
         var alarmManager = (AlarmManager)Android.App.Application.Context.GetSystemService(Context.AlarmService);
        long interval = 60 * 1000;//AlarmManager.IntervalDay;  60 *
        alarmManager.Set(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + interval, pendingIntent);
       // alarmManager.SetRepeating(AlarmType.RtcWakeup, startTime.Ticks, interval, pendingIntent);
    }

The alarmManager.SetRepeating can't work but the alarmManager.Set work. The OnReceive method will trigger after about one minute. I also tested the code in the native android with the android studio and got the same result.

In addition, you can use the special custom intent filter to make the broadcast receiver work. Such as:

[BroadcastReceiver(Exported =true,Enabled =true)]
[IntentFilter(new[] { "com.com.test" })]
   public class AlarmReceiver : BroadcastReceiver
    {
        public override async void OnReceive(Context context, Intent intent)
        { 

        }
    }

And send broadcast:

private void Button_Clicked(object sender, EventArgs e)
    {
     Intent intent1 = new Intent("com.com.test");
     Android.App.Application.Context.SendBroadcast(intent1);
    }

Note: you need to use [BroadcastReceiver(Exported =true,Enabled =true)] instead of registering the broadcast receiver in the AndroidManifest.xml. I don't know why.

Liyun Zhang - MSFT
  • 8,271
  • 1
  • 2
  • 14
  • You're live saver, thank you it worked! So the only problem left is to get some intents of different alarms and to cancel them. But that the least problematic) – Pavlo Horvat Apr 29 '23 at 18:43
  • Which is the reason to use intent.PutExtra("pendingIntent", pendingIntent) when you are configuration the alarm? Thanks so much for the example. – Álvaro García May 25 '23 at 07:51