Xamarin.IOS UILocalNotification.UserInfo is null after closing application - xamarin

Local notification works as it should when application is opened. But there are cases when local notification remains in notification center after closing application. And then clicking on notification starts application and notification data should be passed in options in AppDelegate.FinishedLaunching method. Options contains key UIApplicationLaunchOptionsLocalNotificationKey which has value of type UIKit.UILocalNotification. This value contains UserInfo property which should be filled with notification data. But this UserInfo is null.
Another problem is when local notification remains in notification center and application is restarted. Clicking on notification causes application to start again and it stops immediately.
Have you had such problem? Is it problem with Xamarin? How to handle such scenarios?
Creating notification:
public void DisplayNotification(MessageInfo info)
{
var notificationCenter = UNUserNotificationCenter.Current;
var content = new UNMutableNotificationContent();
content.Title = info.Title;
content.Body = info.Body;
content.UserInfo = IosStaticMethods.CreateNsDictFromMessageInfo(info);
UNNotificationTrigger trigger;
trigger = UNTimeIntervalNotificationTrigger.CreateTrigger(0.1, false);
var id = (++_LastNotificationId).ToString();
var request = UNNotificationRequest.FromIdentifier(id, content, trigger);
notificationCenter.Delegate = new UserNotificationCenterDelegate();
notificationCenter.AddNotificationRequest(request, (error) =>
{
//handle error
});
}
internal class UserNotificationCenterDelegate : UNUserNotificationCenterDelegate
{
public override void WillPresentNotification(UNUserNotificationCenter center, UNNotification notification, Action<UNNotificationPresentationOptions> completionHandler)
{
completionHandler(UNNotificationPresentationOptions.Alert);
}
public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler)
{
//do something
}
}
Handling notification in AppDelegate.FinishedLaunching
if (options != null)
{
var notification = options["UIApplicationLaunchOptionsLocalNotificationKey"] as UIKit.UILocalNotification;
var userInfo = notification.UserInfo;//the userInfo is null
}

It seems NSDictionary should not contain NSNull values. After removing NSNull values everything is OK even if NSDictionary documentation https://developer.apple.com/documentation/foundation/nsdictionary says NSNull is allowed.

Related

Xamarin Forms iOS Remote Notifications Not Displaying

Remote Notifications are not displaying on the device.
We are using iOS 11.2 and Twilio.
We have generated the APN in Apple Developer Portal and exported the
certificate and key into Twilio.
Twilio says the message is "sent," but it never displays on the
device.
The goal is to send a message with a simple header and body text, and have that display as a remote push notification on the device.
The Xamarin documentation seems incomplete, and I cannot find clear instructions on how to handle displaying the notification. I have looked at the Xamarin samples, but they mostly cover local notifications.
Questions are below in the comments. What is missing?
using Foundation;
using UserNotifications;
using UIKit;
namespace MyNotifications.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
protected UIWindow window;
protected string deviceToken = string.Empty;
public string DeviceToken { get { return deviceToken; } }
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
// check for a notification while running
if (options != null)
{
if (options.ContainsKey(UIApplication.LaunchOptionsRemoteNotificationKey))
{
NSDictionary remoteNotification = options[UIApplication.LaunchOptionsRemoteNotificationKey] as NSDictionary;
if (remoteNotification != null)
{
//1) is this necessary to handle??? if so, how to display? what are the properties from the remoteNotification object that contain the text?
}
}
}
//this prompts for permissions, which are set
if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var notificationSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null
);
app.RegisterUserNotificationSettings(notificationSettings);
app.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
UNUserNotificationCenter.Current.GetNotificationSettings((settings) =>
{
var alertsAllowed = (settings.AlertSetting == UNNotificationSetting.Enabled);
});
// Request notification permissions from the user
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert, (approved, err) =>
{
// 2) how do we handle this??? what comes next?
});
return base.FinishedLaunching(app, options);
}
// 3) does this override need to do anything???
public override void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
{
// 4) should all of these trigger a notification? does that have to happen manually?
if (application.ApplicationState == UIApplicationState.Active)
{
ProcessPushNotification(userInfo, true);
}
else if (application.ApplicationState == UIApplicationState.Background)
{
ProcessPushNotification(userInfo, true);
}
else if (application.ApplicationState == UIApplicationState.Inactive)
{
ProcessPushNotification(userInfo, true);
}
}
protected void ProcessPushNotification(NSDictionary userInfo, bool isAppAlreadyRunning)
{
if (userInfo == null) return;
if (isAppAlreadyRunning)
{
// 5) do we need to generate our own view???
}
else
{
// 6) how to handle in the background???
}
}
// APNS background
public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
{
deviceToken = deviceToken.ToString();
}
// Handle errors and offline
public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
{
// 7) what to do here???
}
}
}
Microsoft Docs has a few guides on how to deal with push notifications on both platforms, iOS and Android. Most of them are sending notifications from an Azure Notifications Hub but in this case, it shouldn't make any difference, because your question is about displaying push notifications, and not sending them.
The guide on how to send and receive notifications in a Xamarin.Forms app gives you an idea of the complete end-to-end setup. There are also two slightly different guides with a focus on Azure here and here
And for rendering messages on iOS, if the app is backgrounded, the notification is rendered by iOS without any custom code so if the app is properly configured and signed, you should be able to see a push notifications without any additional client-side code, just make sure you test on a device (sims doesn't support pushes) and valid profile with pushes enabled.

Local Push notification not working in Xamarin iOS

I am using Xamarin.forms and implemented Local push notification for iOS. It is working successfully when I am debugging the app through visual studio even when the app is minimized, the app can able to receive the notification. But while running the app directly without debugging through visual studio, the app is not able to display the notification. Kindly guide me on this.
Then I also tried by releasing the app to the app store but experienced the same, the app is not able to receive the notification it not even in foreground mode.
I already have selected the "Background fetch" property under Background Modes in Info.plist.
I have also added below the line in my FinishedLaunching method
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
Entire Implementation of code is as below
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
try
{
UIApplication.SharedApplication.SetMinimumBackgroundFetchInterval(UIApplication.BackgroundFetchIntervalMinimum);
try
{
if (UIDevice.CurrentDevice.CheckSystemVersion(10, 0))
{
UNUserNotificationCenter.Current.RequestAuthorization(UNAuthorizationOptions.Alert |
UNAuthorizationOptions.Sound |
UNAuthorizationOptions.Sound,
(granted, error) =>
{
if (granted)
{
InvokeOnMainThread(UIApplication.SharedApplication.RegisterForRemoteNotifications);
}
});
}
else if (UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
{
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound,
new NSSet());
UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
UIApplication.SharedApplication.RegisterForRemoteNotifications();
}
else
{
UIRemoteNotificationType notificationTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound;
UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(notificationTypes);
}
bool IsRegistered = UIApplication.SharedApplication.IsRegisteredForRemoteNotifications;
}
catch (Exception ex)
{
UIAlertView avAlert = new UIAlertView("FinishedLaunching Push Notification Exception", ex.Message, null, "OK", null);
avAlert.Show();
}
UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
LoadApplication(new MessengerClient.App());
}
catch (Exception ex)
{
NativeHelper.SendUnhandledException(ex, NativeHelper.iOS + ": FinishedLaunching");
}
return base.FinishedLaunching(app, options);
}
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
/// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
/// Cancel/clear all Local notifications fronm the tray.
UIApplication.SharedApplication.CancelLocalNotification(notification);
/// Cancel/clear all notifications fronm the tray.
UIApplication.SharedApplication.CancelAllLocalNotifications();
}
code for displaying the notification is as below.
UILocalNotification notification = new UILocalNotification();
notification.FireDate = NSDate.FromTimeIntervalSinceNow(1);
notification.AlertAction = title;
notification.AlertBody = content;
notification.AlertTitle = title;
notification.SoundName = UILocalNotification.DefaultSoundName;
notification.ApplicationIconBadgeNumber = 1;
UIApplication.SharedApplication.ScheduleLocalNotification(notification);
I know this is the repeat question but, I tried all the workaround but didn't work for me.
You can have a check with this Notifications in Xamarin.iOS .
iOS applications handle remote and local notifications in almost exactly the same fashion. When an application is running, the ReceivedLocalNotification method or the ReceivedRemoteNotification method on the AppDelegate class will be called, and the notification information will be passed as a parameter.
An application can handle a notification in different ways. For instance, the application might just display an alert to remind users about some event. Or the notification might be used to display an alert to the user that a process has finished, such as synching files to a server.
The following code shows how to handle a local notification and display an alert and reset the badge number to zero:
public override void ReceivedLocalNotification(UIApplication application, UILocalNotification notification)
{
// show an alert
UIAlertController okayAlertController = UIAlertController.Create(notification.AlertAction, notification.AlertBody, UIAlertControllerStyle.Alert);
okayAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
Window.RootViewController.PresentViewController(okayAlertController, true, null);
// reset our badge
UIApplication.SharedApplication.ApplicationIconBadgeNumber = 0;
}
In addition , there is a sample you can download to check . It works no matter in Debug or Release Model in my local site (iOS 13.3).
The effect :
Just add this code in your AppDelegate DidFinishLaunching and notification will start working in the background. BackgroundTask- showNotification may get canceled sometime, for me whenever my dashboard is loaded, I guess as it has multiple API Calls. so add it in your DidEnterBackground Delegate as well with different taskID, to start a new background task. It works fine for me.
nint taskID = yourTaskID;
taskID = application.BeginBackgroundTask("showNotification", expirationHandler: ()=> {
UIApplication.SharedApplication.EndBackgroundTask(taskID);
});

Xamarin Forms - Processing a Notification Click

I have a Xamarin Forms application which raises an Android Notification but I'm having trouble creating a simple page that will interact with the user when they click the Notification.
I understand that in Xamarin.Forms there is only 1 activity and so the pending Intent must be to that mainActivity
I have set the LaunchMode to SingleTop and and Intent Filter to match the Intent name used in the pendingIntent
Now when I click the Notification I do get routed to the OnResume of the MainActivity but I don't understand how to:
1) Recognise that I am in this activity because of the notification click - I tried adding an Extra to the pending Intent but it is not there when I inspect this.Intent.Extras
2) Even if I know that I'm in the activity due to the notification click, how do I launch a specific page from the Activity. I'm new to Xamarin but I can't see how to navigate to a Content Page or access the Navigation Stack.
This must be a really common use case but I can't find anything relevant.
Ensure the you have set LaunchMode.SingleTop on your MainActivity:
LaunchMode.SingleTop
[Activity(~~~, LaunchMode = LaunchMode.SingleTop, ~~~]
public class MainActivity
{
~~~~
In your MainActivity (the FormsAppCompatActivity subclass) add a OnNewIntent override:
OnNewIntent:
protected override void OnNewIntent(Intent intent)
{
base.OnNewIntent(intent);
NotificationClickedOn(intent);
}
Now you can check the intent.Action / intent.HasExtra to determine if it is your notification that was send and thus process it. With Xamarin.Forms the easiest would be to use MessagingCenter to send a message that is subscribed to within your .NetStd/PCL Xamarin.Forms code base.
NotificationClickedOn:
void NotificationClickedOn(Intent intent)
{
if (intent.Action == "ASushiNotification" && intent.HasExtra("MessageFromSushiHangover"))
{
/// Do something now that you know the user clicked on the notification...
var notificationMessage = intent.Extras.GetString("MessageFromSushiHangover");
var winnerToast = Toast.MakeText(this, $"{notificationMessage}.\n\nšŸ£ Please send 2 BitCoins to SushiHangover to process your winning ticket! šŸ£", ToastLength.Long);
winnerToast.SetGravity(Android.Views.GravityFlags.Center, 0, 0);
winnerToast.Show();
}
}
Send notification example:
void SendNotifacation()
{
var title = "Winner, Winner, Chicken Dinner";
var message = "You just won a million StackOverflow reputation points";
var intent = new Intent(BaseContext, typeof(MainActivity));
intent.SetAction("ASushiNotification");
intent.PutExtra("MessageFromSushiHangover", message);
var pending = PendingIntent.GetActivity(BaseContext, 0, intent, PendingIntentFlags.CancelCurrent);
using (var notificationManager = NotificationManager.FromContext(BaseContext))
{
Notification notification;
if (Android.OS.Build.VERSION.SdkInt < Android.OS.BuildVersionCodes.O)
{
#pragma warning disable CS0618 // Type or member is obsolete
notification = new Notification.Builder(BaseContext)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetDefaults(NotificationDefaults.All)
.SetContentIntent(pending)
.Build();
#pragma warning restore CS0618 // Type or member is obsolete
}
else
{
var myUrgentChannel = BaseContext.PackageName;
const string channelName = "Messages from SushiHangover";
NotificationChannel channel;
channel = notificationManager.GetNotificationChannel(myUrgentChannel);
if (channel == null)
{
channel = new NotificationChannel(myUrgentChannel, channelName, NotificationImportance.High);
channel.EnableVibration(true);
channel.EnableLights(true);
channel.SetSound(
RingtoneManager.GetDefaultUri(RingtoneType.Notification),
new AudioAttributes.Builder().SetUsage(AudioUsageKind.Notification).Build()
);
channel.LockscreenVisibility = NotificationVisibility.Public;
notificationManager.CreateNotificationChannel(channel);
}
channel?.Dispose();
notification = new Notification.Builder(BaseContext)
.SetChannelId(myUrgentChannel)
.SetContentTitle(title)
.SetContentText(message)
.SetAutoCancel(true)
.SetSmallIcon(Resource.Drawable.icon)
.SetContentIntent(pending)
.Build();
}
notificationManager.Notify(1331, notification);
notification.Dispose();
}
}

Processing notifications in Xamarin Forms Android

I'm using the library https://github.com/aritchie/notifications and I can create and schedule notifications properly.
I wish to process them in Android so that depending on the notification - it will navigate to a particular page when the user taps on it.
I've found that the below event is fired when I tap on a notification (in my Android Project)
protected override void OnNewIntent(Intent intent)
{
}
However, I can't find any info in the intent from my notification in order to build up navigation to a particular page.
Any advice would be appreciated.
Cheers!
Edit #1 (Adding additional code for a related issue):
If I fire off a notification, and close the app before the notification is received - I receive an error saying the app has crashed. If I receive the notification and close the app - I can load the app from the notification OK.
I have a dependency service which hits the following methods.
public void Remind(DateTime dateTime, string msgtype, string usermedid)
{
DateTime now = DateTime.Now;
var diffinseconds = (dateTime - now).TotalSeconds;
Intent alarmIntent = new Intent(Forms.Context, typeof(AlarmBroadcastReceiver));
alarmIntent.PutExtra("notificationtype", msgtype);
alarmIntent.PutExtra("id", id);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Forms.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = (AlarmManager)Forms.Context.GetSystemService(Context.AlarmService);
//TODO: For demo set after 5 seconds.
alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);
}
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new string[]{"android.intent.action.BOOT_COMPLETED"}, Priority = (int) IntentFilterPriority.LowPriority)]
public class AlarmBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
string notificationtype = intent.GetStringExtra("notificationtype");
PowerManager.WakeLock sWakeLock;
var pm = PowerManager.FromContext(context);
sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Reciever Tag");
sWakeLock.Acquire();
intent = new Intent(Forms.Context, typeof(MainActivity));
intent.PutExtra("notificationtype", notificationtype);
intent.AddFlags(ActivityFlags.IncludeStoppedPackages);
// Instantiate the builder and set notification elements, including pending intent:
NotificationCompat.Builder builder = new NotificationCompat.Builder(Forms.Context)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
.SetAutoCancel(true)
.SetContentIntent(PendingIntent.GetActivity(Forms.Context, 0, intent, 0)).SetContentTitle("Sample Notification")
.SetContentText("Hello World! This is my first action notification!")
.SetTicker("New Notification")
.SetSmallIcon(Resource.Drawable.icon);
// Build the notification:
Android.App.Notification notification = builder.Build();
notification.Flags = NotificationFlags.AutoCancel;
// Get the notification manager:
//NotificationManager notificationManager = Forms.Context.GetSystemService(Context.NotificationService) as NotificationManager;
var manager = NotificationManagerCompat.From(context);
// Publish the notification:
const int notificationId = 0;
manager.Notify(notificationId, notification);
sWakeLock.Release();
}
}
How do I keep my Broadcast Receiver alive when the app is closed?
Ok so it took me some time to figure this one out. OnNewIntent is called when the app is in the background and the notification is clicked on. It is also called each time the app is minimized and the brought back up... so to tell the difference between the 2 events, you need to check the passed in Intent for what extra data is inside it. The extra data would have come from the Intent you made when you first initiated the notification.
Also make sure to set your MainActivity's LaunchMode to LaunchMode.SingleTop so that your app does not get restarted each time the notification is clicked on.
[Activity(LaunchMode = LaunchMode.SingleTop, ....)]
public class MainActivity : FormsApplicationActivity {
....
/// <summary>
/// Called when the app is in the background and a notification is clicked on (also called each time the app is minimized and the brought back up), a new <c>Intent</c> is created
/// and sent out, since we use <c>LaunchMode</c> set to <c>SingleTop</c> this method is called instead of the app being restarted.
/// </summary>
/// <param name="intent">The <c>Intent</c> that was set when the call was made. If started from a notification click, extra <c>string</c> values can be extracted.</param>
protected override void OnNewIntent(Intent intent) {
if(intent.HasExtra("Some special key you made up")) { //Here is where you check for special notification intent extras
//Do something brilliant now that you know a notification was clicked on
}
base.OnNewIntent(intent);
}
To see how you can add data to the Intent you can check out the Xamarin Sport App, but do not get too bogged down in all the other stuff they are doing like I always tend to do. Just focus on the PutExtra part.
Edit #1:
If your app is completely closed, you need to pull the data from the Intent passed into OnCreate and pass it into your App class or do something else with it:
protected override async void OnCreate(Android.OS.Bundle bundle) {
base.OnCreate(bundle);
Forms.Init(this, bundle);
string parameterValue = Intent.GetStringExtra("Some special key you made up"); //This would come in from the Push Notification being clicked on
Console.WriteLine("\nIn MainActivity.OnCreate() - Param Intent Extras: {0}\n", parameterValue);
//MessagingCenter.Send("nothing", ConstantKeys.NewNotification); //Do something special with the notification data
LoadApplication(parameterValue != null ? new App(parameterValue) : new App()); //Do something special with the notification data
}
Edit #2:
Some changes I would recommend to your OnReceive method based on my current code (some may not be necessary, but it is just what I am doing):
Label your Broadcast Receiver
Add stupid Xamarin constructors
Used constant property instead of string for IntentFilter
Remove IntentFilter Priority
Check for null Intent (might not be necessary)
Use Application.Context instead of Forms.Context (I use Forms.Context in other parts of my app so not sure about this one, but
can't hurt)
Do not overwrite the passed in Intent
Create startup intent instead of regular
Add IncludeStoppedPackages flag before pulling out extras
Check for boot completed event
Use Notification.Builder instead of NotificationCompat.Builder (though you might need to change this back)
Add following flags to pendingintent: PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot
-- Use NotificationManager (unless you have a specific reason you commented it out)
[assembly: UsesPermission(Android.Manifest.Permission.Vibrate)]
[assembly: UsesPermission(Android.Manifest.Permission.WakeLock)] //Optional, keeps the processor from sleeping when a message is received
[assembly: UsesPermission(Android.Manifest.Permission.ReceiveBootCompleted)] //Allows our app to be opened and to process notifications even when the app is closed
namespace Your.App.Namespace {
[BroadcastReceiver(Enabled = true, Label = "GCM Alarm Notifications Broadcast Receiver")]
[IntentFilter(new []{ Intent.ActionBootCompleted })]
public class AlarmBroadcastReceiver : BroadcastReceiver {
#region Constructors
// ReSharper disable UnusedMember.Global
public AlarmBroadcastReceiver() { }
public AlarmBroadcastReceiver(IntPtr handle, JniHandleOwnership transfer) : base(handle, transfer) { }
// ReSharper restore UnusedMember.Global
#endregion
public void Remind(DateTime dateTime, string msgtype, string usermedid) {
DateTime now = DateTime.Now;
var diffinseconds = (dateTime - now).TotalSeconds;
Intent alarmIntent = new Intent(Application.Context, typeof(AlarmBroadcastReceiver));
alarmIntent.PutExtra("notificationtype", msgtype);
alarmIntent.PutExtra("id", id);
PendingIntent pendingIntent = PendingIntent.GetBroadcast(Application.Context, 0, alarmIntent, PendingIntentFlags.UpdateCurrent);
AlarmManager alarmManager = (AlarmManager)Application.Context.GetSystemService(Context.AlarmService);
//TODO: For demo set after 5 seconds.
alarmManager.Set(AlarmType.ElapsedRealtime, SystemClock.ElapsedRealtime() + diffinseconds * 1000, pendingIntent);
}
public override void OnReceive(Context context, Intent intent) {
#region Null Check
if(intent == null) {
Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Intent is null\n");
return;
}
#endregion
intent.AddFlags(ActivityFlags.IncludeStoppedPackages);
string action = intent.Action;
Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Action: {0}\n", action);
#region Boot Completed Check
if(action.Equals("android.intent.action.BOOT_COMPLETED")) {
PowerManager pm = PowerManager.FromContext(context);
PowerManager.WakeLock sWakeLock = pm.NewWakeLock(WakeLockFlags.Partial, "GCM Broadcast Receiver Tag");
sWakeLock.Acquire();
Console.WriteLine("\nIn AlarmBroadcastReceiver.OnReceive() - Process Shared Preferences Notifications\n");
#region Process Saved Scheduled Notifications
//Get list of saved scheduled notifications that did not fire off before the device was turned off (I store them in SharedPreferences and delete them after they are fired off)
//Go through the list and reschedule them
#endregion
sWakeLock.Release();
return;
}
#endregion
string notificationtype = intent.GetStringExtra("notificationtype");
Intent startupIntent = Application.Context.PackageManager.GetLaunchIntentForPackage(Application.Context.PackageName);
startupIntent.PutExtra("notificationtype", notificationtype);
// Instantiate the builder and set notification elements, including pending intent:
Notification.Builder builder = new Notification.Builder(Application.Context)
.SetDefaults((int)NotificationDefaults.Sound | (int)NotificationDefaults.Vibrate)
.SetAutoCancel(true)
.SetContentIntent(PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.UpdateCurrent | PendingIntentFlags.OneShot))
.SetContentTitle("Sample Notification")
.SetContentText("Hello World! This is my first action notification!")
.SetTicker("New Notification")
.SetSmallIcon(Resource.Drawable.icon);
// Build the notification:
Android.App.Notification notification = builder.Build();
// Get the notification manager:
NotificationManager notificationManager = Application.Context.GetSystemService(Context.NotificationService) as NotificationManager;
// Publish the notification:
int notificationId = ??;//This should be a real unique number, otherwise it can cause problems if there are ever multiple scheduled notifications
notificationManager.Notify(notificationId, notification);
}
}
}

how to get inputs from wearable devices

I'm implementing a notification system using Xamarin platform, which extends to wearable devices to send the notification. I also want to get the input of user from the wear notification and i have programed it in such away that user can select text or use voice. i followed the following tutorial
http://developer.android.com/training/wearables/notifications/voice-input.html
my code is:
void SendWearNotification (string message, string from)
{
var valuesForActivity = new Bundle();
valuesForActivity.PutString ("message", message);
String groupkey = "group_key_emails";
var intent = new Intent (this, typeof(MyMainActivity));
intent.PutExtras (valuesForActivity);
intent.AddFlags (ActivityFlags.ClearTop);
var pendingIntent = PendingIntent.GetActivity (this, 0, intent, PendingIntentFlags.OneShot);
var builder = new NotificationCompat.Builder (this)
.SetAutoCancel (true)
.SetContentIntent (pendingIntent)
.SetContentTitle (from)
.SetSmallIcon (Resource.Drawable.Iconlogo)
.SetContentText (message) //message is the one recieved from the notification
.SetTicker(from)
.SetGroup (groupkey) //creates groups
.SetPriority((int)NotificationPriority.High);
//
//for viewing the message in second page
var pagestyle= new NotificationCompat.BigTextStyle();
pagestyle.SetBigContentTitle (from)
.BigText (messagefromapp); //message from app is the one rerieved from the wcf app
//second page
var secondpagenotification = new NotificationCompat.Builder (this)
.SetStyle (pagestyle)
.Build ();
//intent for voice input or text selection
var wear_intent = new Intent (Intent.ActionView);
var wear_pending_intent = PendingIntent.GetActivity (this,0,wear_intent,0);
// Create the reply action and add the remote input
setRemoteInput ();
var action = new NotificationCompat.Action.Builder (Resource.Drawable.ic_mes,
GetString (Resource.String.messages), wear_pending_intent)
.AddRemoteInput (remoteinput)
.Build ();
//add it to the notification builder
Notification notification = builder.Extend (new NotificationCompat.WearableExtender ()
.AddPage (secondpagenotification).AddAction(action)).Build ();
//create different notitfication id so that we can as list
if(notification_id<9){
notification_id += 1;
}else{
notification_id=0;
}
var notificationManager = (NotificationManager)GetSystemService(Context.NotificationService);
notificationManager.Notify (notification_id+2, notification);
}
this method is implmented inside GCMListnerService class.
According to the tutorial from the above link, i can retreive the input data user selected or spoke uing the following code:
private void getResponse(Intent intent){
Bundle remoteInput = RemoteInput.GetResultsFromIntent(intent);
if (remoteInput != null) {
Toast.MakeText(this, remoteInput.GetCharSequence(EXTRA_VOICE_REPLY), ToastLength.Short);
}
//return null;
}
My question is when do i call this method, how do i know if user have selected a text en send from the wearable device. if there is any event which i can use.
I got the solution. the method the gets the remote input (the "getresponse" in my case) should be called from the "Oncreate" method of an activity that is used when the notification is created. In my case the actvity i used is "MyMainActivity" when i create the intent of the notification as u can see it in the code. So this means the method will be called twice, when the application runs, and when user reponds from the wear. but ony in the second case will the "remoteinput.getResultfromIntent" will have a value. I hope it will help for someone with same issues.

Resources