how to disable location services in my WP7 app - windows-phone-7

I'm making a windows phone app which displays where the closest campus shuttles are (among other things). Windows Phone requires apps to allow the users to turn off location services within the app.
So, I added a toggle for it on a settings page, but it doesn't seem to do anything.
Here's the viewmodel where I declared the geocoordinatewatcher.
public MainViewModel()
{
geoWatcher = new GeoCoordinateWatcher();
if (geoWatcher.TryStart(false, TimeSpan.FromSeconds(30) )==false )
{ MessageBox.Show("The location services are disabled for this app. We can't detect the nearby stops. To turn location services back on, go to the settings page.", "Warning", MessageBoxButton.OK); }
}
private GeoCoordinateWatcher geoWatcher;
public GeoCoordinateWatcher GeoWatcher
{
get
{
return geoWatcher;
}
set
{
if (geoWatcher != value)
{
geoWatcher = value;
NotifyPropertyChanged("GeoWatcher");
}
if(geoWatcher.Status== GeoPositionStatus.Disabled)
{
geoWatcher.Stop();
}
}
}
and here's the bulk of the settings page
public SettingsPage()
{
InitializeComponent();
if (App.ViewModel.GeoWatcher.Status == GeoPositionStatus.Ready)
{
locToggle.IsChecked = true;
locToggle.Content = "On";
}
else
{
locToggle.IsChecked = false;
locToggle.Content = "Off";
}
}
private void toggleChecked(object sender, RoutedEventArgs e)
{
locToggle.Content = "On";
App.ViewModel.GeoWatcher.Start();
MessageBox.Show("this is the status " + App.ViewModel.GeoWatcher.Status.ToString(), "Info", MessageBoxButton.OK); //for debugging
}
private void toggleUnchecked(object sender, RoutedEventArgs e)
{
locToggle.Content = "Off";
App.ViewModel.GeoWatcher.Stop();
MessageBox.Show("this is the status " + App.ViewModel.GeoWatcher.Status.ToString(), "Info", MessageBoxButton.OK); //for debugging
}
When i turn the toggle off and click away from the Settings page, and go back to it, the toggle is re-enabled again.
I tried putting in a message box on the functions to debug but the status always says "Ready" and my app still uses the location services, even when I turn the toggle to "off".
Is there something I should be adding to the code so that the toggle will properly make my app stop using location services across my app if it's disabled on the settings page? Or should I be checking something else besides GeoPositionStatus? I couldn't figure out a way to make my app actually change the location services permissions or PositionStatus.
I looked at this page here, but am still confused since I followed the example at the bottom of the page, to no avail. I searched StackOverflow but I couldn't seem to find a similar question with WP. I also posted this on the AppHub forums though.
Thanks!

In your MainViewModel you need to check if they have allowed location services before you use the geocoordinatewatcher.
if(settings.LocationAllowed)
{all your code for using location}

You should probably take into account a few factors/points, most of which, you have. Anyway, you might find these helpful.
Your application settings toggle should only show when the location service is switched on on the device
GeoPositionStatus is just an Enum which contains the types of statuses.
StatusChanged is the event which is to be handled to check for changes in the device settings. See this.
You cannot change the device settings from the application.
Add event handlers before you call start on the watcher.

Related

How to change state of Bluetooth on iOS is PowerOn on Xamarin Forms?

On iOS, I only can check state of Bluetooth. I'm find the solutions on network and use it.
public class CallBluetoothIphoneService : ICallBlueTooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager();
if (bluetoothManager.State == CBCentralManagerState.PoweredOff|| bluetoothManager.State == CBCentralManagerState.Unknown)
// Does not go directly to bluetooth on every OS version though, but opens the Settings on most
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
}
But when I try turn off Bluetooth and test code, state of bluetooth is "Unknown".
Then I run code, device open settings, toggle button has color green (turn on bluetooth), but when I check state of Bluetooth in code, State of Bluetooth is "Unknown", is not "Power on".
I'm using Xamarin 3.3 and test on device iOS version 12.0.
I am not sure exactly what you want to do, but if your intent is to open the Bluetooth settings page, this:
UIApplication.SharedApplication.OpenUrl(new NSUrl("App-Prefs:root=Bluetooth"));
won't work. Apple has at some points allowed this (iOS 8 IIRC) and at other points it has disallowed this (most versions of iOS). See this long SO thread about this issue: How to open Settings programmatically like in Facebook app?
Regardless, there is no need. When iOS detects that your app has created a CBCentralManager type with delegate, iOS will display an alert to the user that allows them to go to the bluetooth settings to enable bluetooth by tapping the "Settings" button in the alert.
As far as always getting state as "Unknown", you need to check the state in the delegate for the CBCentralManager. You cannot use the parameterless CBCentralManager constructor new CBCentralManager();. Check the apple docs: https://developer.apple.com/documentation/corebluetooth/cbcentralmanager?language=objc and note that there are only two listed init methods, one that takes delegate and queue parameters, and one that takes delegate, queue, and options parameters, although no one complains if you use the parameterless constructor... but you will never get the correct state if you use it. See: https://stackoverflow.com/a/36824770/2913599
So try this:
public class CallBluetoothIphoneService : ICallBluetooth
{
public void LaunchBluetoothOnPhone()
{
try
{
// Is bluetooth enabled?
var bluetoothManager = new CBCentralManager(new MySimpleCBCentralManagerDelegate(), DispatchQueue.CurrentQueue);
// This will always show state "Unknown". You need to check it in the delegate's UpdatedState method
Console.WriteLine($"State: {bluetoothManager.State.ToString()}");
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
}
public class MySimpleCBCentralManagerDelegate : CBCentralManagerDelegate
{
override public void UpdatedState(CBCentralManager mgr)
{
// You can check the state in this delegate method
Console.WriteLine($"UpdatedState: {mgr.State.ToString()}");
if (mgr.State == CBCentralManagerState.PoweredOn)
{
//Passing in null scans for all peripherals. Peripherals can be targeted by using CBUIIDs
CBUUID[] cbuuids = null;
mgr.ScanForPeripherals(cbuuids); //Initiates async calls of DiscoveredPeripheral
//Timeout after 30 seconds
var timer = new Timer(30 * 1000);
timer.Elapsed += (sender, e) => mgr.StopScan();
}
else
{
//Invalid state -- Bluetooth powered down, unavailable, etc.
System.Console.WriteLine("Bluetooth is not available");
}
}
public override void DiscoveredPeripheral(CBCentralManager central, CBPeripheral peripheral, NSDictionary advertisementData, NSNumber RSSI)
{
Console.WriteLine("Discovered {0}, data {1}, RSSI {2}", peripheral.Name, advertisementData, RSSI);
}
}
Bottom line: always create a CBCentralManager object with one of the following constructors:
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue)
CBCentralManager(ICBCentralManagerDelegate, DispatchQueue, CBCentralInitOptions)

How can I correctly close an application in Application_Launching event

I want to close my app if network not available.
I check network in App.cs:
private void Application_Launching(object sender, LaunchingEventArgs e)
{
if (!NetworkInterface.GetIsNetworkAvailable())
{
//close my app
}
else
{
//continue to work
}
}
Is there a better way to do it?
Thanks in advance.
just add reference to Microsoft.Xna.Framework.Game i'm sure you can achieve exit with this code and it will be ok. if you wanna show message box you have to do it in main page
what i would do:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (!NetworkInterface.GetIsNetworkAvailable())
{
MessageBoxResult m = MessageBox.Show(Sorry, no internet connection is available.do you want to exit the application , "Oops...", MessageBoxButton.OKCancel);
if (m == MessageBoxResult.OK)
{
var g = new Microsoft.Xna.Framework.Game();
g.Exit();
}
}
}
you should provide a "gentle" way for closing
5.1.2 - App closure
The app must handle exceptions raised by the any of the managed or native System API
and not close unexpectedly. During the certification process, the app is monitored
for unexpected closure. An app that closes unexpectedly fails certification. The app
must continue to run and remain responsive to user input after the exception is
handled.
for more information visit this link
Application.Current.Terminate();

Lock app with password

In WP application we need to provide user option to lock app with password.
As I understand WP app lifecycle, I need to put navigation to LockPage in App.Application_Activated, App.Application_Deactivated and start page, but I can not use NavigationService in App class...
I do not want to put navigation code to lock page in each other pages, or there is no other options?
I writed own solution, but may be it is not so elegant as it could be.
App locking logic: User enable app locking with password, we handling Application_Deactivated and Application_Closing events in App class and marking app as locked if user enabled this option. Then, on each page we should put check: is app currently locked and if it is, we should navigate to AppLockedWithPasswordPage. On AppLockedWithPasswordPage we need to check user`s password, if it is correct call NavigationService.GoBack().
So we need to do 6 steps:
You should choose where to save IsAppCurrentlyLocked (bool flag), AppLockPassword (string) and IsUserEnabledAppLockWithPassword (bool flag). I had chosen IsolatedStorageSettings
Create AppLockedWithPassword page, where you need to show TextBox and Button, do not forget to provide option for user to reset AppLock of course with deleting app data
AppLockedWithPasswordPage should prevent BackButton navigation, so preventing it:
// AppLockedWithPasswordPage
protected override void OnBackKeyPress(CancelEventArgs e)
{
// Preventing back key navigation
e.Cancel = true;
}
Check password on button click
// AppLockedWithPasswordPage
private void UnlockAppButton_Click(object sender, RoutedEventArgs e)
{
if (PasswordBox.Password.Equals(IsolatedStorageSettings["AppLockPassword"]))
{
NavigationService.GoBack();
}
else
{
// Say user, that password incorrect, etc...
}
}
In App class find Application_Deactivated (to handle app minimizing (windows button)) and Application_Closing (to handle when user closing app) methods, we should mark app as locked if user enabled this option when this events happens
private void SetIsAppCurrentlyLockedFlagIfUserEnabledAppLocking()
{
if ((bool)IsolatedStorageSettings["IsUserEnabledAppLockWithPassword"])
{
IsolatedStorageSettings["IsAppCurrentlyLocked"] = true;
}
}
private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
SetIsAppCurrentlyLockedFlagIfUserEnabledAppLocking();
}
private void Application_Closing(object sender, ClosingEventArgs e)
{
SetIsAppCurrentlyLockedFlagIfUserEnabledAppLocking();
}
And final step, on all pages you want to lock you should add check in OnNavigatedTo method which will navigate to AppLockedWithPasswordPage if app is currently locked
// Create some class, like PagesUtils or so on with check method
private static Uri uriToAppLockedWithPasswordPage = new Uri("pathToAppLockedWithPasswordPage", UriKind.Relative);
public static void NavigateToAppLockedWithPasswordPageIfAppLocked(PhoneApplicationPage page)
{
if ((bool)IsolatedStorageSettings["IsAppCurrentlyLocked"])
{
page.NavigationService.Navigate(uriToAppLockedWithPasswordPage);
}
}
// In each page you want to lock add
protected override void OnNavigatedTo(NavigationEventArgs e)
{
PagesUtils.NavigateToAppLockedWithPasswordPageIfAppLocked();
base.OnNavigatedTo();
}
P.S. of course real code is much better, this is just simple example, I hope it will help you
You should add the check in the Application_Launching and Application_Activated events.
The launching event for when the app is first opened and the activated one for when the user returns to the app after having left to do something else.
Have these events both set a flag and have the base page that all your pages inherit from check for this flag when navigated to. The check should be for if the flag is set, if it is, show the login prompt and then clear the flag after successful password entry.
This approach will handle FAS, FAR & deep linking, in addition to starting the app normally.
Beware Some choosers will trigger the activated event when they return to the app. Add extra handling for these as appropriate / if necessary.
Why not create a start page where the passwords is entered?
For instances you have your MainPage.xaml, create a InsertPasswordPage.xaml reference it on WMAppManifest as the start page:
<DefaultTask Name="_default" NavigationPage="InsertPasswordPage.xaml" />
And insert all the password logic on the InsertPasswordPage.xaml, when the user successfully logins just navigate to your main page ;)
EDIT: As Gambit said if the user pressed the back button he will return to the insert password page, but you can solve this by removing from the backstack the page after the user logged in.

User consent to stop the playing audio

Windows Phone 7.5 / Silverlight app
If user is playing music / radio on their phone and they try to launch my application, I want to give user an option to stop the currently playing option.
Working fine:
The message popup shows up fine. When I select Cancel, the popup closes, the music keeps playing and my app starts/works as normal.
Issue:
If I select Ok i.e. to stop the currently playing music on phone, the music stops but at the same time my app also exits.
Any ideas what I am doing wrong here?
Here is the code I am using. I call this method on launching:
private void CheckAudio()
{
if (FMRadio.Instance.PowerMode == RadioPowerMode.On)
{
MessageBoxResult Choice;
Choice = MessageBox.Show("For better user experience with this application it is recommended you stop other audio applications. Do you want to stop the radio?", "Radio is currently playing!", MessageBoxButton.OKCancel);
if (Choice == MessageBoxResult.OK)
{
FMRadio.Instance.PowerMode = RadioPowerMode.Off;
}
}
if (MediaPlayer.State == MediaState.Playing)
{
MessageBoxResult Choice;
Choice = MessageBox.Show("For better user experience with this application it is recommended you stop other audio/video applications. Do you want to stop the MediaPlayer?", "MediaPlayer is currently playing!", MessageBoxButton.OKCancel);
if (Choice == MessageBoxResult.OK)
{
MediaPlayer.Stop();
}
}
}
Update:
I posted my solution below. Do let me know if I am doing anything wrong.
I found the following error was being thrown:
FrameworkDispatcher.Update has not been called. Regular
FrameworkDispatcher. Update calls are necessary for fire and forget
sound effects and framework events to function correctly.
So I added this code and now it is working fine. Now upon clicking OK, the music player stops and my app launches fine. I call the SetupTimer method from InitializeComponent in App.xaml.cs
private GameTimer gameTimer;
private void SetupTimer()
{
gameTimer = new GameTimer();
gameTimer.UpdateInterval = TimeSpan.FromMilliseconds(33);
// Call FrameworkDispatcher.Update to update the XNA Framework internals.
gameTimer.Update += new EventHandler<GameTimerEventArgs>(gameTimer_Update); //delegate { try { FrameworkDispatcher.Update(); } catch { } };
// Start the GameTimer running.
gameTimer.Start();
// Prime the pump or we'll get an exception.
FrameworkDispatcher.Update();
}
void gameTimer_Update(object sender, GameTimerEventArgs e)
{
try { FrameworkDispatcher.Update(); }
catch { }
}
If anybody sees any problem/issue with the above please do let me know. Thanks.

WP7 Navigation - NullReferenceException

I need to navigate to a certain page the first time my app is run, to gather login details etc. I'm using IsloatedStorageSettings to save a value to determine if this is the first run of the app or not, which works fine.
My problem is actually navigating to my 'first run' page when the app is run for the first time, using NavigationService, it seems NavigationService is not created at this point so is still null. When is NavigationService created or how can I work around this?
My code (in the constructor of my main page:
if ((bool)settings["firstRun"])
{
if (NavigationService != null)
{
NavigationService.Navigate(new Uri("/FirstRun.xaml", UriKind.Relative));
}
else
{
MessageBox.Show("Navigation service must be null?"); //always prompts
}
}
else
{
InitializeComponent();
}
Peter Torr has a great blog post on the ins and outs of redirecting for the initial navigation, though for user login I'd suggest that you either use a full screen popup or have a login control on your "normal" start page and toggle visibility based on your first run condition.
Add in class
private bool m_onNavigatedToCalled = false;
In ctor
this.LayoutUpdated += new EventHandler(MainPage_LayoutUpdated);
Then in code
void MainPage_LayoutUpdated(object sender, EventArgs e)
{
if (m_onNavigatedToCalled)
{
m_onNavigatedToCalled = false;
Dispatcher.BeginInvoke(() =>
{
if (NavigationService != null)
{
MessageBox.Show("Navigation not null?"); //always prompts
}
else
{
MessageBox.Show("Navigation service must be null?");
}
//StartApp(); do all stuff here to keep the ctor lightweight
}
);
}
}

Resources