Creating a notification at a specific time - c#

I have a calendar app that I'm working on, and I need to alert the user to an Upcoming event.
so I want to know what's the best practice to do this, and how should I do it, since the current solution I have isn't even working very well.
the way I do it now is by using an AlarmManager to trigger the a BroadcasReciever that creates and shows the notification.
do I need to use a service? and if so, how should I do it?
CODE:
private void StartDBUpdateAlarm() // Start the alarm manager for event reminder
{
// Get the eventos orded by date (Later than DateTime.Now),
// so that we can get the earliest events
var eventos = eventDao.Select(FromEventos.OrderByDate, DateTime.Now);
if ((eventos.Count > 0)) // Only create notification if there is an event
{
// Create the Intent to pass some info through it to the notification
Intent alarmIntent = new Intent(this, typeof(ReminderReciever));
// Putting the information that will be passed with constant Id's
alarmIntent.PutExtra(GerirUtils.INTENT_TITLE, GetString(Resource.String.main_notification_title));
alarmIntent.PutExtra(GerirUtils.INTENT_INFO, "Info");
alarmIntent.PutExtra(GerirUtils.INTENT_CONTENT, eventos[0].Descricao);
// Creating/Recreating the Pending Intent that will pass the actual information to the notification
PendingIntent pendingIntent = PendingIntent.GetBroadcast(this, GerirUtils.NOTIFICATION_REMINDER_ID, alarmIntent, 0);
// Getting the date and time of the next event, then calculate the diference between DateTime.Now,
// to know how much time it'll be until next event, so that we know when to trigger the notification
DateTime eventDateTime = CalendarHelper.EventDateTime(eventos[0]);
TimeSpan eventMillis = (eventDateTime - GerirUtils.BaseUTCDate); // BaseDate is just the Utc date = 1970/01/01, because the alarm counts millis since then
// Creating and setting the alarm manager
alarm = (AlarmManager)GetSystemService(Context.AlarmService);
alarm.SetExact(AlarmType.RtcWakeup, (long)eventMillis.TotalMilliseconds, pendingIntent);
}
}
BROADCAST RECIEVER CLASS
[BroadcastReceiver(Enabled = true)]
public class ReminderReciever : BroadcastReceiver
{
private string type, title, info, content;
private IList<string> events;
private int notificationId;
private Context context;
public override void OnReceive(Context context, Intent intent)
{
this.context = context;
notificationId = intent.GetIntExtra(GerirUtils.INTENT_ID, -1);
type = intent.GetStringExtra(GerirUtils.INTENT_TYPE);
events = intent.GetStringArrayListExtra(GerirUtils.INTENT_EVENTS);
title = intent.GetStringExtra(GerirUtils.INTENT_TITLE);
info = intent.GetStringExtra(GerirUtils.INTENT_INFO);
content = intent.GetStringExtra(GerirUtils.INTENT_CONTENT);
if(notificationId > -1)
if(type == GerirUtils.NOTIFICATION_TYPE_EVENT_REMINDER)
ShowNotification();
else if(type == GerirUtils.NOTIFICATION_TYPE_ADDED_EVENTS)
ShowNotificationList();
}
private void ShowNotification()
{
Android.Net.Uri sound = RingtoneManager.GetDefaultUri(RingtoneType.Alarm);
NotificationManager mNotificationManager = (NotificationManager)context.GetSystemService(Context.NotificationService);
if (Android.OS.Build.VERSION.SdkInt >= Android.OS.BuildVersionCodes.O)
{
NotificationChannel channel = new NotificationChannel("default", title, NotificationImportance.Default) { Description = content };
mNotificationManager.CreateNotificationChannel(channel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "default")
.SetSmallIcon(Resource.Mipmap.ic_calendario_gerir) // notification icon
.SetContentTitle(title) // title for notification
.SetContentText(content) // message for notification
.SetContentInfo(info) // Info message next to content
.SetSound(sound) // set alarm sound for notification
.SetAutoCancel(true); // clear notification after click
Intent intent = new Intent(context, typeof(MainActivity));
PendingIntent pi = PendingIntent.GetActivity(context, 0, intent, PendingIntentFlags.UpdateCurrent);
mBuilder.SetContentIntent(pi);
mNotificationManager.Notify(0, mBuilder.Build());
}
}

Well,I managed to find the problem after carefully inspecting the code, it looked like I wasn't sending an notificationId, through the intent. the the intent on the BroadcastReviever was always the default -1, so the if statement was always false and, dumb ol' me, didn't put a message warning when the Id was -1, so I had a harder time to find the error then what I would've if I had the message.
and so, the solution was adding this line of code to the program:
private void StartDBUpdateAlarm() // Start the alarm manager for event reminder
{
...
...
if ((eventos.Count > 0)) // Only create notification if there is an event
{
// Create the Intent to pass some info through it to the notification
Intent alarmIntent = new Intent(this, typeof(ReminderReciever));
// MISSING LINE OF CODE
alarmIntent.PutExtra(GerirUtils.INTENT_ID, GerirUtils.NOTIFICATION_REMINDER_ID);
...
...
...
}
}

Related

Ready event handler times out

I'm currently working on a Discord bot written in C#. It is supposed to celebrate the birthday of the users in a server, once they have provided their day and month of birth by sending a message (user-birthday pairs are stored inside a local .txt file). A birthday is celebrated by sending an embed in the main channel of the guild (with which it shares the ID parameter) if the date of execution happens to be someone's birthday.
The content of the Ready event handler of the DiscordSocketClient element within the Program class and a partial call stack are shown below:
public DiscordSocketClient Client;
//...
private async Task Client_Ready()
{
await Commands.CelebrateUsers(Client);
}
also
public static async Task CelebrateUsers(DiscordSocketClient client)
{
DateTime now = DateTime.Now;
List<ulong> users = new List<ulong>();
using (StreamReader reader = new StreamReader(#"docs\birthdays.txt"))
{
string date;
ulong user;
while ((date = reader.ReadLine()) != null)
{
user = Convert.ToUInt64(reader.ReadLine());
int[] dm = date.Split(' ').Select(x=>Convert.ToInt32(x)).ToArray();
if(now.Day == dm[0] && now.Month == dm[1])
{
foreach(SocketGuild g in client.Guilds)
{
if(g.Users.FirstOrDefault(x=>x.Id == user) != null)
await CelebrateUser(user, g);
}
}
}
}
}
private static async Task CelebrateUser(ulong id, SocketGuild guild)
{
var embed = new EmbedBuilder()
{
Title = "Auguri ",
Color = Discord.Color.Green,
ThumbnailUrl = "https://c7.uihere.com/files/240/249/186/hot-air-balloon-birthday-balloon.jpg",
ImageUrl = guild.GetUser(id).GetAvatarUrl(size:900),
Footer =
{
IconUrl = "https://cdn.discordapp.com/avatars/406195350903193600/9629b569007720204f7fe775a9be0aeb.png",
Text = "Generato da DrKikkoCeccato++."
},
Timestamp = DateTimeOffset.Now
};
await guild.DefaultChannel.SendMessageAsync("",embed:embed.Build());
}
However, I have an issue with the last function. The last piece of code (the "SendMessageAsync" part) is not even called.
Upon the initialization of the embed, the Log event of the DiscordSocketClient is fired with the following records:
"A Ready handler is blocking the gateway task."
"A Ready handler has thrown an unhandled exception."
The state changes to "Ready" immediately afterwards. Needless to say, my embed is not being sent.
I don't get what the problem might be, since every action is marked as "asynchronous" (in order to avoid problems with the 3-second timeout of the "Ready" event). Could anyone help me?
Thanks in advance.

Chang Phone to Silent Mode on BroadCast Recieving in Xamarin Android

MainActivity.cs
private void StartAlarm()
{
Intent myIntent;
PendingIntent pendingIntent; myIntent = new Intent(this, typeof(AlarmToastReceiver));
pendingIntent = PendingIntent.GetBroadcast(this, 0, myIntent, 0);
alarm_manager.Set(AlarmType.RtcWakeup, calndr.TimeInMillis, pendingIntent);
}
AlarmToastReceiver.cs
[BroadcastReceiver(Enabled =true)]
public class AlarmToastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "BroadCast Received.", ToastLength.Long).Show();
}
}
I want to Change my Phone mode to Silent at Specific Time automatically on Broadcast receiving, So here i pick the Time from Time-picker, and then set the Ala ram Manager Instance. When the Pending Intent completed , then Broadcast Receiver is active, and a Message is Shown to me,i.e "Broadcast Received.", but here i want to change my Mobile Mode to silent Mode,So how can i do it,can any one help me ? thanks in advance.
You can use the AudioManager to set Silent/Vibrate/Normal.
var audioMgr = (AudioManager)GetSystemService(AudioService);
audioMgr.RingerMode = RingerMode.Silent; // In Oreo(+) this will enable DnD mode
From N onward, ringer mode adjustments that would toggle Do Not Disturb are not allowed unless the app has been granted Do Not Disturb Access.
Re: AudioManager

Pending Intent Extras are not set for Launcher Application

I have created a Launcher application named HomeActivity which has a LaunchMode = SingleTask and CATEGORY_HOME and CATEGORY_LAUNCHER. This activity in turn starts new activities and some other applications as well.
The activity is connected with a Firebase Messaging service to get Push notifications. The Firebase service adds some extras (gathered from the push notification and sends them in Extras in HomeActivity
public override void OnMessageReceived(RemoteMessage message)
{
Notification.Builder builder = new Notification.Builder(this);
builder.SetSmallIcon(Resource.Drawable.Icon);
Intent intent = new Intent(this, typeof(HomeActivity));
intent.AddFlags(ActivityFlags.ClearTop | ActivityFlags.SingleTop);
intent.PutExtra(General.UPDATE_NOTIFIED, true);
if(message.Data != null)
{
if (message.Data.Any())
{
foreach(KeyValuePair<string,string> kv in message.Data)
{
intent.PutExtra(kv.Key, kv.Value);
}
}
}
PendingIntent pendingIntent = PendingIntent.GetActivity(this, 0, intent, PendingIntentFlags.UpdateCurrent);
builder.SetContentIntent(pendingIntent);
builder.SetLargeIcon(BitmapFactory.DecodeResource(Resources, Resource.Drawable.app_logo));
builder.SetContentTitle(message.GetNotification().Title);
builder.SetContentText(message.GetNotification().Body);
builder.SetDefaults(NotificationDefaults.Sound);
builder.SetAutoCancel(true);
NotificationManager notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.Notify(1, builder.Build());
}
Whenever the HomeActivity is on top and a push notification is received and clicked, I can access the Extras in HomeActivity's OnResume function (I have overriden OnNewIntent(Intent intent)).
protected override void OnNewIntent(Intent intent)
{
bool updateNotification = intent.GetBooleanExtra(General.UPDATE_NOTIFIED, false); //Check if Extra is set
this.Intent = intent;
base.OnNewIntent(intent);
}
But when I am in another activity which is launched by the HomeActivity and a Push notification is clicked; the app does return to the HomeActivity but there are no Extras in the Intent.
I have tried all sorts of Flags, including but not limited to NewTask, ClearTask as well.
I am still unable to get why the Extras aren't being set when the notification is clicked at the time another activity is in place. What am I missing here.
Ok so I figured out what the issue is.
The Firebase system WILL NOT fire the OnMessageReceived method if you post a Notification with data (That is a display message).
What is needed to be done is that only data payload in the push notification will fire the OnMessageRecieved function which is responsible for setting the data.
So the notification should be like
{
to: "topic | Registered device",
data:{
data1: "data_value1",
data2: "data_value2",
data3: "data_value3",
}
}

how to stack notification using pushwoosh in xamarin android

how to stack notification using pushwoosh when the app receive multiple message, i have search all over the internet but i didn't get answer. in this reference
public void doOnMessageReceive(String message)
{
// code to run when device receives notification
}
i should create a code in doOnMessageReceive when the app receive message so i create this code
const int intnumer = 100;
var resultIntent = new Intent(this, typeof (MainActivity));
var stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddParentStack(Class.FromType(typeof (MainActivity)));
stackBuilder.AddNextIntent(resultIntent);
var resultPendingIntent = stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);
var builder = new NotificationCompat.Builder(this)
.SetAutoCancel(true)
.SetContentIntent(resultPendingIntent)
.SetContentTitle("Yeah")
.SetSmallIcon(Resource.Drawable.ic_action_home)
.SetContentText(string.Format("The button has been clicked"));
var notificationManager = (NotificationManager) GetSystemService(NotificationService);
notificationManager.Notify(intnumer,builder.Build());
but the behavior is like when i receive the message this pop on notification bar
then click on it this will pop up
anyone can help me?

How to activate an activity using a local notification created from a remote notification

I have successfully created a local notification that starts an activity, but for some reason when this local notification is created from within the handler of a remote notification the activity is not started when the local notification is tapped by the user. No error or exception seems to be thrown.
Below is the code that creates the local notification. Note I'm using Xamarin.
I wonder if it is perhaps somehow permissions related (remote notification handlers maybe cannot create intents to start activities?).
private void CreateNotification(string title, string desc) {
var uiIntent = new Intent(this, typeof(ConversationActivity));
var stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddParentStack(Java.Lang.Class.FromType(typeof(ConversationActivity)));
stackBuilder.AddNextIntent(uiIntent);
PendingIntent pendingIntent = stackBuilder.GetPendingIntent(0, (int)PendingIntentFlags.UpdateCurrent);
var notification = new NotificationCompat.Builder(this)
.SetAutoCancel(true) // Remove the notification once the user touches it
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetSmallIcon(Resource.Drawable.AppIcon)
.SetContentText(desc)
.SetDefaults((int)(NotificationDefaults.Sound | NotificationDefaults.Vibrate))
;
// Set the notification info
// we use the pending intent, passing our ui intent over which will get called
// when the notification is tapped.
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Notify(1, notification.Build());
}
I'm still not sure what was wrong with my original attempt, but I did find out I could fix it by changing the Intent to use a component name instead of an action or activity type:
private void SendNotification() {
var nMgr = (NotificationManager)this.GetSystemService(NotificationService);
var notification = new Notification(Resource.Drawable.AppIcon, "Incoming Dart");
var intent = new Intent();
intent.SetComponent(new ComponentName(this, "dart.androidapp.ContactsActivity"));
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
notification.SetLatestEventInfo(this, "You've got something to read", "You have received a message", pendingIntent);
nMgr.Notify(0, notification);
}
You should be able to call it with typeof(...) as well. The code you posted first is quite different from the latter. Try if this works for you:
private void SendNotification()
{
var nMgr = (NotificationManager)this.GetSystemService(NotificationService);
var notification = new Notification(Resource.Drawable.AppIcon, "Incoming Dart");
var intent = new Intent(this, typeof(ContactsActivity));
//intent.SetComponent(new ComponentName(this, "dart.androidapp.ContactsActivity"));
var pendingIntent = PendingIntent.GetActivity(this, 0, intent, 0);
notification.SetLatestEventInfo(this, "You've got something to read", "You have received a message", pendingIntent);
nMgr.Notify(0, notification);
}
Hello Andrew for me bellow is working fine
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "Hello Chitta!", System.currentTimeMillis());
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("message/rfc822");
intent.putExtra(Intent.EXTRA_EMAIL , new String[]{"jdsjdjbdf#gmail.com"});
intent.putExtra(Intent.EXTRA_SUBJECT, "Hello CR!");
intent.putExtra(Intent.EXTRA_TEXT , "This is the body of email");
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
notification.setLatestEventInfo(getApplicationContext(), "Send an e-mail", "Ha ha", pendingIntent);
notificationManager.notify(742134, notification);
Are talking about something else?

Categories