Cant create an alarm in Xamerin Android C# - c#

Copied my teacher's simplified code in order to see if the code i wrote was wrong or somthing yet even her's isnt working. Here is it:
private void BtnAlarm_Click(object sender, EventArgs e)
{
Intent intentAlarm = new Intent(this, typeof(AlarmReceiver));
// #2 - Pending intent - > Broadcast
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 1, intentAlarm, 0);
// #3 - Set Alarm Manager
AlarmManager alarmManager = (AlarmManager)GetSystemService(AlarmService);
//30s
alarmManager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup,
SystemClock.ElapsedRealtime() + 30 * 1000, pendingIntent);
}
The debugger wont run onto this activity:
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "Received intent!", ToastLength.Short).Show();
}
}
Just to be clear, while running her app the alarm was working.

You could use the code below with your AlarmReceiver:
[BroadcastReceiver(Enabled = true, Exported = false)]
public class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "Received intent!", ToastLength.Short).Show();
}
}

Related

Xamarin.forms unexpected alarm trigger in backgroud process in Android

I'm just trying to get a multiple countdown counters, when it reaches individually to 0 I want to sound an alert (without any interaction from the user between one and the next).
The countdown is programmed, for instance, to 5, 4 and 7 minutes.
If it's seconds and the app works with the screen ON or just seconds there's no problem, but as soon as it's minutes, the screen turns off and the phone goes into Doze mode (I think), the resulting times are: 5, 6:26 and 9:58 (instead 5,4 and 7).
I've read a lot of user solutions that have been discussed here, but it doesn't work for me.
The phone runs Android v10.
The code to program the Alarm with SetExactAndAllowWhileIdle:
public void ProgAlarm(int nIntervalo) {
var alarmIntent = new Intent(MainActivity.Instance, typeof(AlarmReceiver));
alarmIntent.PutExtra("Contador", nIntervalo);
var pending = PendingIntent.GetBroadcast(MainActivity.Instance, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
MainActivity.alarM.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup,
SystemClock.ElapsedRealtime()+tiempos[nIntervalo]*1000, pending);
}
And the event triggerd to reprogram the alarm:
[BroadcastReceiver]
public class AlarmReceiver: BroadcastReceiver {
public override void OnReceive(Context context, Intent intent) {
DependencyService.Get<IVarios>().Beep();
int actual=intent.GetIntExtra("Contador",-1);
if (actual!=-1) DependencyService.Get<IVarios>().ProgAlarm(++actual);
}
}
Before the Alarm I tried with PowerManager:
PowerManager pM = (PowerManager)GetSystemService(PowerService);
wakeLock=pM.NewWakeLock(WakeLockFlags.Partial, "CronoMultiple");
[...]
wakeLock.Acquire();
[...]
wakeLock.Release();
and with the flag: WakeLockFlags.AcquireCausesWakeup
But this only works when the screen was always ON, with flag .Partial, the screen turns off and the app stops and the counter doesn't work. In the PC emulator it works (even with adb commands), but not on the phone.
Any solution without using a Service? (I'm new to Xamarin.forms).
Here is a simple sample ,it will alarm every 1 min:
interface IVarios
public interface IVarios
{
void ProgAlarm(int minute);
}
in MainActivity,let it implement IVarios :
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity,IVarios
{
public void ProgAlarm(int minute)
{
Intent intent = new Intent(MainActivity.Instance, typeof(LongRunningService));
intent.PutExtra("Contador", minute);
MainActivity.Instance.StartService(intent);
}
}
in Android project,create LongRunningService :
[Service]
class LongRunningService : Service
{
int minutes;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnCreate()
{
base.OnCreate();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
Android.Util.Log.Error("LongRunningService", "executed");
AlarmManager manager = (AlarmManager)GetSystemService(AlarmService);
int min = intent.GetIntExtra("Contador", -1);
minutes = min != -1 ? min : minutes;
int anHour = minutes * 60 * 1000; // Number of milliseconds
long triggerAtTime = SystemClock.ElapsedRealtime() + anHour;
Intent i = new Intent(this, typeof(AlarmReceiver));
PendingIntent pi = PendingIntent.GetBroadcast(this, 0, i, PendingIntentFlags.UpdateCurrent);
manager.SetExactAndAllowWhileIdle(AlarmType.ElapsedRealtimeWakeup, triggerAtTime, pi);
return StartCommandResult.Sticky;
}
}
in Android project,create AlarmReceiver :
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionBootCompleted })]
class AlarmReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Intent i = new Intent(context, typeof(LongRunningService));
context.StartService(i);
}
}
Then you could call it in your page like :
DependencyService.Get<IVarios>().ProgAlarm(1);

Android Xamarin - Closed app notification

I'd like to create notificiation in my app, which is going to be showed in 10 seconds. It works well, when application is running, but when I close the application, notification is not showed. Here is my code:
My notification service:
[Service]
class NotifyEvent : IntentService
{
protected override void OnHandleIntent(Intent intent)
{
PendingIntent pIntent = PendingIntent.GetActivity(this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(this);
builder.SetContentTitle(Resources.GetString(Resource.String.NotifikaceNadpis));
builder.SetContentText(Resources.GetString(Resource.String.NotifikaceText));
builder.SetSmallIcon(Resource.Drawable.Icon);
builder.SetPriority(1);
builder.SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate);
builder.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis());
Notification notifikace = builder.Build();
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
const int notificationId = 0;
notificationManager.Notify(notificationId, notifikace);
}
}
Class, which starts notification:
public class Notificator
{
public void ShowNotification(Context context)
{
Intent intent = new Intent(context, typeof(NotifyEvent));
var pendingServiceIntent = PendingIntent.GetService(context, 0, intent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarm = (AlarmManager)context.GetSystemService(Context.AlarmService);
alarm.Set(AlarmType.ElapsedRealtimeWakeup, SystemClock.ElapsedRealtime() + 10000, pendingServiceIntent);
}
}
Method in activity:
Notificator not = new Notificator();
not.ShowNotification(this);
My Activity:
[Activity(Label = "Nastavení")]
public class SettingsActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
SetContentView(Resource.Layout.Settings);
Button vynulovatButton = FindViewById<Button>(Resource.Id.buttonRestartDne);
vynulovatButton.Click += VynulovatDen;
}
...
protected void VynulovatDen(object sender, EventArgs e)
{
Notificator not = new Notificator();
not.ShowNotification(this);
}
}
Thanks for every help.
you can try this.
protected override void OnDestroy()
{
Notificator not = new Notificator();
not.ShowNotification(this);
base.OnDestroy();
}
You should keep your service alive when you destroy your application.
add return StartCommandResult.Sticky; in the OnStartCommand method.
start the service OnTaskRemoved function.
Create your service with the Service interface, the IntentService is for Time-consuming operation.
class NotifyEvent : Service
{
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
new Task(() => {
PendingIntent pIntent = PendingIntent.GetActivity(this, 0, intent, 0);
Notification.Builder builder = new Notification.Builder(this);
builder.SetContentTitle("hello");
builder.SetContentText("hello");
builder.SetSmallIcon(Resource.Drawable.Icon);
builder.SetPriority(1);
builder.SetDefaults(NotificationDefaults.Sound | NotificationDefaults.Vibrate);
builder.SetWhen(Java.Lang.JavaSystem.CurrentTimeMillis());
Notification notifikace = builder.Build();
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
const int notificationId = 0;
notificationManager.Notify(notificationId, notifikace);
}).Start();
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
public override void OnTaskRemoved(Intent rootIntent)
{
Intent restartService = new Intent(ApplicationContext, typeof(NotifyEvent));
restartService.SetPackage(PackageName);
var pendingServiceIntent = PendingIntent.GetService(ApplicationContext, 0, restartService, PendingIntentFlags.UpdateCurrent);
AlarmManager alarm = (AlarmManager)ApplicationContext.GetSystemService(Context.AlarmService);
alarm.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + 1000, pendingServiceIntent);
System.Console.WriteLine("service OnTaskRemoved");
base.OnTaskRemoved(rootIntent);
}
}

BroadcastReceiver does not receive broadcast

My BroadcastReceiver does not receive anything. Most likely its my setup that is wrong, because I was not able to find any good examples on this. I need my receiver to receive something in my MainActivity, and change a View. I have almost the same code in an Android project, and here it is working, however BroadcastReceivers seems to be implemented a tiny bit differently in Xamarin (in Android, I can make a new BroadcastReceiver almost like an object, but in Xamarin, or C#, it seems I must make my own class and thus do not have the same possibilities to directly reference the views). If I get this to work, I will post a full working example for everyone too.
Here is how I have tried to set it up:
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
Button button;
protected override void OnCreate(Bundle bundle)
{
// ... various OnCreate() code
LocationBroadcastReciever lbr = new LocationBroadcastReciever();
RegisterReceiver(lbr, new IntentFilter("test"));
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
[BroadcastReceiver]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
/* My program never get this far, so I have not been able
to confirm if the bellow code works or not (its from
another example I saw). */
//EDIT: It does NOT work. See my answer for a working example
string text = intent.GetStringExtra("title");
((MainActivity)context).SetButtonText(text);
InvokeAbortBroadcast();
}
}
And in my IntentService I have this method that actually runs, but never arrives at my receiver.
private void SendBroadcast(double lat, double lng, string activity)
{
Intent intent = new Intent("test");
intent.PutExtra("title", "Updated");
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
}
This is pretty much the same code as I have in my working Android (only tweaked the BroadcastReceiver and minor adjustments to make it compile).
Can anyone see whats wrong??
EDIT
Finally got this whole thing to work. You can see my answer for a full, clean example.
Local
You register receiver as global, but send intents via LocalBroadcastManager. If you want to use this manager you should register your receiver like this:
LocalBroadcastManager.GetInstance(this).RegisterReceiver(lbr, filter);
You can find more about LocalBroadcastManager here.
Global
Or if you want to use global broadcasts, you should create intent by type:
var intent = new Intent(this, typeof(LocationBroadcastReciever));
and send it via android Context (in your service):
this.SendBroadcast(intent);
Also you can use intent with action, but it requires IntentFilter attribute on your receiver:
[IntentFilter(new []{ "test" })]
[BroadcastReceiver]
public class LocationBroadcastReciever : BroadcastReceiver { ... }
For the sake of future search results, here is a clean example of my code with a working BroadcastReceiver
// ** MainActivity
namespace GetLocation.Droid
{
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
//I initialize my view(s) here to access them from outside of OnCreate().
Button button;
//I found this in an Android BroadcastReceiver example of how to access the MainActivity from the BroadcastReceiver.
private static MainActivity ins;
public static MainActivity getInstace()
{
return ins;
}
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
button = FindViewById<Button>(Resource.Id.myButton);
ins = this;
button.Click += delegate
{
Intent intent = new Intent(this, typeof(MyIntentService));
StartService(intent);
};
LocationBroadcastReciever lbr = new LocationBroadcastReciever();
LocalBroadcastManager.GetInstance(this).RegisterReceiver(lbr, new IntentFilter("test"));
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
[BroadcastReceiver]
[IntentFilter(new[] { "test" })]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string text = intent.GetStringExtra("title");
MainActivity.getInstace().SetButtonText(text);
}
}
}
And in my IntentService
namespace GetLocation.Droid
{
[Service]
[IntentFilter(new String[] { "com.mytos.MyIntentService" })]
public class MyIntentService : IntentService
{
protected override void OnHandleIntent(Intent intent)
{
SendBroadcast("My message");
}
private void SendBroadcast(string message)
{
//Here you can of course send whatever variable you want. Mine is a string
Intent intent = new Intent("test");
intent.PutExtra("title", message);
LocalBroadcastManager.GetInstance(this).SendBroadcast(intent);
}
}
}
A couple of things:
First, you need the [IntentFilter] on the receiver. So it should look like....
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new [] { "test" })]
public class LocationBroadcastReciever : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
/* My program never get this far, so I have not been able
to confirm if the bellow code works or not (its from
another example I saw). */
string text = intent.GetStringExtra("title");
((MainActivity)context).SetButtonText(text);
InvokeAbortBroadcast();
}
}
That should get you past your issue.
Second, you should register and unregister the reciever. So you should register in the OnResume and unregister in OnPause.
[Activity(Label = "GetLocation.Droid", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
LocationBroadcastReciever _lbr;
Button button;
protected override void OnCreate(Bundle bundle)
{
// ... various OnCreate() code
}
protected override void OnResume()
{
base.OnResume();
_lbr = new LocationBroadcastReciever();
RegisterReceiver(lbr, new IntentFilter("test"));
}
protected override void OnPause()
{
UnregisterReceiver(_lbr);
base.OnPause();
}
public void SetButtonText(string text)
{
button.Text = text;
}
}
Note: these changes are what I saw different between your code and my code for a working broadcast receiver. Whether my changes are necessary or not, I'm not entirely sure.

Xamarin Android Background Service crashes when the Application get closed

Hello, I want to build an app, in which you can start a service, which runs intependenly and creates a notification, and this service should constantly proof, if the DateTime.Now.Date is bigger than a spezific Date.
When I execute the code below, the notification gets displayed, but when I am closing the app, a few secondes later I get two times an information that the app crashed and I dont know why.
I cant even debug the code because this anly happens when the application is closed....
I hope you can help me thanks!
Here is my code:
namespace App
{
[Activity(Label = "App", MainLauncher = true, Icon = "#drawable/icon")]
public class MainActivity : Activity
{
int count = 1;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.Main);
// Get our button from the layout resource,
// and attach an event to it
Button button = FindViewById<Button>(Resource.Id.MyButton);
button.Click += delegate {
button.Text = string.Format("{0} clicks!", count++);
StartService(new Intent(this, typeof(backgroudservice)));
};
}
}
public class backgroudservice : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
newnotification("Title", "Text: ", 0);
new Task(() => {
DoWork();
Thread.Sleep(1000);
}).Start();
return StartCommandResult.Sticky;
}
public void DoWork()
{
if (DateTime.Now.Date > Convert.ToDateTime("2016-03-29").Date)
{
cancelnotification(0);
StopSelf();
}
}
public override void OnDestroy()
{
base.OnDestroy();
cancelnotification(0);
}
private void newnotification(string titel, string text, int id)
{
Notification.Builder builder = new Notification.Builder(this)
.SetContentTitle(titel)
.SetContentText(text)
.SetSmallIcon(Resource.Drawable.droidlogo_small)
.SetAutoCancel(false)
.SetVisibility(NotificationVisibility.Public)
.SetContentIntent(PendingIntent.GetActivity(this, 0, new Intent(this, typeof(MainActivity)), PendingIntentFlags.OneShot));
// Build the notification:
Notification notification = builder.Build();
notification.Flags = NotificationFlags.NoClear;
//notification.ContentIntent = new Intent(this,typeof(login));
// Get the notification manager:
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
// Publish the notification:
notificationManager.Notify(id, notification);
}
private void cancelnotification(int id)
{
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Cancel(id);
}
}
}
I solved it, I forgot the [Service] above my class, now it works!
[Service]
public class backgroudservice : Service
{
...
}
You might try moving the call to cancelnotification in your service's OnDestroy to before the call to the base method, i.e.:
public override void OnDestroy()
{
cancelnotification(0);
base.OnDestroy();
}

Xamarin android SendBroadcast from IntentService not received by Activity

As in title broadcast from IntentService is not received.
Here's how I have it set up:
[Service]
[IntentFilter(new[] { MyService.ToUploadCountNotification })]
public class MyService : IntentService
{
public const string ToUploadCountNotification = "MyService.ToUploadCountNotification";
public const string ToUploadCount = "MyService.ToUploadCount";
protected override void OnHandleIntent(Intent intent)
{
while (Count > 0)
{
var uploadCount = new Intent();
uploadCount.SetAction(ToUploadCountNotification);
uploadCount.PutExtra(ToUploadCount, localHarryys.Count);
Log.Debug("Sync service", "sending broadcast");
SendBroadcast(intent, null);
}
}
}
public class MyServiceBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
//throw new NotImplementedException();
Toast.MakeText(context,
string.Format("Uploading...({0})", intent.Extras.GetInt(MyService.ToUploadCount)),
ToastLength.Short).Show();
}
}
In activity I register receiver:
protected override void OnResume()
{
base.OnResume();
RegisterReceiver(_receiver, new IntentFilter(MyHarryysSyncService.ToUploadCountNotification));
Log.Debug("Browse", "Receiver registered");
}
protected override void OnPause()
{
base.OnPause();
UnregisterReceiver(_receiver);
Log.Debug("Browse", "Receiver unregistered");
}
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
if (requestCode == 0)
{
StartService(new Intent(this, typeof(MyService)));
}
base.OnActivityResult(requestCode, resultCode, data);
}
In my research all I could find was
make sure that you register it correctly in activity - I believe I do I've also put it in OnCreate/OnDestroy see below
activity might not be visible/active at the time service sends broadcast - From debug window I get correct order of messages Receiver registered / sending broadcast so I'm assuming that activity is active and receiver registered.
I've tested couple more things.
After line StartService(new Intent(this, typeof(MyService)))
I've put SendBroadcast(new Intent(MyService.ToUploadCountNotification), null);
that didn't work till I've move registration to OnCreate/OnDestroy. Unfortunatelly broadcast from service was still not received
I've registered receiver in androidmanifest.xml that works as well but I wanted to have it registered dynamically by activity as there might be different behaviour depending on active activity.
So my question is what else am I doing wrong there. What else can I check.

Categories