How to bring Xamrin MAC app to foreground programmatically? - macos

How to bring Xamarin MAC app to foreground programmatically, by clicking on the local notification? How can I achieve it? I have written below code for the local notification. On clicking on that local notification I want to foreground my app.
NSUserNotificationCenter center = NSUserNotificationCenter.DefaultUserNotificationCenter;
NSUserNotification notification = new NSUserNotification();
notification.Title = title;
notification.Subtitle = content;
notification.InformativeText = "TEST";
notification.SoundName = NSUserNotification.NSUserNotificationDefaultSoundName;
notification.DeliveryDate = NSDate.FromTimeIntervalSinceNow(1);
center.ScheduleNotification(notification);
center.DidDeliverNotification += (s, e) =>
{
Console.WriteLine("Notification Delivered");
};
center.DidActivateNotification += (s, e) =>
{
Console.WriteLine("Notification Touched");
};
Thank you in advance,
Vivek

You can use NSWorkspace.SharedWorkspace.LaunchApp to "launch" your app, it does not matter if the app is already running or not, and you can use NSWorkspaceLaunchOptions.HideOthers to bring forward just the last active window of that app.
center.DidActivateNotification += (s, e) =>
{
Console.WriteLine("Notification Touched");
NSWorkspace.SharedWorkspace.LaunchApp(NSBundle.MainBundle.BundleIdentifier, NSWorkspaceLaunchOptions.HideOthers, new NSAppleEventDescriptor(), IntPtr.Zero);
};

Related

Toast notification not working in Xamarin UWP Windows app

I have UWP Windows application, developed under the Xamarin.forms. I have implemented the Toast notifications but I am facing the issue with this. In some Windows 10 systems, it is working and showing the toast notification properly, but in some of the Windows 10 systems (even having the same Windows 10 OS update) it is not working.
Below first code snippets that I have implemented in the Native UWP.
string msg = "Toast Notification Header";
string subMsg = "Toast Notification Title";
var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode(msg));
toastTextElements[1].AppendChild(toastXml.CreateTextNode(subMsg));
//To play the custom sound
var toastNode = toastXml.SelectSingleNode("/toast");
var audio = toastXml.CreateElement("audio");
audio.SetAttribute("src", "ms-appx:///Assets/incoming_message.wav");
audio.SetAttribute("loop", "false");
toastNode.AppendChild(audio);
var toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
Below second code snippets that I have implemented in the Native UWP.
// "With Microsoft.Toolkit.Uwp.Notifications"
// Construct the toast content
ToastContent toastContent = new ToastContent()
{
Visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText()
{
Text = "Toast Notification Header"
},
new AdaptiveText()
{
Text = "Toast Notification Content"
}
}
}
}
};
bool supportsCustomAudio = true;
// If we're running on Desktop before Version 1511, do NOT include custom audio
// since it was not supported until Version 1511, and would result in a silent toast.
if (AnalyticsInfo.VersionInfo.DeviceFamily.Equals("Windows.Desktop")
&& !ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 2))
{
supportsCustomAudio = false;
}
if (supportsCustomAudio)
{
toastContent.Audio = new ToastAudio()
{
Src = new Uri("ms-appx:///Assets/incoming_message.wav")
};
}
// And create the toast notification
ToastNotification notification = new ToastNotification(toastContent.GetXml());
// And then send the toast
ToastNotificationManager.CreateToastNotifier().Show(notification);
Above code snips showing the Toast notification in some Windows 10 system and not working in some other Windows 10 system.
Kindly guide me on this. Thanks in advance.
Regards,
Vivek
Please follow these steps to add toast notification in UWP Project.
Step 1:- Create a new UWP project.
Step 2:- Go to the code-behind and add the namespace.
using Windows.UI.Notifications;
using
NotificationsExtensions.Toasts;
Step 3:- I created a Toast Generic Template like the following code:
public static Windows.Data.Xml.Dom.XmlDocument CreateToast()
{
var xDoc = new XDocument(
new XElement("toast",
new XElement("visual",
new XElement("binding", new XAttribute("template", "ToastGeneric"),
new XElement("text", "C# Corner"),
new XElement("text", "Do you got MVP award?")
)
),// actions
new XElement("actions",
new XElement("action", new XAttribute("activationType", "background"),
new XAttribute("content", "Yes"), new XAttribute("arguments", "yes")),
new XElement("action", new XAttribute("activationType", "background"),
new XAttribute("content", "No"), new XAttribute("arguments", "no"))
)
)
);
var xmlDoc = new Windows.Data.Xml.Dom.XmlDocument();
xmlDoc.LoadXml(xDoc.ToString());
return xmlDoc;
}
Step 4:- Create a toast notification object using XML document.
var xmdock = CreateToast();
var toast = new ToastNotification(xmdock);
Next show the toast using ToastNotificationManager class.
var notifi = Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier();
notifi.Show(toast);
Step 5:- C# code-behind:
private void showToastBtn_Click(object sender, RoutedEventArgs e)
{
var xmdock = CreateToast();
var toast = new ToastNotification(xmdock);
var notifi = Windows.UI.Notifications.ToastNotificationManager.CreateToastNotifier();
notifi.Show(toast);
}
I hope the above code will be useful for you.
Thank you

Player Notifications with Xamarin MediaManager plugin

I'm using the media manager nuget plugin and it's great, but for the life of me, I can't get the lock screen or car bluetooth to show the notifications. I'm using the following to display the notifications (set within OnAppearing)
ViewModel.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "RadioSchedule":
if (listData != null)
{
listData.ItemsSource = null;
var first = ViewModel.RadioSchedule[0];
Device.BeginInvokeOnMainThread(() =>
{
listData.ItemsSource = ViewModel.RadioSchedule;
MediaFile.Metadata.Artist = MediaFile.Metadata.DisplaySubtitle = MediaFile.Metadata.AlbumArtist = first.Artist;
MediaFile.Metadata.Title = MediaFile.Metadata.DisplayTitle = first.Track;
MediaFile.Metadata.DisplayIcon = new Image { Source = "icon".CorrectedImageSource() };
MediaFile.Metadata.BluetoothFolderType = "1";
MediaFile.Type = MediaFileType.Audio;
MediaFile.Url = Constants.RadioStream;
MediaFile.Availability = ResourceAvailability.Remote;
MediaFile.MetadataExtracted = true;
MediaFile.Metadata.Date = DateTime.Now;
MediaFile.Metadata.Duration = 300;
MediaFile.Metadata.Genre = "Rock";
MediaFile.Metadata.TrackNumber = MediaFile.Metadata.NumTracks = 1;
MediaFile.Metadata.DisplayDescription = "Radio Station";
if (!ViewModel.NotificationStarted)
{
if (CrossMediaManager.Current.MediaNotificationManager != null)
CrossMediaManager.Current.MediaNotificationManager.StartNotification(MediaFile);
ViewModel.NotificationStarted = true;
}
CrossMediaManager.Current.MediaNotificationManager?.UpdateNotifications(MediaFile, MediaPlayerStatus.Playing);
});
}
break;
The code itself is being hit (I can set break points and they are hit). I've tried it on and off the UI thread as well.
The playlist comes from a webapi which works fine. The notifier gives unknown/unknown on the device media player (both iOS and Android) and nothing in-car. For Android, the permissions the readme file says to use have also been set.
Is there some sort of magic I have to do to get this to work? This is a Xam.Forms package rather than something native.
The MediaPlayer is started further in the class using the following code
CrossMediaManager.Current.Play(Constants.RadioStream, MediaFileType.Audio, ResourceAvailability.Remote);
Where Constants.RadioStream is the URL of the radio stream.

Toast notification when app in background in Windows phone 8.1

I want to send a toast notification to the action center when my app is in background. So I have set up a Timer, when I start the timer from the app, after 10 sec it produces a toast notification. Now when I try it in the debugger, the toast is produced, even if I press the home button or if I suspend the app using debugger suspend option. But when I deploy the app , it is not producing the toast when I start the timer and click home button. Can anyone suggest a solution for this..?
Adding the Code
private Timer stateTimer;
private void Button_Click(object sender, RoutedEventArgs e)
{
TimerCallback timerDelegate = new TimerCallback(timer_Tick);
TimeSpan delayTime = new TimeSpan(0, 0, 10);
AutoResetEvent autoEvent = new AutoResetEvent(false);
TimeSpan intervalTime = new TimeSpan(0, 0, 0, 0, 0);
Timer notification_timer = new Timer(timerDelegate, autoEvent, delayTime, intervalTime);
}
private void timer_Tick(object state)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode("Download has complete"));
toastTextElements[1].AppendChild(toastXml.CreateTextNode("Download has complete"));
IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
((XmlElement)toastNode).SetAttribute("duration", "long");
((XmlElement)toastNode).SetAttribute("launch", "{\"type\":\"toast\",\"param1\":\"12345\",\"param2\":\"67890\"}");
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
When you're debugging your app is never suspended until you explicitly choose suspension from the lifecycle events in Visual Studio. So when you press the home button your app actually continues running.
This is not the case when running the app without an attached debugger on an actual device. Once you hit the home button your app gets suspended and won't run until it's resumed.
You would have to use a background task to execute code in background.

Geofence in the Background Windows Phone 8.1 (WinRT)

Issue
I'm trying to trigger a BackgroundTask when a Geofence Event (Enter / Exit) occurs in WP8.1 (WinRT). I've written a sample application to try to get it working, but can't seem to be able to do so.
So far, these are the steps I've taken to try to get Geofences working in the background:
Check for Location Capabilities
Create + Register a Geofence
Create + Register a BackgroundTask that listens for LocationTrigger(LocationTriggerType.Geofence);
In my background task, trigger a simple popup notification
Things I have done to Troubleshoot
I have enabled in my app.manifest:
Toast Capable => Yes
Capabilities: Location, Internet(Client &
Server)
Declarations: BackgroundTasks (Location). EntryPoint = BackgroundTask.GeofenceBackgroundTask
My background task is located in a separate project, titled BackgroundTask. It is a WindowsRT Component and contains one class GeofenceBackgroundTask.
Sample Project
The code for the project can be found at this [link](https://github.com/kiangtengl/GeofenceSample):
How To Test
Run the code in the emulator
Set Location to to: Latitude = 01.3369, Longitude = 103.7364
Click the Register Geofence + BackgroundTasks button
Exit the app (press the home button)
Change the current location to anywhere 100m away from the location you set previously. A notification should pop out.
Project Code:
Check for Location Capabilities
public static async Task GetLocationCapabilities()
{
try
{
var geolocator = new Geolocator();
await geolocator.GetGeopositionAsync();
var backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();
Debug.WriteLine("background access status" + backgroundAccessStatus);
}
catch (UnauthorizedAccessException e)
{
Debug.WriteLine(e);
}
catch (TaskCanceledException e)
{
Debug.WriteLine(e);
}
}
Create Geofence
public static void CreateGeofence(BasicGeoposition position, double radius, string id = "default")
{
// The Geofence is a circular area centered at (latitude, longitude) point, with the
// radius in meter.
var geocircle = new Geocircle(position, radius);
// Sets the events that we want to handle: in this case, the entrace and the exit
// from an area of intereset.
var mask = MonitoredGeofenceStates.Entered | MonitoredGeofenceStates.Exited;
// Specifies for how much time the user must have entered/exited the area before
// receiving the notification.
var dwellTime = TimeSpan.FromSeconds(1);
// Creates the Geofence and adds it to the GeofenceMonitor.
var geofence = new Geofence(id, geocircle, mask, false, dwellTime);
try
{
GeofenceMonitor.Current.Geofences.Add(geofence);
}
catch (Exception e)
{
Debug.WriteLine(e);
// geofence already added to system
}
}
Register Background Task
public static async Task RegisterBackgroundTask()
{
try
{
// Create a new background task builder
var geofenceTaskBuilder = new BackgroundTaskBuilder()
{
Name = GeofenceBackgroundTaskName,
TaskEntryPoint = "BackgroundTask.GeofenceBackgroundTask"
};
// Create a new location trigger
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
// Associate the location trigger with the background task builder
geofenceTaskBuilder.SetTrigger(trigger);
var geofenceTask = geofenceTaskBuilder.Register();
// Associate an event handler with the new background task
geofenceTask.Completed += (sender, e) =>
{
try
{
e.CheckResult();
}
catch(Exception error)
{
Debug.WriteLine(error);
}
};
}
catch(Exception e)
{
// Background task probably exists
Debug.WriteLine(e);
}
}
BackgroundTask Code to Trigger Toast
namespace BackgroundTask
{
public sealed class GeofenceBackgroundTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
var toastTemplate = ToastTemplateType.ToastText02;
var toastXML = ToastNotificationManager.GetTemplateContent(toastTemplate);
var textElements = toastXML.GetElementsByTagName("text");
textElements[0].AppendChild(toastXML.CreateTextNode("You have left!"));
var toast = new ToastNotification(toastXML);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}
I've discovered that the above code sample, as well as the above code works. The problem that I was facing was that Windows Phone 8.1 does not automatically trigger a Geofence event. You have to wait a certain amount of time <5 mins before the BackgroundTask is triggered.
This applies to Geofencing in the foreground as well.
I'm busy with the same stuff, and I also noticed this behaviour, but for me its 2 mins.
Unfortunately it always triggers after 2 min, even, if there was no change in location and still inside the fence..

How to play MediaElement in background.?

I am developing an application to play online radio via streaming. I have used MediaElement. But the problem is the player doesn't play in background. I mean as soon as I click on "start" or "back" button on the phone, the streaming as well as the audio stops. I have not tested it on any device, so please inform me if it does happen in simulator but not device. Here is my code..
private void Play()
{
if (mediaElement == null || mediaElement.CurrentState != MediaElementState.Playing)
{
if (SystemTray.ProgressIndicator == null)
SystemTray.ProgressIndicator = new ProgressIndicator();
SystemTray.ProgressIndicator.IsIndeterminate = true;
SystemTray.ProgressIndicator.IsVisible = true;
SystemTray.ProgressIndicator.Text = "Connecting to *********...";
mediaStream = new ********.RadioStream(uri);
mediaStream.StreamSetupComplete += (o, e) =>
{
Dispatcher.BeginInvoke(() =>
{
if (mediaElement != null)
{
LayoutRoot.Children.Remove(mediaElement);
}
mediaElement = new MediaElement();
mediaElement.Volume = 1.0;
LayoutRoot.Children.Add(mediaElement);
mediaElement.SetSource(mediaStream);
SystemTray.ProgressIndicator.IsVisible = false;
});
};
}
}
I want to know the steps to enable this to play in background. Atleast when the user presses "start" button, the audio streaming should not stop.
Also one more problem I have is I have added an ApplicationBarMenu in which I have an "Exit" button. As soon as the user clicks this button the streaming should stop and application should close itself. I am unable to close the application programmatically. Code is give below..
void exit_Click(object sender, EventArgs e)
{
if (playing)
{
MessageBoxResult Choice;
Choice = MessageBox.Show("Media is currently playing, do you want to stop it?", "Stop Player", MessageBoxButton.OKCancel);
if (Choice == MessageBoxResult.OK)
{
ImageBrush brush = new ImageBrush();
brush.ImageSource = new BitmapImage(new Uri(#"Images/play.png", UriKind.Relative));
play.Background = brush;
Stop();
playing = false;
try
{
// if (NavigationService.CanGoBack)
// {
// while (NavigationService.RemoveBackEntry() != null)
// {
// NavigationService.RemoveBackEntry();
// }
// }
}
catch
{
}
}
else
{
}
}
}
Please help me with the proper code. Even if there is any other way to stream media in background other than MediaElement, please suggest that too..
Hoping a reply soon. Thanks to all in advance.
You must use BackgroundAudioPlayer for this.
You should take a look at Microsoft.Phone.BackgroundAudio Namespace too.

Resources