b5c374eae91ceb906438fc0e91056a1a4797d637
[platform/core/csapi/tizenfx.git] / src / Tizen.Location / Tizen.Location / Locator.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Threading.Tasks;
20 using Tizen.Internals.Errors;
21 using System.Runtime.InteropServices;
22
23 namespace Tizen.Location
24 {
25     static internal class Globals
26     {
27         internal const string LogTag = "Tizen.Location";
28     }
29
30     /// <summary>
31     /// A class which contains the functionality for obtaining geographical infomation and setting boundary condition.
32     /// Notifications on events like service becoming enabled or disabled, new position data being available
33     /// and others can also be acquired.
34     /// </summary>
35     public class Locator : IDisposable
36     {
37         private int _interval = 1;
38         private int _stayInterval = 120;
39         private int _requestId = 0;
40         private double _distance = 120.0;
41         private bool _isEnableMock = false;
42         private bool _disposed = false;
43         private bool _isStarted = false;
44         private IntPtr _handle;
45         private LocationType _locationType;
46         private Location _location = null;
47         private Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback> _callback_map = new Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback>();
48
49         private Interop.LocatorEvent.ServiceStatechangedCallback _serviceStateChangedCallback;
50         private Interop.LocatorEvent.ZonechangedCallback _zoneChangedCallback;
51         private Interop.LocatorEvent.SettingchangedCallback _settingChangedCallback;
52         private Interop.LocatorEvent.LocationchangedCallback _distanceBasedLocationChangedCallback;
53         private Interop.LocatorEvent.LocationchangedCallback _locationChangedCallback;
54
55         private EventHandler<ZoneChangedEventArgs> _zoneChanged;
56         private EventHandler<ServiceStateChangedEventArgs> _serviceStateChanged;
57         private EventHandler<SettingChangedEventArgs> _settingChanged;
58         private EventHandler<LocationChangedEventArgs> _distanceBasedLocationChanged;
59         private EventHandler<LocationChangedEventArgs> _locationChanged;
60
61         /// <summary>
62         /// The constructor of Locator class.
63         /// </summary>
64         /// <param name="locationType"> The back-end positioning method to be used for LBS.</param>
65         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
66         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
67         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
68         public Locator(LocationType locationType)
69         {
70             Log.Info(Globals.LogTag, "Locator Constructor");
71             int ret = Interop.Locator.Create((int)locationType, out _handle);
72             if (((LocationError)ret != LocationError.None))
73             {
74                 Log.Error(Globals.LogTag, "Error creating Location Manager," + (LocationError)ret);
75                 throw LocationErrorFactory.ThrowLocationException(ret);
76             }
77             _location = new Location();
78             _locationType = locationType;
79         }
80
81         /// <summary>
82         /// The destructor of Locator class.
83         /// </summary>
84         ~Locator()
85         {
86             Dispose(false);
87         }
88
89         /// <summary>
90         /// The time interval between callback updates.
91         /// Should be in the range [1~120] seconds.
92         /// </summary>
93         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
94         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
95         public int Interval
96         {
97             get
98             {
99                 Log.Info(Globals.LogTag, "Getting the Callback Interval");
100                 return _interval;
101             }
102             set
103             {
104                 Log.Info(Globals.LogTag, "Setting the Callback Interval");
105                 if (value > 0 && value <= 120)
106                 {
107                     _interval = value;
108                 }
109                 else
110                 {
111                     Log.Error(Globals.LogTag, "Error setting Callback Interval");
112                     throw LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
113                 }
114             }
115         }
116
117         /// <summary>
118         /// The time interval between Distance based location callback updates.
119         /// Should be in the range [1~120] seconds.
120         /// </summary>
121         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
122         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
123         public int StayInterval
124         {
125             get
126             {
127                 Log.Info(Globals.LogTag, "Getting the StayInterval");
128                 return _stayInterval;
129             }
130             set
131             {
132                 Log.Info(Globals.LogTag, "Setting the StayInterval");
133                 if (value > 0 && value <= 120)
134                 {
135                     _stayInterval = value;
136                 }
137                 else
138                 {
139                     Log.Error(Globals.LogTag, "Error Setting the StayInterval");
140                     throw LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
141                 }
142             }
143         }
144
145         /// <summary>
146         /// The distance between callback updates.
147         /// Should be in the range [1-120] meters.
148         /// </summary>
149         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
150         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
151         public double Distance
152         {
153             get
154             {
155                 Log.Info(Globals.LogTag, "Getting the Distance Interval");
156                 return _distance;
157             }
158             set
159             {
160                 Log.Info(Globals.LogTag, "Setting the Distance Interval");
161                 if (value > 0 && value <= 120)
162                 {
163                     _distance = value;
164                 }
165                 else
166                 {
167                     Log.Error(Globals.LogTag, "Error Setting the Distance");
168                     throw LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
169                 }
170             }
171         }
172
173         /// <summary>
174         /// Gets the Location object.
175         /// </summary>
176         public Location Location
177         {
178             get
179             {
180                 Log.Info(Globals.LogTag, "Getting location details");
181                 return _location;
182            }
183         }
184
185         /// <summary>
186         /// Gets the type used to obtain Location data.
187         /// </summary>
188         public LocationType LocationType
189         {
190             get
191             {
192                 Log.Info(Globals.LogTag, "Getting LocationType");
193                 return _locationType;
194             }
195         }
196
197         /// <summary>
198         /// Gets the status whether mock location is enabled or not.
199         /// </summary>
200         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
201         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
202         public bool EnableMock
203         {
204             get
205             {
206                 Log.Info(Globals.LogTag, "Getting getting Mock");
207                 _isEnableMock = GetEnableMock();
208                 return _isEnableMock;
209             }
210             set
211             {
212                 _isEnableMock = value;
213                 SetEnableMock();
214             }
215         }
216
217         internal IntPtr GetHandle()
218         {
219             return _handle;
220         }
221
222         private bool GetEnableMock()
223         {
224                         bool status = false;
225             int ret = Interop.Locator.IsEnabledMock(out status);
226             if (((LocationError)ret != LocationError.None))
227             {
228                 Log.Error(Globals.LogTag, "Error Get Enable Mock Status," + (LocationError)ret);
229                 throw LocationErrorFactory.ThrowLocationException(ret);
230             }
231                         return status;
232         }
233
234         private void SetEnableMock()
235         {
236             int ret = Interop.Locator.EnableMock(_isEnableMock);
237             if (((LocationError)ret != LocationError.None))
238             {
239                 Log.Error(Globals.LogTag, "Error Set Enable Mock Status," + (LocationError)ret);
240                 throw LocationErrorFactory.ThrowLocationException(ret);
241             }
242         }
243
244         /// <summary>
245         /// Starts the Location Manager which has been created using the specified method.
246         /// </summary>
247         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
248         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
249         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
250         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
251         public void Start()
252         {
253             Log.Info(Globals.LogTag, "Starting Location Manager");
254             int ret = Interop.Locator.Start(_handle);
255             if (((LocationError)ret != LocationError.None))
256             {
257                 Log.Error(Globals.LogTag, "Error Starting Location Manager," + (LocationError)ret);
258                 throw LocationErrorFactory.ThrowLocationException(ret);
259             }
260             _isStarted = true;
261         }
262
263         /// <summary>
264         /// Stops the Location Manager which has been activated using the specified method.
265         /// Does not destroy the manager.
266         /// </summary>
267         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
268         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
269         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
270         public void Stop()
271         {
272             Log.Info(Globals.LogTag, "Stopping Location Manager");
273             int ret = Interop.Locator.Stop(_handle);
274             if (((LocationError)ret != LocationError.None))
275             {
276                 Log.Error(Globals.LogTag, "Error stopping Location Manager," + (LocationError)ret);
277                 throw LocationErrorFactory.ThrowLocationException(ret);
278             }
279             _isStarted = false;
280        }
281
282         /// <summary>
283         /// Sets a mock location for the given location method.
284         /// </summary>
285         /// <param name="location"> The location object containing the mock location details.</param>
286         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
287         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
288         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
289         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
290         public void SetMockLocation(Location location)
291         {
292             Log.Info(Globals.LogTag, "Setting mock location");
293             int ret = Interop.Locator.SetMockLocation(_handle, location.Latitude, location.Longitude, location.Altitude, location.Speed, location.Direction, location.Accuracy);
294             if (((LocationError)ret == LocationError.None))
295             {
296                 _location.Latitude = location.Latitude;
297                 _location.Longitude = location.Longitude;
298                 _location.Altitude = location.Altitude;
299                 _location.Speed = location.Speed;
300                 _location.Direction = location.Direction;
301                 _location.Accuracy = location.Accuracy;
302             }
303             else
304             {
305                 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
306                 throw LocationErrorFactory.ThrowLocationException(ret);
307             }
308         }
309
310         /// <summary>
311         /// Clears a mock location for the given location method.
312         /// </summary>
313         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
314         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
315         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
316         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
317         public void ClearMock()
318         {
319             Log.Info(Globals.LogTag, "Clear mock location");
320             int ret = Interop.Locator.ClearMock(_handle);
321             if (((LocationError)ret != LocationError.None))
322             {
323                 Log.Error(Globals.LogTag, "Error in clear up location mocking," + (LocationError)ret);
324                 throw LocationErrorFactory.ThrowLocationException(ret);
325             }
326         }
327
328         /// <summary>
329         /// Gets the details of the location asynchronously.
330         /// </summary>
331         /// <param name="timeout"> Timeout to stop requesting single location after(seconds).</param>
332         /// <returns> A task which contains the current location details</returns>
333         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
334         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
335         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
336         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
337         public Task<Location> GetLocationAsync(int timeout)
338         {
339             var task = new TaskCompletionSource<Location>();
340             IntPtr id = IntPtr.Zero;
341             lock (_callback_map)
342             {
343                 id = (IntPtr)_requestId++;
344                 _callback_map[id] = (LocationError error, double latitude, double longitude, double altitude, int timestamp, double speed, double direction, double climb, IntPtr userData) =>
345                 {
346                     if (error != LocationError.None)
347                     {
348                         Log.Error(Globals.LogTag, "Error in getting up location information," + (LocationError)error);
349                     }
350                     else
351                     {
352                         Log.Info(Globals.LogTag, "Creating a current location object");
353                         _location = new Location(latitude, longitude, altitude, speed, direction, 0.0, timestamp);
354                         task.SetResult(_location);
355                     }
356                     lock (_callback_map)
357                     {
358                         _callback_map.Remove(userData);
359                     }
360                 };
361             }
362
363             int ret = Interop.LocatorEvent.GetSingleLocation(_handle, timeout, _callback_map[id], id);
364             if (((LocationError)ret != LocationError.None))
365             {
366                 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
367                 throw LocationErrorFactory.ThrowLocationException(ret);
368             }
369             return task.Task;
370         }
371
372
373         /// <summary>
374         /// Gets the details of the location.
375         /// </summary>
376         /// <returns> which contains the current location details</returns>
377         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
378         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
379         /// <exception cref="UnauthroizedAccessException">Thrown when the app has no privilege to use the location</exception>
380         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
381         public Location GetLocation()
382         {
383             double latitude = 0;
384             double longitude = 0;
385             double altitude = 0;
386             double climb = 0;
387             double speed = 0;
388             double direction = 0;
389             int level = 0;
390             double accuracy = 0;
391             double vertical = 0;
392             int timestamp = 0;
393
394             if (_isStarted)
395             {
396                 Log.Info(Globals.LogTag, "Get current location information");
397                 int ret = Interop.Locator.GetLocation(_handle, out altitude, out latitude, out longitude, out climb, out direction, out speed, out level, out accuracy, out vertical, out timestamp);
398                 if (((LocationError)ret != LocationError.None))
399                 {
400                     Log.Error(Globals.LogTag, "Error in get current location infomation," + (LocationError)ret);
401                     throw LocationErrorFactory.ThrowLocationException(ret);
402                 }
403             }
404             else
405             {
406                 Log.Info(Globals.LogTag, "Get last location information");
407                 int ret = Interop.Locator.GetLastLocation(_handle, out altitude, out latitude, out longitude, out climb, out direction, out speed, out level, out accuracy, out vertical, out timestamp);
408                 if (((LocationError)ret != LocationError.None))
409                 {
410                     Log.Error(Globals.LogTag, "Error in get last location information," + (LocationError)ret);
411                     throw LocationErrorFactory.ThrowLocationException(ret);
412                 }
413             }
414
415             Location location = new Location(latitude, longitude, altitude, speed, direction, accuracy, timestamp);
416             _location = location;
417
418             return location;
419         }
420
421
422         /// <summary>
423         /// Adds a bounds for a given locator.
424         /// </summary>
425         /// <param name="locationBoundary"> The boundary object to be added to the locator.</param>
426         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
427         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
428         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
429         public void AddBoundary(LocationBoundary locationBoundary)
430         {
431             Log.Info(Globals.LogTag, "AddBoundary called");
432
433             int ret = Interop.Locator.AddBoundary(_handle, locationBoundary.GetHandle());
434             if ((LocationBoundError)ret != LocationBoundError.None)
435             {
436                 Log.Error(Globals.LogTag, "Error Adding Boundary," + (LocationBoundError)ret);
437                 throw LocationErrorFactory.ThrowLocationBoundaryException(ret);
438             }
439         }
440
441         /// <summary>
442         /// Deletes a bounds for a given locator.
443         /// </summary>
444         /// <param name="locationBoundary"> The boundary object to be removed from the locator.</param>
445         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
446         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
447         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
448         public void RemoveBoundary(LocationBoundary locationBoundary)
449         {
450             Log.Info(Globals.LogTag, "RemoveBoundary called");
451             int ret = Interop.Locator.RemoveBoundary(_handle, locationBoundary.GetHandle());
452             if ((LocationBoundError)ret != LocationBoundError.None)
453             {
454                 Log.Error(Globals.LogTag, "Error Removing Boundary," + (LocationBoundError)ret);
455                 throw LocationErrorFactory.ThrowLocationBoundaryException(ret);
456             }
457         }
458
459         /// <summary>
460         /// The overidden Dispose method of the IDisposable class.
461         /// </summary>
462         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
463         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
464         public void Dispose()
465         {
466             Dispose(true);
467             GC.SuppressFinalize(this);
468         }
469
470         protected virtual void Dispose(bool disposing)
471         {
472             if (_disposed)
473                 return;
474
475             if (disposing)
476                 DestroyHandle();
477
478             _disposed = true;
479         }
480
481         private void DestroyHandle()
482         {
483             int ret = Interop.Locator.Destroy(_handle);
484             if (((LocationError)ret != LocationError.None))
485             {
486                 Log.Error(Globals.LogTag, "Error in Destroy handle, " + (LocationError)ret);
487                 throw LocationErrorFactory.ThrowLocationException(ret);
488             }
489         }
490
491         /// <summary>
492         /// (event) ServiceStateChanged Event is invoked when the location service state is changed.
493         /// </summary>
494         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
495         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
496         public event EventHandler<ServiceStateChangedEventArgs> ServiceStateChanged
497         {
498             add
499             {
500                 Log.Info(Globals.LogTag, "ServiceStateChanged called");
501                 if (_serviceStateChanged == null)
502                 {
503                     Log.Info(Globals.LogTag, "Calling function SetServiceStateChangedCallback");
504                     SetServiceStateChangedCallback();
505                 }
506                 _serviceStateChanged += value;
507             }
508             remove
509             {
510                 Log.Info(Globals.LogTag, "Callback removed");
511                 _serviceStateChanged -= value;
512
513                 if (_serviceStateChanged == null)
514                 {
515                     Log.Info(Globals.LogTag, "Calling function UnSetServiceStateChangedCallback");
516                     UnSetServiceStateChangedCallback();
517                 }
518             }
519         }
520
521         private void SetServiceStateChangedCallback()
522         {
523             Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.SetServiceStateChangedCallback");
524             if (_serviceStateChangedCallback == null)
525             {
526                 _serviceStateChangedCallback = (state, userData) =>
527                 {
528                     Log.Info(Globals.LogTag, "Inside ServiceStateChangedCallback");
529                     _serviceStateChanged?.Invoke(this, new ServiceStateChangedEventArgs(state));
530                 };
531             }
532
533             int ret = Interop.LocatorEvent.SetServiceStateChangedCallback(_handle, _serviceStateChangedCallback, IntPtr.Zero);
534             if (((LocationError)ret != LocationError.None))
535             {
536                 Log.Error(Globals.LogTag, "Error in Setting Service State Changed Callback," + (LocationError)ret);
537                 throw LocationErrorFactory.ThrowLocationException(ret);
538             }
539         }
540
541         private void UnSetServiceStateChangedCallback()
542         {
543             Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.UnSetServiceStateChangedCallback");
544             int ret = Interop.LocatorEvent.UnSetServiceStateChangedCallback(_handle);
545             if (((LocationError)ret != LocationError.None))
546             {
547                 Log.Error(Globals.LogTag, "Error in UnSetting Service State Changed Callback," + (LocationError)ret);
548                 throw LocationErrorFactory.ThrowLocationException(ret);
549             }
550         }
551
552         /// <summary>
553         /// (event) ZoneChanged is  invoked when the previously set boundary area is entered or left.
554         /// </summary>
555         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
556         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
557         public event EventHandler<ZoneChangedEventArgs> ZoneChanged
558         {
559             add
560             {
561                 Log.Info(Globals.LogTag, "ZoneChanged called");
562                 if (_zoneChanged == null)
563                 {
564                     Log.Info(Globals.LogTag, "Calling function SetZoneChangedCallback");
565                     SetZoneChangedCallback();
566                 }
567                 _zoneChanged += value;
568             }
569             remove
570             {
571                 Log.Info(Globals.LogTag, "Callback removed");
572                 _zoneChanged -= value;
573
574                 if (_zoneChanged == null)
575                 {
576                     Log.Info(Globals.LogTag, "Calling function UnSetZoneChangedCallback");
577                     UnSetZoneChangedCallback();
578                 }
579             }
580         }
581
582         private void SetZoneChangedCallback()
583         {
584             Log.Info(Globals.LogTag, "Inside SetZoneChangedCallback");
585             if (_zoneChangedCallback == null)
586             {
587                 _zoneChangedCallback = (state, latitude, longitude, altitude, timestamp, userData) =>
588                 {
589                     Log.Info(Globals.LogTag, "Inside ZoneChangedCallback");
590                     DateTime timeStamp = DateTime.Now;
591                     if (timestamp != 0)
592                     {
593                         DateTime start = DateTime.SpecifyKind(new DateTime(1970, 1, 1).AddSeconds(timestamp), DateTimeKind.Utc);
594                         timeStamp = start.ToLocalTime();
595                     }
596                     _zoneChanged?.Invoke(this, new ZoneChangedEventArgs(state, latitude, longitude, altitude, timeStamp));
597                 };
598             }
599
600             int ret = Interop.LocatorEvent.SetZoneChangedCallback(_handle, _zoneChangedCallback, IntPtr.Zero);
601             if (((LocationError)ret != LocationError.None))
602             {
603                 Log.Error(Globals.LogTag, "Error in Setting Zone Changed Callback," + (LocationError)ret);
604                 throw LocationErrorFactory.ThrowLocationException(ret);
605             }
606         }
607
608         private void UnSetZoneChangedCallback()
609         {
610             Log.Info(Globals.LogTag, "Inside UnSetZoneChangedCallback");
611             int ret = Interop.LocatorEvent.UnSetZoneChangedCallback(_handle);
612             if (((LocationError)ret != LocationError.None))
613             {
614                 Log.Error(Globals.LogTag, "Error in UnSetting Zone Changed Callback," + (LocationError)ret);
615             }
616         }
617
618         /// <summary>
619         /// (event) SetttingChanged is raised when the location setting is changed.
620         /// </summary>
621         /// <exception cref="InvalidOperationException">Thrown when the operation is invalid for the current state</exception>
622         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
623         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
624         public event EventHandler<SettingChangedEventArgs> SettingChanged
625         {
626             add
627             {
628                 Log.Info(Globals.LogTag, "Adding SettingChanged EventHandler");
629                 if (_settingChanged == null)
630                 {
631                     Log.Info(Globals.LogTag, "Calling function SetSettingChangedCallback");
632                     SetSettingChangedCallback();
633                 }
634                 _settingChanged += value;
635             }
636             remove
637             {
638                 Log.Info(Globals.LogTag, "Removing SettingChanged EventHandler");
639                 _settingChanged -= value;
640
641                 if (_settingChanged == null)
642                 {
643                     Log.Info(Globals.LogTag, "Calling function UnSetSettingChangedCallback");
644                     UnSetSettingChangedCallback();
645                 }
646             }
647         }
648
649         private void SetSettingChangedCallback()
650         {
651             Log.Info(Globals.LogTag, "Calling SetSettingChangedCallback");
652             if (_settingChangedCallback == null)
653             {
654                 _settingChangedCallback = (method, enable, userData) =>
655                 {
656                     Log.Info(Globals.LogTag, "Calling SettingChangedCallback");
657                     _settingChanged?.Invoke(this, new SettingChangedEventArgs(method, enable));
658                 };
659             }
660
661             int ret = Interop.LocatorEvent.SetSettingChangedCallback((int)_locationType, _settingChangedCallback, IntPtr.Zero);
662             if (((LocationError)ret != LocationError.None))
663             {
664                 Log.Error(Globals.LogTag, "Error in Setting Changed Callback," + (LocationError)ret);
665                 throw LocationErrorFactory.ThrowLocationException(ret);
666             }
667         }
668
669         private void UnSetSettingChangedCallback()
670         {
671             Log.Info(Globals.LogTag, "Calling UnSetSettingChangedCallback");
672             int ret = Interop.LocatorEvent.UnSetSettingChangedCallback((int)_locationType);
673             if (((LocationError)ret != LocationError.None))
674             {
675                 Log.Error(Globals.LogTag, "Error in Unsetting Setting's Callback," + (LocationError)ret);
676                 throw LocationErrorFactory.ThrowLocationException(ret);
677             }
678         }
679
680         /// <summary>
681         /// (event) DistanceBasedLocationChanged is raised with updated location information.
682         /// The callback will be invoked at minimum interval or minimum distance with updated position information.
683         /// </summary>
684         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
685         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
686         public event EventHandler<LocationChangedEventArgs> DistanceBasedLocationChanged
687         {
688             add
689             {
690                 Log.Info(Globals.LogTag, "Adding DistanceBasedLocationChanged EventHandler");
691                 //if (_distanceBasedLocationChanged == null)
692                 {
693                     Log.Info(Globals.LogTag, "Calling function SetDistanceBasedLocationChangedCallback");
694                     SetDistanceBasedLocationChangedCallback();
695                 }
696                 _distanceBasedLocationChanged += value;
697             }
698             remove
699             {
700                 Log.Info(Globals.LogTag, "Removing DistanceBasedLocationChanged EventHandler");
701                 _distanceBasedLocationChanged -= value;
702
703                 if (_distanceBasedLocationChanged == null)
704                 {
705                     Log.Info(Globals.LogTag, "Calling function UnSetDistanceBasedLocationChangedCallback");
706                     UnSetDistanceBasedLocationChangedCallback();
707                 }
708             }
709         }
710
711         private void SetDistanceBasedLocationChangedCallback()
712         {
713             Log.Info(Globals.LogTag, "SetDistanceBasedLocationChangedCallback");
714             if (_distanceBasedLocationChangedCallback == null) {
715                 _distanceBasedLocationChangedCallback = (latitude, longitude, altitude, speed, direction, accuracy, timestamp, userData) =>
716                 {
717                     Log.Info(Globals.LogTag, "DistanceBasedLocationChangedCallback #1");
718                     Location location = new Location(latitude, longitude, altitude, speed, direction, accuracy, timestamp);
719                     Log.Info(Globals.LogTag, "DistanceBasedLocationChangedCallback #2");
720                     _distanceBasedLocationChanged?.Invoke(this, new LocationChangedEventArgs(location));
721                     Log.Info(Globals.LogTag, "DistanceBasedLocationChangedCallback #3");
722                 };
723             }
724
725             int ret = Interop.LocatorEvent.SetDistanceBasedLocationChangedCallback(_handle, _distanceBasedLocationChangedCallback, _stayInterval, _distance, IntPtr.Zero);
726             if (((LocationError)ret != LocationError.None))
727             {
728                 Log.Error(Globals.LogTag, "Error in Setting Distance based location changed Callback," + (LocationError)ret);
729                 throw LocationErrorFactory.ThrowLocationException(ret);
730             }
731         }
732
733         private void UnSetDistanceBasedLocationChangedCallback()
734         {
735             Log.Info(Globals.LogTag, "UnSetDistanceBasedLocationChangedCallback");
736             int ret = Interop.LocatorEvent.UnSetDistanceBasedLocationChangedCallback(_handle);
737             if (((LocationError)ret != LocationError.None))
738             {
739                 Log.Error(Globals.LogTag, "Error in UnSetting Distance based location changed Callback," + (LocationError)ret);
740                 throw LocationErrorFactory.ThrowLocationException(ret);
741             }
742             _distanceBasedLocationChanged = null;
743         }
744
745         /// <summary>
746         /// (event)LocationUpdated is raised at defined intervals of time with updated location information.
747         /// The callback will be invoked periodically.
748         /// </summary>
749         /// <exception cref="ArgumentException">Thrown when an invalid argument is used</exception>
750         /// <exception cref="NotSupportedException">Thrown when the location is not supported</exception>
751         public event EventHandler<LocationChangedEventArgs> LocationChanged
752         {
753             add
754             {
755                 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
756                 if (_locationChanged == null)
757                 {
758                     Log.Info(Globals.LogTag, "Calling function SetLocationChangedCallback");
759                     SetLocationChangedCallback();
760                 }
761                 _locationChanged += value;
762             }
763             remove
764             {
765                 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
766                 _locationChanged -= value;
767
768                 if (_locationChanged == null)
769                 {
770                     Log.Info(Globals.LogTag, "calling function UnSetLocationChangedCallback");
771                     UnSetLocationChangedCallback();
772                 }
773             }
774         }
775
776         private void SetLocationChangedCallback()
777         {
778             Log.Info(Globals.LogTag, "Calling SetLocationChangedCallback");
779
780             if (_locationChangedCallback == null) {
781                 _locationChangedCallback = (latitude, longitude, altitude, speed, direction, accuracy, timestamp, userData) =>
782                 {
783                     Log.Info(Globals.LogTag, "LocationChangedCallback has been called");
784                     Location location = new Location(latitude, longitude, altitude, speed, direction, accuracy, timestamp);
785                     _location = location;
786                     _locationChanged?.Invoke(this, new LocationChangedEventArgs(location));
787                 };
788             }
789
790             int ret = Interop.LocatorEvent.SetLocationChangedCallback(_handle, _locationChangedCallback, _interval, IntPtr.Zero);
791             if (((LocationError)ret != LocationError.None))
792             {
793                 Log.Error(Globals.LogTag, "Error in Setting location changed Callback," + (LocationError)ret);
794                 throw LocationErrorFactory.ThrowLocationException(ret);
795             }
796         }
797
798         private void UnSetLocationChangedCallback()
799         {
800             Log.Info(Globals.LogTag, "Calling UnSetLocationChangedCallback");
801             int ret = Interop.LocatorEvent.UnSetLocationChangedCallback(_handle);
802             if (((LocationError)ret != LocationError.None))
803             {
804                 Log.Error(Globals.LogTag, "Error in UnSetting location changed Callback," + (LocationError)ret);
805                 throw LocationErrorFactory.ThrowLocationException(ret);
806             }
807         }
808     }
809 }