Skip to content

Commit

Permalink
fix: Geolocator methods invoked on Dispatcher when necessary
Browse files Browse the repository at this point in the history
  • Loading branch information
juliecantin committed Sep 14, 2020
1 parent a5fdb6f commit e67e139
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 55 deletions.
23 changes: 18 additions & 5 deletions src/Uno.UWP/Devices/Geolocation/Geolocator.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
using Android.Locations;
using Android.OS;
using Android.Runtime;
using Uno.Extensions;
using Windows.Extensions;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Foundation.Metadata;
using Windows.UI.Core;

namespace Windows.Devices.Geolocation
{
public sealed partial class Geolocator : Java.Lang.Object, ILocationListener
Expand All @@ -39,12 +42,22 @@ private void TryInitialize()

public Task<Geoposition> GetGeopositionAsync()
{
TryInitialize();
if (CoreDispatcher.Main.HasThreadAccess)
{
TryInitialize();

BroadcastStatus(PositionStatus.Initializing);
var location = _locationManager.GetLastKnownLocation(_locationProvider);
BroadcastStatus(PositionStatus.Ready);
return Task.FromResult(location.ToGeoPosition());
BroadcastStatus(PositionStatus.Initializing);
var location = _locationManager.GetLastKnownLocation(_locationProvider);
BroadcastStatus(PositionStatus.Ready);
return Task.FromResult(location.ToGeoPosition());
}
else
{
return CoreDispatcher.Main.RunWithResultAsync(
priority: CoreDispatcherPriority.Normal,
task: () => GetGeopositionAsync()
);
}
}

public Task<Geoposition> GetGeopositionAsync(TimeSpan maximumAge, TimeSpan timeout)
Expand Down
122 changes: 72 additions & 50 deletions src/Uno.UWP/Devices/Geolocation/Geolocator.iOSmacOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using CoreLocation;
using Uno.Extensions;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Foundation.Metadata;
using Windows.UI.Core;

namespace Windows.Devices.Geolocation
{
public sealed partial class Geolocator
Expand Down Expand Up @@ -38,24 +41,34 @@ partial void StartPositionChanged()
}

#if __IOS__
public async Task<Geoposition> GetGeopositionAsync() //will be removed with #2240
public Task<Geoposition> GetGeopositionAsync() => GetGeopositionInternalAsync(); //will be removed with #2240
#else
public IAsyncOperation<Geoposition> GetGeopositionAsync()
public IAsyncOperation<Geoposition> GetGeopositionAsync() => GetGeopositionInternalAsync().AsAsyncOperation();
#endif

public Task<Geoposition> GetGeopositionInternalAsync()

{
BroadcastStatus(PositionStatus.Initializing);
var location = _locationManager.Location;
if (location == null)
if (CoreDispatcher.Main.HasThreadAccess)
{
throw new InvalidOperationException("Could not obtain the location. Please make sure that NSLocationWhenInUseUsageDescription and NSLocationUsageDescription are set in info.plist.");
}
BroadcastStatus(PositionStatus.Initializing);
var location = _locationManager.Location;
if (location == null)
{
throw new InvalidOperationException("Could not obtain the location. Please make sure that NSLocationWhenInUseUsageDescription and NSLocationUsageDescription are set in info.plist.");
}

BroadcastStatus(PositionStatus.Ready);
#if __IOS__
return ToGeoposition(location);
#else
return Task.FromResult(ToGeoposition(location)).AsAsyncOperation();
#endif
BroadcastStatus(PositionStatus.Ready);

return Task.FromResult(ToGeoposition(location));
}
else
{
return CoreDispatcher.Main.RunWithResultAsync<Geoposition>(
priority: CoreDispatcherPriority.Normal,
task: () => GetGeopositionInternalAsync()
);
}
}

private static Geoposition ToGeoposition(CLLocation location)
Expand Down Expand Up @@ -91,62 +104,71 @@ public IAsyncOperation<Geoposition> GetGeopositionAsync(TimeSpan maximumAge, Tim
private static List<CLLocationManager> _requestManagers = new List<CLLocationManager>();

#if __IOS__
public static async Task<GeolocationAccessStatus> RequestAccessAsync() //will be removed with #2240
public static Task<GeolocationAccessStatus> RequestAccessAsync() => RequestAccessInternalAsync(); //will be removed with #2240
#else
public static IAsyncOperation<GeolocationAccessStatus> RequestAccessAsync() =>
RequestAccessInternalAsync().AsAsyncOperation();

private static async Task<GeolocationAccessStatus> RequestAccessInternalAsync()
public static IAsyncOperation<GeolocationAccessStatus> RequestAccessAsync() => RequestAccessInternalAsync().AsAsyncOperation();
#endif
{
var mgr = new CLLocationManager();
private static async Task<GeolocationAccessStatus> RequestAccessInternalAsync()

lock (_requestManagers)
{
if (CoreDispatcher.Main.HasThreadAccess)
{
_requestManagers.Add(mgr);
}
var mgr = new CLLocationManager();

try
{
GeolocationAccessStatus accessStatus;
var cts = new TaskCompletionSource<CLAuthorizationStatus>();
lock (_requestManagers)
{
_requestManagers.Add(mgr);
}

mgr.AuthorizationChanged += (s, e) =>
try
{
GeolocationAccessStatus accessStatus;
var cts = new TaskCompletionSource<CLAuthorizationStatus>();

if (e.Status != CLAuthorizationStatus.NotDetermined)
mgr.AuthorizationChanged += (s, e) =>
{
cts.TrySetResult(e.Status);
}
};
if (e.Status != CLAuthorizationStatus.NotDetermined)
{
cts.TrySetResult(e.Status);
}
};

#if __IOS__ //required only for iOS
mgr.RequestWhenInUseAuthorization();
mgr.RequestWhenInUseAuthorization();
#endif

if (CLLocationManager.Status != CLAuthorizationStatus.NotDetermined)
{
accessStatus = TranslateStatus(CLLocationManager.Status);
}
if (CLLocationManager.Status != CLAuthorizationStatus.NotDetermined)
{
accessStatus = TranslateStatus(CLLocationManager.Status);
}

var cLAuthorizationStatus = await cts.Task;
var cLAuthorizationStatus = await cts.Task;

accessStatus = TranslateStatus(cLAuthorizationStatus);

//if geolocation is not well accessible, default geoposition should be recommended
if (accessStatus != GeolocationAccessStatus.Allowed)
accessStatus = TranslateStatus(cLAuthorizationStatus);

//if geolocation is not well accessible, default geoposition should be recommended
if (accessStatus != GeolocationAccessStatus.Allowed)
{
IsDefaultGeopositionRecommended = true;
}

return accessStatus;
}
finally
{
IsDefaultGeopositionRecommended = true;
lock (_requestManagers)
{
_requestManagers.Remove(mgr);
}
}

return accessStatus;
}
finally
else
{
lock (_requestManagers)
{
_requestManagers.Remove(mgr);
}
return await CoreDispatcher.Main.RunWithResultAsync<GeolocationAccessStatus>(
priority: CoreDispatcherPriority.Normal,
task: () => RequestAccessInternalAsync()
);
}
}

Expand Down

0 comments on commit e67e139

Please sign in to comment.