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