Pending Intent Extras are not set for Launcher Application - c#

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",
}
}

Related

send push notification from one android app to another when data in sql server database changes

i am trying to understand how an android app on a device could send a notification to another android app on another device when a user adds a record to sql server database or deletes one. i started my research and figured out that i must use FCM. i applied this tutorial https://learn.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/remote-notifications-with-fcm?tabs=windows and it worked but it didn't help me understand how the android app well send the notification. i tried to apply codes from java like this one https://blog.heyday.xyz/send-device-to-device-push-notifications-without-server-side-code-238611c143, i tried to convert it to c# but it didn't work for me. i actually didn't know how to completely write it as c#. i also tried this one: Xamarin android FCM Notification Client to client(phone to phone) but in vain. i searched a lot but i don't know why it feels complicated. if anyone could help me find a tutorial to do so. thanks in advance.
To send notifications from one device to another in Xamarin.android there are several ways:
using firebase cloud messaging when add new row to database
Example:
//process that add new row
//post on FCM
note: receive device must be register device token in firebase cloud messaging
for more details:
https://learn.microsoft.com/en-us/xamarin/android/data-cloud/google-messaging/firebase-cloud-messaging
using task work in background in reciver device and check the number of row in database
example:
Task.Run(()=>{
//code that check number of row
});
if changed call this method :
public void SendNotification(int periority_notification, return_user_info User_info, Context context)
{
/*here intent to open layout when click on notification*/
Intent inten = new Intent(context, typeof(MainActivity));
const int pendingIntentId = 0;
PendingIntent pendingIntent =
PendingIntent.GetActivity(context, pendingIntentId, inten, PendingIntentFlags.OneShot);
var title = User_info.User_Email;
var message = User_info.User_Name.Trim() + " Reserved Request";
using (var notificationManager = NotificationManager.FromContext(context))
{
Notification notification;
if (Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
{
notification = new Notification.Builder(context)
.SetContentIntent(pendingIntent)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetPriority(1)
.SetSmallIcon(Resource.Drawable.carparts)
.SetDefaults(NotificationDefaults.All)
.Build();
}
else
{
var myUrgentChannel = context.PackageName;
const string channelName = "SushiHangover Urgent";
NotificationChannel channel;
channel = notificationManager.GetNotificationChannel(myUrgentChannel);
if (channel == null)
{
channel = new NotificationChannel(myUrgentChannel, channelName, NotificationImportance.High);
channel.EnableVibration(true);
channel.EnableLights(true);
channel.LockscreenVisibility = NotificationVisibility.Public;
notificationManager.CreateNotificationChannel(channel);
}
channel?.Dispose();
notification = new Notification.Builder(context)
.SetContentIntent(pendingIntent)
.SetChannelId(myUrgentChannel)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.carparts)
.Build();
}
notificationManager.Notify(periority_notification, notification);
notification.Dispose();
}
}

Creating a notification at a specific time

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);
...
...
...
}
}

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

FCM Background Notification on IOS app in Xamarin C# not working

The team is developing an IOS app on Xamarin in c# . Now we wanted to use the push notification service of fcm . Tried deploying the app but the issue is : The notifications are not received on ios if the app is in background. Did some research on it but found that the app disconnects from fcm when goes in background. Although tried not to disconnect it by not invoking the function but still the notifications were not received. Just wanted to know whether it's possible to receive the notification on ios while the app is in the background.
Sharing the relevant link and also the code for background that disconnects the app from fcm when it goes in background. Also removed the function call but it did not work.
public override void DidEnterBackground (UIApplication application)
{
// Use this method to release shared resources, save user data,
//invalidate timers and store the application state.
// If your application supports background exection this method is
//called instead of WillTerminate when the user quits.
Messaging.SharedInstance.Disconnect ();
Console.WriteLine (“Disconnected from FCM”);
}
Link:
https://components.xamarin.com/gettingstarted/firebaseioscloudmessaging/true
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
App.Configure ();
// Register your app for remote notifications.
if (UIDevice.CurrentDevice.CheckSystemVersion (10, 0)) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.Current.Delegate = this;
var authOptions = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound;
UNUserNotificationCenter.Current.RequestAuthorization (authOptions, (granted, error) => {
Console.WriteLine (granted);
});
} else {
// iOS 9 or before
var allNotificationTypes = UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound;
var settings = UIUserNotificationSettings.GetSettingsForTypes (allNotificationTypes, null);
UIApplication.SharedApplication.RegisterUserNotificationSettings (settings);
}
UIApplication.SharedApplication.RegisterForRemoteNotifications ();
Messaging.SharedInstance.Delegate = this;
// To connect with FCM. FCM manages the connection, closing it
// when your app goes into the background and reopening it
// whenever the app is foregrounded.
Messaging.SharedInstance.ShouldEstablishDirectChannel = true;
return true;
}
Next put this in the AppDelegate.cs
[Export("messaging:didReceiveRegistrationToken:")]
public void DidReceiveRegistrationToken(Messaging messaging, string fcmToken)
{
// Monitor token generation: To be notified whenever the token is updated.
LogInformation(nameof(DidReceiveRegistrationToken), $"Firebase registration token: {fcmToken}");
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// You'll need this method if you set "FirebaseAppDelegateProxyEnabled": NO in GoogleService-Info.plist
//public override void RegisteredForRemoteNotifications (UIApplication application, NSData deviceToken)
//{
// Messaging.SharedInstance.ApnsToken = deviceToken;
//}
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// Handle Notification messages in the background and foreground.
// Handle Data messages for iOS 9 and below.
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
//Messaging.SharedInstance.AppDidReceiveMessage (userInfo);
if(ConnectionClass.CompanyID != null)
{
SyncData.SyncDataDB();
}
//FirebasePushNotificationManager.CurrentNotificationPresentationOption = UNNotificationPresentationOptions.Alert;
FirebasePushNotificationManager.DidReceiveMessage(userInfo);
//HandleMessage(userInfo);
// Print full message.
//LogInformation(nameof(DidReceiveRemoteNotification), userInfo);
//completionHandler(UIBackgroundFetchResult.NewData);
}
[Export("messaging:didReceiveMessage:")]
public void DidReceiveMessage(Messaging messaging, RemoteMessage remoteMessage)
{
// Handle Data messages for iOS 10 and above.
HandleMessage(remoteMessage.AppData);
LogInformation(nameof(DidReceiveMessage), remoteMessage.AppData);
}
void HandleMessage(NSDictionary message)
{
if (MessageReceived == null)
return;
MessageType messageType;
if (message.ContainsKey(new NSString("aps")))
messageType = MessageType.Notification;
else
messageType = MessageType.Data;
var e = new UserInfoEventArgs(message, messageType);
MessageReceived(this, e);
}
public static void ShowMessage(string title, string message, UIViewController fromViewController, Action actionForOk = null)
{
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var alert = UIAlertController.Create(title, message, UIAlertControllerStyle.Alert);
alert.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, (obj) => actionForOk?.Invoke()));
fromViewController.PresentViewController(alert, true, null);
}
else
{
var alert = new UIAlertView(title, message, null, "Ok", null);
alert.Clicked += (sender, e) => actionForOk?.Invoke();
alert.Show();
}
}
void LogInformation(string methodName, object information) => Console.WriteLine($"\nMethod name: {methodName}\nInformation: {information}");

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