* First pass at Android Geolocation impl

* No need for nullables

* Added the geolocation sample

* Added the UWP geolocation implementation

* Getting some of the iOS in

* Use a global location manager so that the permissions popup lives for mor than a few seconds

* Check before asking on iOS

* Finished the iOS implementation and tweak a few things

* Remove the unsused using

* Don't use locking and static fields, use the TCS state

* Keep the manager alive for the duration of the method

* Use platform specific accuracy

* Moving files after merge

* Changing namespaces

* Removed the `ConfigureAwait(false)` instances

* Use extension methods

* tabs not spaces

* Added sopme docs

* More docs

* Added some tests (that can't run yet)

* Enabling the tests for CI after adding attributes

* Added the iOS permissions text to the tests

* iOS has opinions when it comes to locations

* Starting the location manager on the main thread, but return on the original thread

* We just need to call the constructor in the main thread

* Added all the permissions to the manifest for the samples and the tests

* Android has looper issues

* Location is now a declared permission

* Changes based on feedback.

* Cleanup iOS Permissions. Must have static location manager around.

* The stylish copper got us again
This commit is contained in:
Jonathan Dick 2018-04-10 15:25:48 -04:00 коммит произвёл James Montemagno
Родитель f2420c8099
Коммит f185ef419f
36 изменённых файлов: 1140 добавлений и 85 удалений

Просмотреть файл

@ -1,7 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.1.0" package="com.xamarin.essentials.devicetests" android:installLocation="auto">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<application android:label="@string/app_name" android:icon="@drawable/icon" android:theme="@style/MainTheme"></application>
</manifest>

Просмотреть файл

@ -28,7 +28,3 @@ using Android.App;
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
// Add some common permissions, these can be removed if not needed
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]

Просмотреть файл

@ -20,6 +20,7 @@
<Compile Include="$(MSBuildThisFileDirectory)DeviceInfo_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Flashlight_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geocoding_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geolocation_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Permissions_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PhoneDialer_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ScreenLock_Tests.cs" />

Просмотреть файл

@ -0,0 +1,74 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xunit;
namespace DeviceTests
{
// TEST NOTES:
// - a human needs to accept permissions
public class Geolocation_Tests
{
[Fact]
[Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
public async Task Get_LastKnownLocation_Is_Something()
{
var location = await Geolocation.GetLastKnownLocationAsync();
Assert.NotNull(location);
Assert.True(location.Accuracy > 0);
Assert.NotEqual(0.0, location.Latitude);
Assert.NotEqual(0.0, location.Longitude);
Assert.NotEqual(DateTimeOffset.MaxValue, location.TimestampUtc);
Assert.NotEqual(DateTimeOffset.MinValue, location.TimestampUtc);
// before right now, but after yesterday
Assert.True(location.TimestampUtc < DateTimeOffset.UtcNow);
Assert.True(location.TimestampUtc > DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(1)));
}
[Fact]
[Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
public async Task Get_Location_Is_Something()
{
var location = await Geolocation.GetLocationAsync();
Assert.NotNull(location);
Assert.True(location.Accuracy > 0);
Assert.NotEqual(0.0, location.Latitude);
Assert.NotEqual(0.0, location.Longitude);
Assert.NotEqual(DateTimeOffset.MaxValue, location.TimestampUtc);
Assert.NotEqual(DateTimeOffset.MinValue, location.TimestampUtc);
// before right now, but after yesterday
Assert.True(location.TimestampUtc < DateTimeOffset.UtcNow);
Assert.True(location.TimestampUtc > DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(1)));
}
[Fact]
[Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
public async Task Get_Location_With_Request_Is_Something()
{
var request = new GeolocationRequest(GeolocationAccuracy.Best);
var location = await Geolocation.GetLocationAsync(request);
Assert.NotNull(location);
Assert.True(location.Accuracy > 0);
Assert.NotEqual(0.0, location.Latitude);
Assert.NotEqual(0.0, location.Longitude);
Assert.NotEqual(DateTimeOffset.MaxValue, location.TimestampUtc);
Assert.NotEqual(DateTimeOffset.MinValue, location.TimestampUtc);
// before right now, but after yesterday
Assert.True(location.TimestampUtc < DateTimeOffset.UtcNow);
Assert.True(location.TimestampUtc > DateTimeOffset.UtcNow.Subtract(TimeSpan.FromDays(1)));
}
}
}

Просмотреть файл

@ -5,10 +5,6 @@ using System.Threading.Tasks;
using Xamarin.Essentials;
using Xunit;
#if __ANDROID__
[assembly: Android.App.UsesPermission(Android.Manifest.Permission.BatteryStats)]
#endif
namespace DeviceTests
{
public class Permissions_Tests
@ -16,23 +12,12 @@ namespace DeviceTests
[Theory]
[InlineData(PermissionType.Battery)]
[InlineData(PermissionType.NetworkState)]
[InlineData(PermissionType.LocationWhenInUse)]
internal void Ensure_Declared(PermissionType permission)
{
Permissions.EnsureDeclared(permission);
}
[Theory]
[InlineData(PermissionType.LocationWhenInUse)]
internal void Ensure_Declared_Throws(PermissionType permission)
{
if (DeviceInfo.Platform == DeviceInfo.Platforms.UWP)
{
return;
}
Assert.Throws<PermissionException>(() => Permissions.EnsureDeclared(permission));
}
[Theory]
[InlineData(PermissionType.Battery, PermissionStatus.Granted)]
[InlineData(PermissionType.NetworkState, PermissionStatus.Granted)]
@ -43,18 +28,6 @@ namespace DeviceTests
Assert.Equal(expectedStatus, status);
}
[Theory]
[InlineData(PermissionType.LocationWhenInUse)]
internal Task Check_Status_Throws(PermissionType permission)
{
if (DeviceInfo.Platform == DeviceInfo.Platforms.UWP)
{
return Task.CompletedTask;
}
return Assert.ThrowsAsync<PermissionException>(async () => await Permissions.CheckStatusAsync(permission));
}
[Theory]
[InlineData(PermissionType.Battery, PermissionStatus.Granted)]
[InlineData(PermissionType.NetworkState, PermissionStatus.Granted)]

Просмотреть файл

@ -53,5 +53,7 @@
<string>DeviceTests</string>
<key>CFBundleShortVersionString</key>
<string>1.0.1.0</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Access to your location is required for cool things to happen!</string>
</dict>
</plist>

Просмотреть файл

@ -1,10 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.xamarin.essentials" android:installLocation="auto">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="26" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<application android:label="@string/app_name" android:icon="@drawable/icon" android:theme="@style/MainTheme"></application>
</manifest>

Просмотреть файл

@ -27,7 +27,3 @@ using Android.App;
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
// Add some common permissions, these can be removed if not needed
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]

Просмотреть файл

@ -24,5 +24,6 @@
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<DeviceCapability Name="location" />
</Capabilities>
</Package>

Просмотреть файл

@ -53,5 +53,7 @@
<string>Xamarin.Essentials</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Access to your location is required for cool things to happen!</string>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8" ?>
<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Samples.View"
xmlns:viewmodels="clr-namespace:Samples.ViewModel"
x:Class="Samples.View.GeolocationPage"
Title="Geolocation">
<ContentPage.BindingContext>
<viewmodels:GeolocationViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Label Text="Quickly get the current location." FontAttributes="Bold" Margin="12" />
<ScrollView>
<StackLayout Padding="12,0,12,12" Spacing="6">
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" />
<Label Text="Last Known Location:" FontAttributes="Bold" Margin="0,6,0,0" />
<Label Text="{Binding LastLocation}" />
<Button Text="Refresh" Command="{Binding GetLastLocationCommand}" IsEnabled="{Binding IsNotBusy}" />
<Label Text="Current Location:" FontAttributes="Bold" Margin="0,6,0,0" />
<Label Text="{Binding CurrentLocation}" />
<Label Text="Accuracy:" />
<Picker ItemsSource="{Binding Accuracies}"
SelectedIndex="{Binding Accuracy, Mode=TwoWay}"
IsEnabled="{Binding IsNotBusy}"
HorizontalOptions="FillAndExpand" />
<Button Text="Refresh" Command="{Binding GetCurrentLocationCommand}" IsEnabled="{Binding IsNotBusy}" />
</StackLayout>
</ScrollView>
</StackLayout>
</views:BasePage>

Просмотреть файл

@ -0,0 +1,10 @@
namespace Samples.View
{
public partial class GeolocationPage : BasePage
{
public GeolocationPage()
{
InitializeComponent();
}
}
}

Просмотреть файл

@ -0,0 +1,97 @@
using System;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Samples.ViewModel
{
public class GeolocationViewModel : BaseViewModel
{
string lastLocation;
string currentLocation;
int accuracy = (int)GeolocationAccuracy.Medium;
public GeolocationViewModel()
{
GetLastLocationCommand = new Command(OnGetLastLocation);
GetCurrentLocationCommand = new Command(OnGetCurrentLocation);
}
public ICommand GetLastLocationCommand { get; }
public ICommand GetCurrentLocationCommand { get; }
public string LastLocation
{
get => lastLocation;
set => SetProperty(ref lastLocation, value);
}
public string CurrentLocation
{
get => currentLocation;
set => SetProperty(ref currentLocation, value);
}
public string[] Accuracies
=> Enum.GetNames(typeof(GeolocationAccuracy));
public int Accuracy
{
get => accuracy;
set => SetProperty(ref accuracy, value);
}
async void OnGetLastLocation()
{
if (IsBusy)
return;
IsBusy = true;
try
{
var location = await Geolocation.GetLastKnownLocationAsync();
LastLocation = FormatLocation(location);
}
catch (Exception)
{
LastLocation = FormatLocation(null);
}
IsBusy = false;
}
async void OnGetCurrentLocation()
{
if (IsBusy)
return;
IsBusy = true;
try
{
var request = new GeolocationRequest((GeolocationAccuracy)Accuracy);
var location = await Geolocation.GetLocationAsync(request);
CurrentLocation = FormatLocation(location);
}
catch (Exception)
{
CurrentLocation = FormatLocation(null);
}
IsBusy = false;
}
private string FormatLocation(Location location)
{
if (location == null)
{
return "Unable to detect location.";
}
return
$"Latitude: {location.Latitude}\n" +
$"Longitude: {location.Longitude}\n" +
$"Accuracy: {location.Accuracy}\n" +
$"Date (UTC): {location.TimestampUtc:d}\n" +
$"Time (UTC): {location.TimestampUtc:T}";
}
}
}

Просмотреть файл

@ -27,6 +27,7 @@ namespace Samples.ViewModel
new SampleItem("File System", typeof(FileSystemPage), "Easily save files to app data."),
new SampleItem("Flashlight", typeof(FlashlightPage), "A simple way to turn the flashlight on/off."),
new SampleItem("Geocoding", typeof(GeocodingPage), "Easily geocode and reverse geocoding."),
new SampleItem("Geolocation", typeof(GeolocationPage), "Quickly get the current location."),
new SampleItem("Gyroscope", typeof(GyroscopePage), "Retrieve rotation around the device's three primary axes."),
new SampleItem("Magnetometer", typeof(MagnetometerPage), "Detect device's orientation relative to Earth's magnetic field."),
new SampleItem("Phone Dialer", typeof(PhoneDialerPage), "Easily open phone dialer."),

Просмотреть файл

@ -0,0 +1,194 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Android.Locations;
using Android.OS;
using Android.Runtime;
using AndroidLocation = Android.Locations.Location;
namespace Xamarin.Essentials
{
public static partial class Geolocation
{
const long twoMinutes = 120000;
static async Task<Location> PlatformLastKnownLocationAsync()
{
await Permissions.RequireAsync(PermissionType.LocationWhenInUse);
var lm = Platform.LocationManager;
AndroidLocation bestLocation = null;
foreach (var provider in lm.GetProviders(true))
{
var location = lm.GetLastKnownLocation(provider);
if (bestLocation == null || IsBetterLocation(location, bestLocation))
bestLocation = location;
}
if (bestLocation == null)
return null;
return bestLocation.ToLocation();
}
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
await Permissions.RequireAsync(PermissionType.LocationWhenInUse);
var locationManager = Platform.LocationManager;
// get the best possible provider for the requested accuracy
var provider = 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(provider))
return await GetLastKnownLocationAsync();
var tcs = new TaskCompletionSource<AndroidLocation>();
var listener = new SingleLocationListener();
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;
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(null);
}
void RemoveUpdates()
{
locationManager.RemoveUpdates(listener);
}
}
class SingleLocationListener : Java.Lang.Object, ILocationListener
{
bool wasRaised = false;
public Action<AndroidLocation> LocationHandler { get; set; }
public void OnLocationChanged(AndroidLocation location)
{
if (wasRaised)
return;
wasRaised = true;
LocationHandler?.Invoke(location);
}
public void OnProviderDisabled(string provider)
{
}
public void OnProviderEnabled(string provider)
{
}
public void OnStatusChanged(string provider, [GeneratedEnum] Availability status, Bundle extras)
{
}
}
static string GetBestProvider(LocationManager locationManager, GeolocationAccuracy accuracy)
{
var criteria = new Criteria();
criteria.BearingRequired = false;
criteria.AltitudeRequired = false;
criteria.SpeedRequired = false;
switch (accuracy)
{
case GeolocationAccuracy.Lowest:
criteria.Accuracy = Accuracy.NoRequirement;
criteria.HorizontalAccuracy = Accuracy.NoRequirement;
criteria.PowerRequirement = Power.NoRequirement;
break;
case GeolocationAccuracy.Low:
criteria.Accuracy = Accuracy.Low;
criteria.HorizontalAccuracy = Accuracy.Low;
criteria.PowerRequirement = Power.Low;
break;
case GeolocationAccuracy.Medium:
criteria.Accuracy = Accuracy.Medium;
criteria.HorizontalAccuracy = Accuracy.Medium;
criteria.PowerRequirement = Power.Medium;
break;
case GeolocationAccuracy.High:
criteria.Accuracy = Accuracy.High;
criteria.HorizontalAccuracy = Accuracy.High;
criteria.PowerRequirement = Power.High;
break;
case GeolocationAccuracy.Best:
criteria.Accuracy = Accuracy.Fine;
criteria.HorizontalAccuracy = Accuracy.Fine;
criteria.PowerRequirement = Power.High;
break;
}
return locationManager.GetBestProvider(criteria, true) ?? locationManager.GetProviders(true).FirstOrDefault();
}
internal static bool IsBetterLocation(AndroidLocation location, AndroidLocation bestLocation)
{
if (bestLocation == null)
return true;
var timeDelta = location.Time - bestLocation.Time;
var isSignificantlyNewer = timeDelta > twoMinutes;
var isSignificantlyOlder = timeDelta < -twoMinutes;
var isNewer = timeDelta > 0;
if (isSignificantlyNewer)
return true;
if (isSignificantlyOlder)
return false;
var accuracyDelta = (int)(location.Accuracy - bestLocation.Accuracy);
var isLessAccurate = accuracyDelta > 0;
var isMoreAccurate = accuracyDelta < 0;
var isSignificantlyLessAccurage = accuracyDelta > 200;
var isFromSameProvider = location?.Provider?.Equals(bestLocation?.Provider, StringComparison.OrdinalIgnoreCase) ?? false;
if (isMoreAccurate)
return true;
if (isNewer && !isLessAccurate)
return true;
if (isNewer && !isSignificantlyLessAccurage && isFromSameProvider)
return true;
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,92 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CoreLocation;
using Foundation;
namespace Xamarin.Essentials
{
public static partial class Geolocation
{
internal static bool IsSupported
=> CLLocationManager.LocationServicesEnabled;
static async Task<Location> PlatformLastKnownLocationAsync()
{
await Permissions.RequireAsync(PermissionType.LocationWhenInUse);
var manager = new CLLocationManager();
var location = manager.Location;
return location.ToLocation();
}
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
await Permissions.RequireAsync(PermissionType.LocationWhenInUse);
// the location manager requires an active run loop
// so just use the main loop
CLLocationManager manager = null;
NSRunLoop.Main.InvokeOnMainThread(() => manager = 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;
// we're only listening for a single update
manager.PausesLocationUpdatesAutomatically = false;
manager.StartUpdatingLocation();
var clLocation = await tcs.Task;
if (clLocation == null)
return null;
return clLocation.ToLocation();
void HandleLocation(CLLocation location)
{
manager.StopUpdatingLocation();
tcs.TrySetResult(location);
}
void Cancel()
{
manager.StopUpdatingLocation();
tcs.TrySetResult(null);
}
}
class SingleLocationListener : CLLocationManagerDelegate
{
bool wasRaised = false;
public Action<CLLocation> LocationHandler { get; set; }
public override void LocationsUpdated(CLLocationManager manager, CLLocation[] locations)
{
if (wasRaised)
return;
wasRaised = true;
var location = locations.LastOrDefault();
if (location == null)
return;
LocationHandler?.Invoke(location);
}
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Xamarin.Essentials
{
public static partial class Geolocation
{
static Task<Location> PlatformLastKnownLocationAsync() =>
throw new NotImplementedInReferenceAssemblyException();
static Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken) =>
throw new NotImplementedInReferenceAssemblyException();
}
}

Просмотреть файл

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Xamarin.Essentials
{
public static partial class Geolocation
{
public static Task<Location> GetLastKnownLocationAsync() =>
PlatformLastKnownLocationAsync();
public static Task<Location> GetLocationAsync() =>
PlatformLocationAsync(new GeolocationRequest(), default);
public static Task<Location> GetLocationAsync(GeolocationRequest request) =>
PlatformLocationAsync(request ?? new GeolocationRequest(), default);
public static Task<Location> GetLocationAsync(GeolocationRequest request, CancellationToken cancelToken) =>
PlatformLocationAsync(request ?? new GeolocationRequest(), cancelToken);
}
}

Просмотреть файл

@ -0,0 +1,54 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Windows.Devices.Geolocation;
namespace Xamarin.Essentials
{
public static partial class Geolocation
{
static async Task<Location> PlatformLastKnownLocationAsync()
{
// no need for permissions as AllowFallbackToConsentlessPositions
// will allow the device to return a location regardless
var geolocator = new Geolocator
{
DesiredAccuracy = PositionAccuracy.Default,
};
geolocator.AllowFallbackToConsentlessPositions();
var location = await geolocator.GetGeopositionAsync().AsTask();
if (location?.Coordinate == null)
return null;
return location.ToLocation();
}
static async Task<Location> PlatformLocationAsync(GeolocationRequest request, CancellationToken cancellationToken)
{
await Permissions.RequireAsync(PermissionType.LocationWhenInUse);
var geolocator = new Geolocator
{
DesiredAccuracyInMeters = request.PlatformDesiredAccuracy
};
cancellationToken = Utils.TimeoutToken(cancellationToken, request.Timeout);
var location = await geolocator.GetGeopositionAsync().AsTask(cancellationToken);
if (location?.Coordinate == null)
return null;
return new Location
{
Latitude = location.Coordinate.Point.Position.Latitude,
Longitude = location.Coordinate.Point.Position.Longitude,
TimestampUtc = location.Coordinate.Timestamp,
Accuracy = location.Coordinate.Accuracy
};
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using CoreLocation;
namespace Xamarin.Essentials
{
public partial class GeolocationRequest
{
internal double PlatformDesiredAccuracy
{
get
{
switch (DesiredAccuracy)
{
case GeolocationAccuracy.Lowest:
return CLLocation.AccuracyThreeKilometers;
case GeolocationAccuracy.Low:
return CLLocation.AccuracyKilometer;
case GeolocationAccuracy.Medium:
return CLLocation.AccuracyHundredMeters;
case GeolocationAccuracy.High:
return CLLocation.AccuracyNearestTenMeters;
case GeolocationAccuracy.Best:
return CLLocation.AccurracyBestForNavigation;
default:
return CLLocation.AccuracyHundredMeters;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
using System;
namespace Xamarin.Essentials
{
public enum GeolocationAccuracy
{
// iOS: ThreeKilometers (3000m)
// Android: ACCURACY_LOW, POWER_LOW (500m)
// UWP: 3000 (1000-5000m)
Lowest,
// iOS: Kilometer (1000m)
// Android: ACCURACY_LOW, POWER_MED (500m)
// UWP: 1000 (300-3000m)
Low,
// iOS: HundredMeters (100m)
// Android: ACCURACY_MED, POWER_MED (100-500m)
// UWP: 100 (30-500m)
Medium,
// iOS: NearestTenMeters (10m)
// Android: ACCURACY_HI, POWER_MED (0-100m)
// UWP: High (<=10m)
High,
// iOS: Best (0m)
// Android: ACCURACY_HI, POWER_HI (0-100m)
// UWP: High (<=10m)
Best
}
public partial class GeolocationRequest
{
public GeolocationRequest()
{
Timeout = TimeSpan.Zero;
DesiredAccuracy = GeolocationAccuracy.Medium;
}
public GeolocationRequest(GeolocationAccuracy accuracy)
{
Timeout = TimeSpan.Zero;
DesiredAccuracy = accuracy;
}
public GeolocationRequest(GeolocationAccuracy accuracy, TimeSpan timeout)
{
Timeout = timeout;
DesiredAccuracy = accuracy;
}
public TimeSpan Timeout { get; set; }
public GeolocationAccuracy DesiredAccuracy { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Xamarin.Essentials
{
public partial class GeolocationRequest
{
internal uint PlatformDesiredAccuracy
{
get
{
switch (DesiredAccuracy)
{
case GeolocationAccuracy.Lowest:
return 3000;
case GeolocationAccuracy.Low:
return 1000;
case GeolocationAccuracy.Medium:
return 100;
case GeolocationAccuracy.High:
return 10; // Equivalent to PositionAccuracy.High
case GeolocationAccuracy.Best:
return 1;
default:
return 500; // Equivalent to PositionAccuracy.Default
}
}
}
}
}

Просмотреть файл

@ -1,7 +1,6 @@
using System.Threading.Tasks;
using CoreLocation;
using Foundation;
using UIKit;
namespace Xamarin.Essentials
{
@ -9,16 +8,12 @@ namespace Xamarin.Essentials
{
static void PlatformEnsureDeclared(PermissionType permission)
{
// Info.plist declarations were only required in >= iOS 8.0
if (!Platform.HasOSVersion(8, 0))
return;
var info = NSBundle.MainBundle.InfoDictionary;
if (permission == PermissionType.LocationWhenInUse)
{
if (!info.ContainsKey(new NSString("NSLocationWhenInUseUsageDescription")))
throw new PermissionException("On iOS 8.0 and higher you must set either `NSLocationWhenInUseUsageDescription` or `NSLocationAlwaysUsageDescription` in your Info.plist file to enable Authorization Requests for Location updates!");
throw new PermissionException("On iOS 8.0 and higher you must set either `NSLocationWhenInUseUsageDescription` in your Info.plist file to enable Authorization Requests for Location updates!");
}
}
@ -35,17 +30,21 @@ namespace Xamarin.Essentials
return Task.FromResult(PermissionStatus.Granted);
}
static Task<PermissionStatus> PlatformRequestAsync(PermissionType permission)
static async Task<PermissionStatus> PlatformRequestAsync(PermissionType permission)
{
// Check status before requesting first
if (await PlatformCheckStatusAsync(permission) == PermissionStatus.Granted)
return PermissionStatus.Granted;
PlatformEnsureDeclared(permission);
switch (permission)
{
case PermissionType.LocationWhenInUse:
return RequestLocationAsync();
return await RequestLocationAsync();
}
return Task.FromResult(PermissionStatus.Granted);
return PermissionStatus.Granted;
}
static PermissionStatus GetLocationStatus()
@ -55,25 +54,10 @@ namespace Xamarin.Essentials
var status = CLLocationManager.Status;
if (Platform.HasOSVersion(8, 0))
{
switch (status)
{
case CLAuthorizationStatus.AuthorizedAlways:
case CLAuthorizationStatus.AuthorizedWhenInUse:
return PermissionStatus.Granted;
case CLAuthorizationStatus.Denied:
return PermissionStatus.Denied;
case CLAuthorizationStatus.Restricted:
return PermissionStatus.Restricted;
default:
return PermissionStatus.Unknown;
}
}
switch (status)
{
case CLAuthorizationStatus.Authorized:
case CLAuthorizationStatus.AuthorizedAlways:
case CLAuthorizationStatus.AuthorizedWhenInUse:
return PermissionStatus.Granted;
case CLAuthorizationStatus.Denied:
return PermissionStatus.Denied;
@ -84,30 +68,29 @@ namespace Xamarin.Essentials
}
}
static CLLocationManager locationManager;
static Task<PermissionStatus> RequestLocationAsync()
{
if (!UIDevice.CurrentDevice.CheckSystemVersion(8, 0))
return Task.FromResult(PermissionStatus.Unknown);
locationManager = new CLLocationManager();
var locationManager = new CLLocationManager();
var tcs = new TaskCompletionSource<PermissionStatus>(locationManager);
var tcs = new TaskCompletionSource<PermissionStatus>();
locationManager.AuthorizationChanged += LocationAuthCallback;
locationManager.RequestWhenInUseAuthorization();
void AuthCallback(object sender, CLAuthorizationChangedEventArgs e)
return tcs.Task;
void LocationAuthCallback(object sender, CLAuthorizationChangedEventArgs e)
{
if (e.Status == CLAuthorizationStatus.NotDetermined)
return;
locationManager.AuthorizationChanged -= AuthCallback;
locationManager.AuthorizationChanged -= LocationAuthCallback;
tcs.TrySetResult(GetLocationStatus());
locationManager.Dispose();
locationManager = null;
}
locationManager.AuthorizationChanged += AuthCallback;
locationManager.RequestWhenInUseAuthorization();
return tcs.Task;
}
}
}

Просмотреть файл

@ -5,6 +5,7 @@ using Android.Content;
using Android.Content.PM;
using Android.Hardware;
using Android.Hardware.Camera2;
using Android.Locations;
using Android.Net;
using Android.Net.Wifi;
using Android.OS;
@ -74,7 +75,7 @@ namespace Xamarin.Essentials
Application.Context.GetSystemService(Context.ConnectivityService) as ConnectivityManager;
internal static Vibrator Vibrator =>
(Vibrator)Application.Context.GetSystemService(Context.VibratorService);
Application.Context.GetSystemService(Context.VibratorService) as Vibrator;
internal static WifiManager WifiManager =>
Application.Context.GetSystemService(Context.WifiService) as WifiManager;
@ -84,6 +85,9 @@ namespace Xamarin.Essentials
internal static ClipboardManager ClipboardManager =>
Application.Context.GetSystemService(Context.ClipboardService) as ClipboardManager;
internal static LocationManager LocationManager =>
Application.Context.GetSystemService(Context.LocationService) as LocationManager;
}
class ActivityLifecycleContextListener : Java.Lang.Object, Application.IActivityLifecycleCallbacks

Просмотреть файл

@ -19,6 +19,7 @@ namespace Xamarin.Essentials
return null;
var provider = new DataProtectionProvider();
var buffer = await provider.UnprotectAsync(encBytes.AsBuffer());
return Encoding.UTF8.GetString(buffer.ToArray());
@ -32,7 +33,9 @@ namespace Xamarin.Essentials
// LOCAL=user and LOCAL=machine do not require enterprise auth capability
var provider = new DataProtectionProvider("LOCAL=user");
var buffer = await provider.ProtectAsync(bytes.AsBuffer());
var encBytes = buffer.ToArray();
settings.Values[key] = encBytes;

Просмотреть файл

@ -46,6 +46,8 @@ namespace Xamarin.Essentials
public double Longitude { get; set; }
public double? Accuracy { get; set; }
public static double CalculateDistance(Location locationStart, Location locationEnd, DistanceUnits units) =>
CalculateDistance(locationStart.Latitude, locationStart.Longitude, locationEnd.Latitude, locationEnd.Longitude, units);

Просмотреть файл

@ -10,13 +10,24 @@ namespace Xamarin.Essentials
public static partial class LocationExtensions
{
internal static Location ToLocation(this AndroidAddress address) =>
new Location(address.Latitude, address.Longitude, DateTimeOffset.UtcNow);
new Location
{
Latitude = address.Latitude,
Longitude = address.Longitude,
TimestampUtc = DateTimeOffset.UtcNow
};
internal static IEnumerable<Location> ToLocations(this IEnumerable<AndroidAddress> addresses) =>
addresses?.Select(a => a.ToLocation());
internal static Location ToLocation(this AndroidLocation location) =>
new Location(location.Latitude, location.Longitude, location.GetTimestamp().ToUniversalTime());
new Location
{
Latitude = location.Latitude,
Longitude = location.Longitude,
TimestampUtc = location.GetTimestamp().ToUniversalTime(),
Accuracy = location.HasAccuracy ? location.Accuracy : (float?)null
};
static readonly DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

Просмотреть файл

@ -2,15 +2,42 @@
using System.Collections.Generic;
using System.Linq;
using CoreLocation;
using Foundation;
namespace Xamarin.Essentials
{
public static partial class LocationExtensions
{
internal static Location ToLocation(this CLPlacemark placemark) =>
new Location(placemark.Location.Coordinate.Latitude, placemark.Location.Coordinate.Longitude, DateTimeOffset.UtcNow);
new Location
{
Latitude = placemark.Location.Coordinate.Latitude,
Longitude = placemark.Location.Coordinate.Longitude,
TimestampUtc = DateTimeOffset.UtcNow
};
internal static IEnumerable<Location> ToLocations(this IEnumerable<CLPlacemark> placemarks) =>
placemarks?.Select(a => a.ToLocation());
internal static Location ToLocation(this CLLocation location) =>
new Location
{
Latitude = location.Coordinate.Latitude,
Longitude = location.Coordinate.Longitude,
Accuracy = location.HorizontalAccuracy,
TimestampUtc = location.Timestamp.ToDateTime()
};
internal static DateTimeOffset ToDateTime(this NSDate timestamp)
{
try
{
return new DateTimeOffset((DateTime)timestamp);
}
catch
{
return DateTimeOffset.UtcNow;
}
}
}
}

Просмотреть файл

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Devices.Geolocation;
using Windows.Services.Maps;
namespace Xamarin.Essentials
@ -8,12 +9,26 @@ namespace Xamarin.Essentials
public static partial class LocationExtensions
{
internal static Location ToLocation(this MapLocation mapLocation) =>
new Location(mapLocation.Point.Position.Latitude, mapLocation.Point.Position.Longitude, DateTimeOffset.UtcNow);
new Location
{
Latitude = mapLocation.Point.Position.Latitude,
Longitude = mapLocation.Point.Position.Longitude,
TimestampUtc = DateTimeOffset.UtcNow
};
internal static IEnumerable<Location> ToLocations(this IEnumerable<MapLocation> mapLocations) =>
mapLocations?.Select(a => a.ToLocation());
internal static IEnumerable<Location> ToLocations(this MapLocationFinderResult result) =>
result?.ToLocations();
internal static Location ToLocation(this Geoposition location) =>
new Location
{
Latitude = location.Coordinate.Point.Position.Latitude,
Longitude = location.Coordinate.Point.Position.Longitude,
TimestampUtc = location.Coordinate.Timestamp,
Accuracy = location.Coordinate.Accuracy
};
}
}

Просмотреть файл

@ -3,6 +3,7 @@
using System.Security.Cryptography;
#endif
using System.Text;
using System.Threading;
namespace Xamarin.Essentials
{
@ -31,5 +32,18 @@ namespace Xamarin.Essentials
return hash.ToString();
#endif
}
internal static CancellationToken TimeoutToken(CancellationToken cancellationToken, TimeSpan timeout)
{
// create a new linked cancellation token source
var cancelTokenSrc = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
// if a timeout was given, make the token source cancel after it expires
if (timeout > TimeSpan.Zero)
cancelTokenSrc.CancelAfter(timeout);
// our Cancel method will handle the actual cancellation logic
return cancelTokenSrc.Token;
}
}
}

Просмотреть файл

@ -12,7 +12,7 @@
<Interfaces />
<Docs>
<summary>Event arguments containing the current reading.</summary>
<remarks>To be added.</remarks>
<remarks></remarks>
</Docs>
<Members>
<Member MemberName="Reading">

Просмотреть файл

@ -0,0 +1,94 @@
<Type Name="Geolocation" FullName="Xamarin.Essentials.Geolocation">
<TypeSignature Language="C#" Value="public static class Geolocation" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi abstract sealed beforefieldinit Geolocation extends System.Object" />
<AssemblyInfo>
<AssemblyName>Xamarin.Essentials</AssemblyName>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>System.Object</BaseTypeName>
</Base>
<Interfaces />
<Docs>
<summary>Provides a way to get the current location of the device.</summary>
<remarks></remarks>
</Docs>
<Members>
<Member MemberName="GetLastKnownLocationAsync">
<MemberSignature Language="C#" Value="public static System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt; GetLastKnownLocationAsync ();" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class System.Threading.Tasks.Task`1&lt;class Xamarin.Essentials.Location&gt; GetLastKnownLocationAsync() cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt;</ReturnType>
</ReturnValue>
<Parameters />
<Docs>
<summary>Returns the last known location of the device.</summary>
<returns>Returns the location.</returns>
<remarks>This location may be a recently cached location.</remarks>
</Docs>
</Member>
<Member MemberName="GetLocationAsync">
<MemberSignature Language="C#" Value="public static System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt; GetLocationAsync ();" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class System.Threading.Tasks.Task`1&lt;class Xamarin.Essentials.Location&gt; GetLocationAsync() cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt;</ReturnType>
</ReturnValue>
<Parameters />
<Docs>
<summary>Returns the current location of the device.</summary>
<returns>Returns the location.</returns>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName="GetLocationAsync">
<MemberSignature Language="C#" Value="public static System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt; GetLocationAsync (Xamarin.Essentials.GeolocationRequest request);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class System.Threading.Tasks.Task`1&lt;class Xamarin.Essentials.Location&gt; GetLocationAsync(class Xamarin.Essentials.GeolocationRequest request) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt;</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="request" Type="Xamarin.Essentials.GeolocationRequest" />
</Parameters>
<Docs>
<param name="request">The criteria to use when determining the location of the device.</param>
<summary>Returns the current location of the device using the specified criteria.</summary>
<returns>Returns the location.</returns>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName="GetLocationAsync">
<MemberSignature Language="C#" Value="public static System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt; GetLocationAsync (Xamarin.Essentials.GeolocationRequest request, System.Threading.CancellationToken cancelToken);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig class System.Threading.Tasks.Task`1&lt;class Xamarin.Essentials.Location&gt; GetLocationAsync(class Xamarin.Essentials.GeolocationRequest request, valuetype System.Threading.CancellationToken cancelToken) cil managed" />
<MemberType>Method</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Threading.Tasks.Task&lt;Xamarin.Essentials.Location&gt;</ReturnType>
</ReturnValue>
<Parameters>
<Parameter Name="request" Type="Xamarin.Essentials.GeolocationRequest" />
<Parameter Name="cancelToken" Type="System.Threading.CancellationToken" />
</Parameters>
<Docs>
<param name="request">The criteria to use when determining the location of the device.</param>
<param name="cancelToken">A token for cancelling the operation.</param>
<summary>Returns the current location of the device using the specified criteria.</summary>
<returns>Returns the location.</returns>
<remarks></remarks>
</Docs>
</Member>
</Members>
</Type>

Просмотреть файл

@ -0,0 +1,92 @@
<Type Name="GeolocationAccuracy" FullName="Xamarin.Essentials.GeolocationAccuracy">
<TypeSignature Language="C#" Value="public enum GeolocationAccuracy" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi sealed GeolocationAccuracy extends System.Enum" />
<AssemblyInfo>
<AssemblyName>Xamarin.Essentials</AssemblyName>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>System.Enum</BaseTypeName>
</Base>
<Docs>
<summary>Represents levels of accuracy when determining location.</summary>
<remarks></remarks>
</Docs>
<Members>
<Member MemberName="Best">
<MemberSignature Language="C#" Value="Best" />
<MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Essentials.GeolocationAccuracy Best = int32(4)" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<MemberValue>4</MemberValue>
<Docs>
<summary>Represents the best accuracy, using the most power to obtain and typically within 10 meters.</summary>
</Docs>
</Member>
<Member MemberName="High">
<MemberSignature Language="C#" Value="High" />
<MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Essentials.GeolocationAccuracy High = int32(3)" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<MemberValue>3</MemberValue>
<Docs>
<summary>Represents high accuracy, typically within 10-100 meters.</summary>
</Docs>
</Member>
<Member MemberName="Low">
<MemberSignature Language="C#" Value="Low" />
<MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Essentials.GeolocationAccuracy Low = int32(1)" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<MemberValue>1</MemberValue>
<Docs>
<summary>Represents low accuracy, typically within 300-3000 meters.</summary>
</Docs>
</Member>
<Member MemberName="Lowest">
<MemberSignature Language="C#" Value="Lowest" />
<MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Essentials.GeolocationAccuracy Lowest = int32(0)" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<MemberValue>0</MemberValue>
<Docs>
<summary>Represents the lowest accuracy, using the least power to obtain and typically within 1000-5000 meters.</summary>
</Docs>
</Member>
<Member MemberName="Medium">
<MemberSignature Language="C#" Value="Medium" />
<MemberSignature Language="ILAsm" Value=".field public static literal valuetype Xamarin.Essentials.GeolocationAccuracy Medium = int32(2)" />
<MemberType>Field</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<MemberValue>2</MemberValue>
<Docs>
<summary>Represents medium accuracy, typically within 30-500 meters.</summary>
</Docs>
</Member>
</Members>
</Type>

Просмотреть файл

@ -0,0 +1,97 @@
<Type Name="GeolocationRequest" FullName="Xamarin.Essentials.GeolocationRequest">
<TypeSignature Language="C#" Value="public class GeolocationRequest" />
<TypeSignature Language="ILAsm" Value=".class public auto ansi beforefieldinit GeolocationRequest extends System.Object" />
<AssemblyInfo>
<AssemblyName>Xamarin.Essentials</AssemblyName>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Base>
<BaseTypeName>System.Object</BaseTypeName>
</Base>
<Interfaces />
<Docs>
<summary>Represents the criteria for a location request.</summary>
<remarks></remarks>
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public GeolocationRequest ();" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor() cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters />
<Docs>
<summary>Creates a new instance of GeolocationRequest.</summary>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public GeolocationRequest (Xamarin.Essentials.GeolocationAccuracy accuracy);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(valuetype Xamarin.Essentials.GeolocationAccuracy accuracy) cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters>
<Parameter Name="accuracy" Type="Xamarin.Essentials.GeolocationAccuracy" />
</Parameters>
<Docs>
<param name="accuracy">The desired accuracy.</param>
<summary>Creates a new instance of GeolocationRequest with the specified accuracy.</summary>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public GeolocationRequest (Xamarin.Essentials.GeolocationAccuracy accuracy, TimeSpan timeout);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(valuetype Xamarin.Essentials.GeolocationAccuracy accuracy, valuetype System.TimeSpan timeout) cil managed" />
<MemberType>Constructor</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<Parameters>
<Parameter Name="accuracy" Type="Xamarin.Essentials.GeolocationAccuracy" />
<Parameter Name="timeout" Type="System.TimeSpan" />
</Parameters>
<Docs>
<param name="accuracy">The desired accuracy.</param>
<param name="timeout">The request timeout.</param>
<summary>Creates a new instance of GeolocationRequest with the specified accuracy and timeout.</summary>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName="DesiredAccuracy">
<MemberSignature Language="C#" Value="public Xamarin.Essentials.GeolocationAccuracy DesiredAccuracy { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance valuetype Xamarin.Essentials.GeolocationAccuracy DesiredAccuracy" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>Xamarin.Essentials.GeolocationAccuracy</ReturnType>
</ReturnValue>
<Docs>
<summary>Gets or sets the desired accuracy of the resulting location.</summary>
<value>The desired accuracy of the location.</value>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName="Timeout">
<MemberSignature Language="C#" Value="public TimeSpan Timeout { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance valuetype System.TimeSpan Timeout" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.TimeSpan</ReturnType>
</ReturnValue>
<Docs>
<summary>Gets or sets the location request timeout.</summary>
<value>The location request timeout.</value>
<remarks></remarks>
</Docs>
</Member>
</Members>
</Type>

Просмотреть файл

@ -100,6 +100,22 @@
</remarks>
</Docs>
</Member>
<Member MemberName="Accuracy">
<MemberSignature Language="C#" Value="public Nullable&lt;double&gt; Accuracy { get; set; }" />
<MemberSignature Language="ILAsm" Value=".property instance valuetype System.Nullable`1&lt;float64&gt; Accuracy" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.Nullable&lt;System.Double&gt;</ReturnType>
</ReturnValue>
<Docs>
<summary>Gets or sets the accuracy (in meters) of the location.</summary>
<value>The location accuracy.</value>
<remarks></remarks>
</Docs>
</Member>
<Member MemberName="CalculateDistance">
<MemberSignature Language="C#" Value="public static double CalculateDistance (Xamarin.Essentials.Location locationStart, Xamarin.Essentials.Location locationEnd, Xamarin.Essentials.DistanceUnits units);" />
<MemberSignature Language="ILAsm" Value=".method public static hidebysig float64 CalculateDistance(class Xamarin.Essentials.Location locationStart, class Xamarin.Essentials.Location locationEnd, valuetype Xamarin.Essentials.DistanceUnits units) cil managed" />
@ -264,7 +280,7 @@
</ReturnValue>
<Docs>
<summary>Gets or sets the timestamp of the location.</summary>
<value>Utc timestamp.</value>
<value>UTC timestamp.</value>
<remarks>
<para></para>
</remarks>

Просмотреть файл

@ -56,8 +56,8 @@
</Attributes>
</Assembly>
</Assemblies>
<Remarks>To be added.</Remarks>
<Copyright>To be added.</Copyright>
<Remarks></Remarks>
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
<Types>
<Namespace Name="Xamarin.Essentials">
<Type Name="Accelerometer" Kind="Class" />
@ -94,6 +94,9 @@
<Type Name="FileSystem" Kind="Class" />
<Type Name="Flashlight" Kind="Class" />
<Type Name="Geocoding" Kind="Class" />
<Type Name="Geolocation" Kind="Class" />
<Type Name="GeolocationAccuracy" Kind="Enumeration" />
<Type Name="GeolocationRequest" Kind="Class" />
<Type Name="Gyroscope" Kind="Class" />
<Type Name="GyroscopeChangedEventArgs" Kind="Class" />
<Type Name="GyroscopeChangedEventHandler" Kind="Delegate" />