static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken) { if (!CLLocationManager.LocationServicesEnabled) { throw new FeatureNotEnabledException("Location services are not enabled on device."); } await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>(); // the location manager requires an active run loop // so just use the main loop var manager = MainThread.InvokeOnMainThread(() => new CLLocationManager()); var tcs = new TaskCompletionSource <CLLocation>(manager); var listener = new SingleLocationListener(); listener.LocationHandler += HandleLocation; cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout); cancellationToken.Register(Cancel); manager.DesiredAccuracy = request.PlatformDesiredAccuracy; manager.Delegate = listener; #if __IOS__ // we're only listening for a single update manager.PausesLocationUpdatesAutomatically = false; #endif manager.StartUpdatingLocation(); var clLocation = await tcs.Task; return(clLocation?.ToLocation()); void HandleLocation(CLLocation location) { manager.StopUpdatingLocation(); tcs.TrySetResult(location); } void Cancel() { manager.StopUpdatingLocation(); tcs.TrySetResult(null); } }
static async Task <Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken) { await Permissions.EnsureGrantedAsync <Permissions.LocationWhenInUse>(); var locationManager = Platform.LocationManager; var enabledProviders = locationManager.GetProviders(true); var hasProviders = enabledProviders.Any(p => !ignoredProviders.Contains(p)); if (!hasProviders) { throw new FeatureNotEnabledException("Location services are not enabled on device."); } // get the best possible provider for the requested accuracy var providerInfo = GetBestProvider(locationManager, request.DesiredAccuracy); // if no providers exist, we can't get a location // let's punt and try to get the last known location if (string.IsNullOrEmpty(providerInfo.Provider)) { return(await GetLastKnownLocationAsync()); } var tcs = new TaskCompletionSource <AndroidLocation>(); var allProviders = locationManager.GetProviders(false); var providers = new List <string>(); if (allProviders.Contains(LocationManager.GpsProvider)) { providers.Add(LocationManager.GpsProvider); } if (allProviders.Contains(LocationManager.NetworkProvider)) { providers.Add(LocationManager.NetworkProvider); } if (providers.Count == 0) { providers.Add(providerInfo.Provider); } var listener = new SingleLocationListener(locationManager, providerInfo.Accuracy, providers); listener.LocationHandler = HandleLocation; cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout); cancellationToken.Register(Cancel); // start getting location updates // make sure to use a thread with a looper var looper = Looper.MyLooper() ?? Looper.MainLooper; foreach (var provider in providers) { locationManager.RequestLocationUpdates(provider, 0, 0, listener, looper); } var androidLocation = await tcs.Task; if (androidLocation == null) { return(null); } return(androidLocation.ToLocation()); void HandleLocation(AndroidLocation location) { RemoveUpdates(); tcs.TrySetResult(location); } void Cancel() { RemoveUpdates(); tcs.TrySetResult(listener.BestLocation); } void RemoveUpdates() { for (var i = 0; i < providers.Count; i++) { locationManager.RemoveUpdates(listener); } } }