-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Geolocation.shared.cs
213 lines (186 loc) · 10.7 KB
/
Geolocation.shared.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#nullable enable
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Maui.ApplicationModel;
namespace Microsoft.Maui.Devices.Sensors
{
/// <summary>
/// Provides a way to get the current location of the device.
/// </summary>
public interface IGeolocation
{
/// <summary>
/// Returns the last known location of the device.
/// </summary>
/// <returns>A <see cref="Location"/> object containing recent location information or <see langword="null"/> if no location is known.</returns>
/// <remarks>
/// <para>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</para>
/// <para>This location may be a recently cached location.</para>
/// </remarks>
Task<Location?> GetLastKnownLocationAsync();
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <param name="request">The criteria to use when determining the location of the device.</param>
/// <param name="cancelToken">A token that can be used for cancelling the operation.</param>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
Task<Location?> GetLocationAsync(GeolocationRequest request, CancellationToken cancelToken);
/// <summary>
/// Indicates if currently listening to location updates while the app is in foreground.
/// </summary>
bool IsListeningForeground { get; }
/// <summary>
/// Occurs while listening to location updates.
/// </summary>
event EventHandler<GeolocationLocationChangedEventArgs>? LocationChanged;
/// <summary>
/// Occurs when an error during listening for location updates arises. When the event is
/// fired, listening for further location updates has been stopped and no further
/// <see cref="LocationChanged"/> events are sent.
/// </summary>
event EventHandler<GeolocationListeningFailedEventArgs>? ListeningFailed;
/// <summary>
/// Starts listening to location updates using the <see cref="LocationChanged"/> event. Events
/// may only sent when the app is in the foreground. Requests
/// <see cref="Permissions.LocationWhenInUse"/> from the user.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="request"/> is <see langword="null"/>.</exception>
/// <exception cref="FeatureNotSupportedException">Thrown if listening is not supported on this platform.</exception>
/// <exception cref="InvalidOperationException">Thrown if already listening and <see cref="IsListeningForeground"/> returns <see langword="true"/>.</exception>
/// <param name="request">The listening request parameters to use.</param>
/// <returns><see langword="true"/> when listening was started, or <see langword="false"/> when listening couldn't be started.</returns>
Task<bool> StartListeningForegroundAsync(GeolocationListeningRequest request);
/// <summary>
/// Stop listening for location updates when the app is in the foreground.
/// Has no effect when <see cref="IsListeningForeground"/> is currently <see langword="false"/>.
/// </summary>
void StopListeningForeground();
}
/// <summary>
/// Provides a way to get the current location of the device.
/// </summary>
public static partial class Geolocation
{
/// <summary>
/// Returns the last known location of the device.
/// </summary>
/// <returns>A <see cref="Location"/> object containing recent location information or <see langword="null"/> if no location is known.</returns>
/// <remarks>
/// <para>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</para>
/// <para>This location may be a recently cached location.</para>
/// </remarks>
public static Task<Location?> GetLastKnownLocationAsync() =>
Current.GetLastKnownLocationAsync();
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
public static Task<Location?> GetLocationAsync() =>
Current.GetLocationAsync();
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <param name="request">The criteria to use when determining the location of the device.</param>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
public static Task<Location?> GetLocationAsync(GeolocationRequest request) =>
Current.GetLocationAsync(request);
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <param name="request">The criteria to use when determining the location of the device.</param>
/// <param name="cancelToken">A token that can be used for cancelling the operation.</param>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
public static Task<Location?> GetLocationAsync(GeolocationRequest request, CancellationToken cancelToken) =>
Current.GetLocationAsync(request, cancelToken);
/// <summary>
/// Indicates if currently listening to location updates while the app is in foreground.
/// </summary>
public static bool IsListeningForeground { get => Current.IsListeningForeground; }
/// <summary>
/// Occurs while listening to location updates.
/// </summary>
public static event EventHandler<GeolocationLocationChangedEventArgs> LocationChanged
{
add => Current.LocationChanged += value;
remove => Current.LocationChanged -= value;
}
/// <summary>
/// Occurs when an error during listening for location updates arises. When the event is
/// fired, listening for further location updates has been stopped and no further
/// <see cref="LocationChanged"/> events are sent.
/// </summary>
public static event EventHandler<GeolocationListeningFailedEventArgs> ListeningFailed
{
add => Current.ListeningFailed += value;
remove => Current.ListeningFailed -= value;
}
/// <summary>
/// Starts listening to location updates using the <see cref="Geolocation.LocationChanged"/>
/// event or the <see cref="Geolocation.ListeningFailed"/> event. Events may only sent when
/// the app is in the foreground. Requests <see cref="Permissions.LocationWhenInUse"/>
/// from the user.
/// </summary>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="request"/> is <see langword="null"/>.</exception>
/// <exception cref="FeatureNotSupportedException">Thrown if listening is not supported on this platform.</exception>
/// <exception cref="InvalidOperationException">Thrown if already listening and <see cref="IsListeningForeground"/> returns <see langword="true"/>.</exception>
/// <param name="request">The listening request parameters to use.</param>
/// <returns><see langword="true"/> when listening was started, or <see langword="false"/> when listening couldn't be started.</returns>
public static Task<bool> StartListeningForegroundAsync(GeolocationListeningRequest request) =>
Current.StartListeningForegroundAsync(request);
/// <summary>
/// Stop listening for location updates when the app is in the foreground.
/// Has no effect when not listening and <see cref="Geolocation.IsListeningForeground"/>
/// is currently <see langword="false"/>.
/// </summary>
public static void StopListeningForeground() =>
Current.StopListeningForeground();
static IGeolocation Current => Devices.Sensors.Geolocation.Default;
static IGeolocation? defaultImplementation;
/// <summary>
/// Provides the default implementation for static usage of this API.
/// </summary>
public static IGeolocation Default =>
defaultImplementation ??= new GeolocationImplementation();
internal static void SetDefault(IGeolocation? implementation) =>
defaultImplementation = implementation;
}
partial class GeolocationImplementation : IGeolocation
{
public event EventHandler<GeolocationLocationChangedEventArgs>? LocationChanged;
public event EventHandler<GeolocationListeningFailedEventArgs>? ListeningFailed;
internal void OnLocationChanged(Location location) =>
OnLocationChanged(new GeolocationLocationChangedEventArgs(location));
internal void OnLocationChanged(GeolocationLocationChangedEventArgs e) =>
LocationChanged?.Invoke(null, e);
internal void OnLocationError(GeolocationError geolocationError) =>
ListeningFailed?.Invoke(null, new GeolocationListeningFailedEventArgs(geolocationError));
}
/// <summary>
/// Static class with extension methods for the <see cref="IGeolocation"/> APIs.
/// </summary>
public static class GeolocationExtensions
{
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <param name="geolocation">The object this method is invoked on.</param>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
public static Task<Location?> GetLocationAsync(this IGeolocation geolocation) =>
geolocation.GetLocationAsync(new GeolocationRequest(), default);
/// <summary>
/// Returns the current location of the device.
/// </summary>
/// <param name="geolocation">The object this method is invoked on.</param>
/// <param name="request">The criteria to use when determining the location of the device.</param>
/// <returns>A <see cref="Location"/> object containing current location information or <see langword="null"/> if no location could be determined.</returns>
/// <remarks>The location permissions will be requested at runtime if needed. You might still need to declare something in your app manifest.</remarks>
public static Task<Location?> GetLocationAsync(this IGeolocation geolocation, GeolocationRequest request) =>
geolocation.GetLocationAsync(request ?? new GeolocationRequest(), default);
}
}