diff --git a/DeviceTests/DeviceTests.Shared/Geolocation_Tests.cs b/DeviceTests/DeviceTests.Shared/Geolocation_Tests.cs index 8d5a08f65..62c8ab184 100644 --- a/DeviceTests/DeviceTests.Shared/Geolocation_Tests.cs +++ b/DeviceTests/DeviceTests.Shared/Geolocation_Tests.cs @@ -69,11 +69,13 @@ await MainThread.InvokeOnMainThreadAsync(async () => }); var request = new GeolocationRequest(GeolocationAccuracy.Best); + request.RequestFullAccuracy = true; var location = await Geolocation.GetLocationAsync(request); Assert.NotNull(location); Assert.True(location.Accuracy > 0); + Assert.False(location.ReducedAccuracy); Assert.NotEqual(0.0, location.Latitude); Assert.NotEqual(0.0, location.Longitude); diff --git a/Xamarin.Essentials/Geolocation/Geolocation.ios.macos.cs b/Xamarin.Essentials/Geolocation/Geolocation.ios.macos.cs index d9bb0d311..ca9006361 100644 --- a/Xamarin.Essentials/Geolocation/Geolocation.ios.macos.cs +++ b/Xamarin.Essentials/Geolocation/Geolocation.ios.macos.cs @@ -19,7 +19,14 @@ static async Task PlatformLastKnownLocationAsync() var manager = new CLLocationManager(); var location = manager.Location; - return location?.ToLocation(); + var reducedAccuracy = false; +#if __IOS__ + if (Platform.HasOSVersion(14, 0)) + { + reducedAccuracy = manager.AccuracyAuthorization == CLAccuracyAuthorization.ReducedAccuracy; + } +#endif + return location?.ToLocation(reducedAccuracy); } static async Task PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken) @@ -51,9 +58,22 @@ static async Task PlatformLocationAsync(GeolocationRequest request, Ca manager.StartUpdatingLocation(); + var reducedAccuracy = false; +#if __IOS__ + if (Platform.HasOSVersion(14, 0)) + { + if (request.RequestFullAccuracy && manager.AccuracyAuthorization == CLAccuracyAuthorization.ReducedAccuracy) + { + await manager.RequestTemporaryFullAccuracyAuthorizationAsync("XamarinEssentialsFullAccuracyUsageDescription"); + } + + reducedAccuracy = manager.AccuracyAuthorization == CLAccuracyAuthorization.ReducedAccuracy; + } +#endif + var clLocation = await tcs.Task; - return clLocation?.ToLocation(); + return clLocation?.ToLocation(reducedAccuracy); void HandleLocation(CLLocation location) { diff --git a/Xamarin.Essentials/Geolocation/GeolocationRequest.shared.cs b/Xamarin.Essentials/Geolocation/GeolocationRequest.shared.cs index ce9c24725..79ff87e56 100644 --- a/Xamarin.Essentials/Geolocation/GeolocationRequest.shared.cs +++ b/Xamarin.Essentials/Geolocation/GeolocationRequest.shared.cs @@ -57,6 +57,8 @@ public GeolocationRequest(GeolocationAccuracy accuracy, TimeSpan timeout) public GeolocationAccuracy DesiredAccuracy { get; set; } + public bool RequestFullAccuracy { get; set; } + public override string ToString() => $"{nameof(DesiredAccuracy)}: {DesiredAccuracy}, {nameof(Timeout)}: {Timeout}"; } diff --git a/Xamarin.Essentials/Types/Location.shared.cs b/Xamarin.Essentials/Types/Location.shared.cs index e08b1b3be..2748e0494 100644 --- a/Xamarin.Essentials/Types/Location.shared.cs +++ b/Xamarin.Essentials/Types/Location.shared.cs @@ -58,6 +58,7 @@ public Location(Location point) Altitude = point.Altitude; Accuracy = point.Accuracy; VerticalAccuracy = point.VerticalAccuracy; + ReducedAccuracy = point.ReducedAccuracy; Speed = point.Speed; Course = point.Course; IsFromMockProvider = point.IsFromMockProvider; @@ -75,6 +76,8 @@ public Location(Location point) public double? VerticalAccuracy { get; set; } + public bool ReducedAccuracy { get; set; } + public double? Speed { get; set; } public double? Course { get; set; } diff --git a/Xamarin.Essentials/Types/LocationExtensions.android.cs b/Xamarin.Essentials/Types/LocationExtensions.android.cs index 8985899e3..e85554099 100644 --- a/Xamarin.Essentials/Types/LocationExtensions.android.cs +++ b/Xamarin.Essentials/Types/LocationExtensions.android.cs @@ -34,6 +34,7 @@ internal static Location ToLocation(this AndroidLocation location) => #else default(float?), #endif + ReducedAccuracy = false, Course = location.HasBearing ? location.Bearing : default(double?), Speed = location.HasSpeed ? location.Speed : default(double?), #pragma warning disable CS0618 // Type or member is obsolete diff --git a/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs b/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs index cfdf74fa3..79a7e053a 100644 --- a/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs +++ b/Xamarin.Essentials/Types/LocationExtensions.ios.tvos.watchos.macos.cs @@ -18,13 +18,14 @@ internal static Location ToLocation(this CLPlacemark placemark) => Longitude = placemark.Location.Coordinate.Longitude, Altitude = placemark.Location.Altitude, AltitudeReferenceSystem = AltitudeReferenceSystem.Geoid, - Timestamp = DateTimeOffset.UtcNow + Timestamp = DateTimeOffset.UtcNow, + ReducedAccuracy = false, }; internal static IEnumerable ToLocations(this IEnumerable placemarks) => placemarks?.Select(a => a.ToLocation()); - internal static Location ToLocation(this CLLocation location) => + internal static Location ToLocation(this CLLocation location, bool reducedAccuracy) => new Location { Latitude = location.Coordinate.Latitude, @@ -32,6 +33,7 @@ internal static Location ToLocation(this CLLocation location) => Altitude = location.VerticalAccuracy < 0 ? default(double?) : location.Altitude, Accuracy = location.HorizontalAccuracy, VerticalAccuracy = location.VerticalAccuracy, + ReducedAccuracy = reducedAccuracy, Timestamp = location.Timestamp.ToDateTime(), #if __IOS__ || __WATCHOS__ Course = location.Course < 0 ? default(double?) : location.Course, diff --git a/Xamarin.Essentials/Types/LocationExtensions.uwp.cs b/Xamarin.Essentials/Types/LocationExtensions.uwp.cs index df54d6065..c8c78fdac 100644 --- a/Xamarin.Essentials/Types/LocationExtensions.uwp.cs +++ b/Xamarin.Essentials/Types/LocationExtensions.uwp.cs @@ -34,6 +34,7 @@ internal static Location ToLocation(this Geoposition location) => Altitude = location.Coordinate.Point.Position.Altitude, Accuracy = location.Coordinate.Accuracy, VerticalAccuracy = location.Coordinate.AltitudeAccuracy, + ReducedAccuracy = false, Speed = (!location.Coordinate.Speed.HasValue || double.IsNaN(location.Coordinate.Speed.Value)) ? default : location.Coordinate.Speed, Course = (!location.Coordinate.Heading.HasValue || double.IsNaN(location.Coordinate.Heading.Value)) ? default : location.Coordinate.Heading, IsFromMockProvider = false, @@ -49,6 +50,7 @@ internal static Location ToLocation(this Geocoordinate coordinate) => Altitude = coordinate.Point.Position.Altitude, Accuracy = coordinate.Accuracy, VerticalAccuracy = coordinate.AltitudeAccuracy, + ReducedAccuracy = false, Speed = (!coordinate.Speed.HasValue || double.IsNaN(coordinate.Speed.Value)) ? default : coordinate.Speed, Course = (!coordinate.Heading.HasValue || double.IsNaN(coordinate.Heading.Value)) ? default : coordinate.Heading, AltitudeReferenceSystem = coordinate.Point.AltitudeReferenceSystem.ToEssentials()