using System; using System.Diagnostics; using System.Collections.Generic; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Navigation; using Microsoft.Phone.Controls; using Microsoft.Phone.Shell; using GPSTracker.Resources; using System.Device.Location; using System.Threading.Tasks; using Windows.Devices.Geolocation; using System.IO.IsolatedStorage; using System.Net.Http; namespace GPSTracker { public partial class MainPage : PhoneApplicationPage { bool firstTimeGettingPosition = true; bool tracking = false; int httpCount = 0; string sessionID; double totalDistanceInMeters = 0; GeoCoordinate previousPosition; // Constructor public MainPage() { InitializeComponent(); BuildApplicationBar(); } // When the page is loaded, make sure that you have obtained the users consent to use their location protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { if (IsolatedStorageSettings.ApplicationSettings.Contains("LocationConsent")) { // User has already opted in or out of Location return; } else { MessageBoxResult result = MessageBox.Show("This app accesses your phone's location. Is that ok?", "Location", MessageBoxButton.OKCancel); if (result == MessageBoxResult.OK) { IsolatedStorageSettings.ApplicationSettings["LocationConsent"] = true; } else { IsolatedStorageSettings.ApplicationSettings["LocationConsent"] = false; } IsolatedStorageSettings.ApplicationSettings.Save(); UpdateAppBar(); } } private async void sendGPS(string latitude, string longitude, string accuracy, string speed, string direction, string locationMethod) { try { httpCount++; // use the websmithing defaultUploadWebsite for testing, change the *phoneNumber* form variable to something you // know and then check your location with your browser here: https://www.websmithing.com/gpstracker/displaymap.php string defaultUploadWebsite = "https://www.websmithing.com/gpstracker/updatelocation.php"; HttpContent httpContent = new FormUrlEncodedContent(new[] { new KeyValuePair<string, string>("latitude", latitude), new KeyValuePair<string, string>("longitude", longitude), new KeyValuePair<string, string>("speed", speed), // in miles per hour new KeyValuePair<string, string>("direction", direction), new KeyValuePair<string, string>("date", DateTime.Now.ToString(@"yyyy-MM-dd\%20HH:mm:ss")), // formatted for mysql datetime format), new KeyValuePair<string, string>("locationmethod", locationMethod), new KeyValuePair<string, string>("distance", (totalDistanceInMeters / 1609).ToString("0.0")), // in miles new KeyValuePair<string, string>("phonenumber", "windowsPhoneUser"), //Windows.Phone.System.Analytics.HostInformation.PublisherHostId), new KeyValuePair<string, string>("sessionid", sessionID), // guid new KeyValuePair<string, string>("accuracy", accuracy), // in meters new KeyValuePair<string, string>("extrainfo", "httpCount-" + httpCount.ToString()), new KeyValuePair<string, string>("eventtype", "windowsPhone") }); HttpClient httpClient = new HttpClient(); HttpResponseMessage responseMessage = await httpClient.PostAsync(defaultUploadWebsite, httpContent); responseMessage.EnsureSuccessStatusCode(); Debug.WriteLine(String.Format("{0:d/M/yy h:mm:ss tt} ", DateTime.Now) + "sendGPS statusCode: " + responseMessage.StatusCode + " httpCount: " + httpCount.ToString()); if (!App.RunningInBackground) { Dispatcher.BeginInvoke(() => { HttpCountTextBlock.Text = " " + httpCount.ToString(); }); } } catch (Exception e) { Debug.WriteLine(String.Format("{0:d/M/yy h:mm:ss tt} ", DateTime.Now + " sendGPS error: " + e.Message)); } } private void TrackLocation_Click(object sender, RoutedEventArgs e) { if ((bool)IsolatedStorageSettings.ApplicationSettings["LocationConsent"] != true) { // The user has opted out of Location. StatusTextBlock.Text = " You have opted out of location. Use the app bar to turn location back on"; return; } if (!tracking) { // If not currently tacking, create a new Geolocator and set options. // Assigning the PositionChanged event handler begins location acquisition. if (App.Geolocator == null) { // Use the app's global Geolocator variable App.Geolocator = new Geolocator(); } // note that you cannot use both ReportInterval and MovementThreshold. MovementThreshold will override ReportInterval App.Geolocator.ReportInterval = 60000; // 1 minute //App.Geolocator.DesiredAccuracy = PositionAccuracy.High; App.Geolocator.DesiredAccuracyInMeters = 100; App.Geolocator.StatusChanged += geolocator_StatusChanged; App.Geolocator.PositionChanged += geolocator_PositionChanged; tracking = true; sessionID = Guid.NewGuid().ToString(); TrackLocationButton.Content = "stop tracking"; } else { // To stop location acquisition, remove the position changed and status changed event handlers. App.Geolocator.PositionChanged -= geolocator_PositionChanged; App.Geolocator.StatusChanged -= geolocator_StatusChanged; App.Geolocator = null; httpCount = 0; totalDistanceInMeters = 0; tracking = false; TrackLocationButton.Content = "start tracking"; StatusTextBlock.Text = " stopped"; } } // The PositionChanged event is raised when new position data is available void geolocator_PositionChanged(Geolocator sender, PositionChangedEventArgs args) { string latitude = args.Position.Coordinate.Latitude.ToString("0.000000"); string longitude = args.Position.Coordinate.Longitude.ToString("0.000000"); string accuracy = args.Position.Coordinate.Accuracy.ToString(); string speed = (args.Position.Coordinate.Speed / 1609 * 3600).ToString(); // in miles per hour string direction = args.Position.Coordinate.Heading.ToString(); string locationMethod = args.Position.Coordinate.PositionSource.ToString(); // note that this is the System.Device.Location.GeoCordinate class with a capital C that has GetDistanceTo method GeoCoordinate currentPosition = new GeoCoordinate(args.Position.Coordinate.Latitude, args.Position.Coordinate.Longitude); if (firstTimeGettingPosition) { firstTimeGettingPosition = false; } else { Double distance = currentPosition.GetDistanceTo(previousPosition); totalDistanceInMeters += distance; } previousPosition = currentPosition; // if (args.Position.Coordinate.Accuracy < 100.0) // in meters // { this.sendGPS(latitude, longitude, accuracy, speed, direction, locationMethod); // } if (!App.RunningInBackground) { Debug.WriteLine(String.Format("{0:d/M/yy h:mm:ss tt}", DateTime.Now) + " positionChanged foreground: " + args.Position.Coordinate.PositionSource.ToString() + " accuracy: " + args.Position.Coordinate.Accuracy.ToString() + "m"); Dispatcher.BeginInvoke(() => { LatitudeTextBlock.Text = " " + latitude; LongitudeTextBlock.Text = " " + longitude; TimeTextBlock.Text = String.Format(" {0:d/M/yy h:mm:ss tt}", DateTime.Now); }); } else { Debug.WriteLine(String.Format("{0:d/M/yy h:mm:ss tt}", DateTime.Now) + " positionChanged background: " + args.Position.Coordinate.PositionSource.ToString() + " accuracy: " + args.Position.Coordinate.Accuracy.ToString() + "m"); } } // The StatusChanged event is raised when the status of the location service changes. void geolocator_StatusChanged(Geolocator sender, StatusChangedEventArgs args) { string status = ""; switch (args.Status) { case PositionStatus.Ready: // Location data is available. status = " ready"; break; case PositionStatus.Initializing: // The location provider is initializing. This is the status if a GPS is the source of location data and // the GPS receiver does not yet have the required number of satellites in view to obtain an accurate position. status = " initializing"; break; case PositionStatus.NoData: // No location data is available from any location provider. LocationStatus will have this value if the // application calls GetGeopositionAsync or registers an event handler for the PositionChanged event, before data // is available from a location sensor. Once data is available LocationStatus transitions to the Ready state. status = " no data"; break; case PositionStatus.Disabled: // The location provider is disabled. This status indicates that the user has not granted the // application permission to access location. status = " location is disabled in phone settings"; break; case PositionStatus.NotInitialized: // An operation to retrieve location has not yet been initialized. LocationStatus will have this value if the // application has not yet called GetGeopositionAsync or registered an event handler for the PositionChanged event. break; case PositionStatus.NotAvailable: status = " not available"; // Not used in WindowsPhone, Windows desktop uses this value to signal that there is no hardware capable to // acquire location information. break; } if (!App.RunningInBackground) { Dispatcher.BeginInvoke(() => { StatusTextBlock.Text = status; }); } Debug.WriteLine(String.Format("{0:d/M/yy h:mm:ss tt} ", DateTime.Now) + "statusChanged:" + status); } // When the page is removed from the backstack, remove the event handlers to stop location acquisition protected override void OnRemovedFromJournal(System.Windows.Navigation.JournalEntryRemovedEventArgs e) { if (App.Geolocator != null) { App.Geolocator.PositionChanged -= geolocator_PositionChanged; App.Geolocator.StatusChanged -= geolocator_StatusChanged; App.Geolocator = null; } } // Allow the user to toggle opting in and out of location with an ApplicationBar menu item. private void BuildApplicationBar() { // Set the page's ApplicationBar to a new instance of ApplicationBar. ApplicationBar = new ApplicationBar(); ApplicationBarMenuItem menuItem = new ApplicationBarMenuItem(); menuItem.Text = "loading"; menuItem.Click += menuItem_Click; ApplicationBar.MenuItems.Add(menuItem); ApplicationBar.IsMenuEnabled = true; } void menuItem_Click(object sender, EventArgs e) { if ((bool)IsolatedStorageSettings.ApplicationSettings["LocationConsent"] == true) { IsolatedStorageSettings.ApplicationSettings["LocationConsent"] = false; } else { IsolatedStorageSettings.ApplicationSettings["LocationConsent"] = false; } UpdateAppBar(); } void UpdateAppBar() { ApplicationBarMenuItem menuItem = (ApplicationBarMenuItem)ApplicationBar.MenuItems[0]; if ((bool)IsolatedStorageSettings.ApplicationSettings["LocationConsent"] == false) { menuItem.Text = "opt in to location"; } else { menuItem.Text = "opt out of location"; } } } }