1 // Copyright 2016 by Samsung Electronics, Inc.,
3 // This software is the confidential and proprietary information
4 // of Samsung Electronics, Inc. ("Confidential Information"). You
5 // shall not disclose such Confidential Information and shall use
6 // it only in accordance with the terms of the license agreement
7 // you entered into with Samsung.
10 using System.Collections.Generic;
11 using System.Threading.Tasks;
12 using Tizen.Internals.Errors;
13 using System.Runtime.InteropServices;
15 namespace Tizen.Location
17 static internal class Globals
19 internal const string LogTag = "Tizen.Location";
23 /// A class which contains the functionality for obtaining geographical infomation and setting boundary condition.
24 /// Notifications on events like service becoming enabled or disabled, new position data being available
25 /// and others can also be acquired.
27 public class Locator:IDisposable
29 private int _interval = 1;
30 private int _stayInterval = 120;
31 private double _distance = 120.0;
32 private bool _isEnableMock;
33 private IntPtr _handle;
34 private LocationType _locationType;
35 private Location _location = null;
36 private bool _disposed = false;
37 private bool _isStarted = false;
38 private static Locator s_locatorReference;
39 private int _requestId = 0;
40 private Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback> _callback_map = new Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback>();
42 private EventHandler<ZoneChangedEventArgs> _zoneChanged;
43 private EventHandler<ServiceStateChangedEventArgs> _serviceStateChanged;
44 private EventHandler<SettingChangedEventArgs> _settingChanged;
45 private EventHandler<LocationChangedEventArgs> _distanceBasedLocationChanged;
46 private EventHandler<LocationChangedEventArgs> _locationChanged;
49 /// The constructor of Locator class.
51 /// <param name="locationType"> The back-end positioning method to be used for LBS.</param>
52 public Locator(LocationType locationType)
54 Log.Info(Globals.LogTag, "Locator Constructor");
55 int ret = Interop.Locator.Create((int)locationType, out _handle);
56 if (((LocationError)ret != LocationError.None))
58 Log.Error(Globals.LogTag, "Error creating Location Manager," + (LocationError)ret);
59 LocationErrorFactory.ThrowLocationException(ret);
61 _location = new Location();
62 _locationType = locationType;
66 /// The destructor of Locator class.
74 /// The time interval between callback updates.
75 /// Should be in the range [1~120] seconds.
81 Log.Info(Globals.LogTag, "Getting the Callback Interval");
86 Log.Info(Globals.LogTag, "Setting the Callback Interval");
87 if (value > 0 && value <= 120)
90 if (_locationChanged != null)
92 SetLocationChangedCallback();
97 Log.Error(Globals.LogTag, "Error setting Callback Interval");
98 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
104 /// The time interval between Distance based location callback updates.
105 /// Should be in the range [1~120] seconds.
107 public int StayInterval
111 Log.Info(Globals.LogTag, "Getting the StayInterval");
112 return _stayInterval;
116 Log.Info(Globals.LogTag, "Setting the StayInterval");
117 if (value > 0 && value <= 120)
119 _stayInterval = value;
120 if (_distanceBasedLocationChanged != null)
122 SetDistanceBasedLocationChangedCallback();
127 Log.Error(Globals.LogTag, "Error Setting the StayInterval");
128 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
134 /// The distance between callback updates.
135 /// Should be in the range [1-120] meters.
137 public double Distance
141 Log.Info(Globals.LogTag, "Getting the Distance Interval");
146 Log.Info(Globals.LogTag, "Setting the Distance Interval");
147 if (value > 0 && value <= 120)
150 if (_distanceBasedLocationChanged != null)
152 SetDistanceBasedLocationChangedCallback();
157 Log.Error(Globals.LogTag, "Error Setting the Distance");
158 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
164 /// Gets the Location object.
166 public Location Location
170 Log.Info(Globals.LogTag, "Getting location details");
176 /// Gets the type used to obtain Location data.
178 public LocationType LocationType
182 Log.Info(Globals.LogTag, "Getting LocationType");
183 return _locationType;
188 /// Gets the status whether mock location is enabled or not.
190 public bool EnableMock
194 Log.Info(Globals.LogTag, "Getting getting Mock");
195 return _isEnableMock;
199 _isEnableMock = value;
204 internal IntPtr GetHandle()
209 private void SetEnableMock()
211 int ret = Interop.Locator.EnableMock(_isEnableMock);
212 if (((LocationError)ret != LocationError.None))
214 Log.Error(Globals.LogTag, "Error Set Enable Mock Type," + (LocationError)ret);
215 LocationErrorFactory.ThrowLocationException(ret);
220 /// Starts the Location Manager which has been created using the specified method.
224 Log.Info(Globals.LogTag, "Starting Location Manager");
225 if (Locator.s_locatorReference == null)
227 int ret = Interop.Locator.Start(_handle);
228 if (((LocationError)ret != LocationError.None))
230 Log.Error(Globals.LogTag, "Error Starting Location Manager," + (LocationError)ret);
231 LocationErrorFactory.ThrowLocationException(ret);
233 Locator.s_locatorReference = this;
235 Log.Info(Globals.LogTag, "Locator reference set");
239 Log.Error(Globals.LogTag, "Error, previous instance of Locator should be stopped before starting a new one," + LocationError.NotSupported);
240 LocationErrorFactory.ThrowLocationException((int)LocationError.NotSupported);
245 /// Stops the Location Manager which has been activated using the specified method.
246 /// Does not destroy the manager.
250 Log.Info(Globals.LogTag, "Stopping Location Manager");
251 int ret = Interop.Locator.Stop(_handle);
252 if (((LocationError)ret != LocationError.None))
254 Log.Error(Globals.LogTag, "Error stopping Location Manager," + (LocationError)ret);
255 LocationErrorFactory.ThrowLocationException(ret);
257 Locator.s_locatorReference = null;
262 /// Sets a mock location for the given location method.
264 /// <param name="location"> The location object containing the mock location details.</param>
265 public void SetMockLocation(Location location)
267 Log.Info(Globals.LogTag, "Setting mock location");
268 int ret = Interop.Locator.SetMockLocation(_handle, location.Latitude, location.Longitude, location.Altitude, location.Speed, location.Direction, location.HorizontalAccuracy);
269 if (((LocationError)ret == LocationError.None))
271 _location.Altitude = 0;
272 _location.Latitude = location.Latitude;
273 _location.Longitude = location.Longitude;
274 _location.Speed = location.Speed;
275 _location.Direction = location.Direction;
276 _location.HorizontalAccuracy = location.HorizontalAccuracy;
280 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
281 LocationErrorFactory.ThrowLocationException(ret);
286 /// Clears a mock location for the given location method.
288 public void ClearMock()
290 Log.Info(Globals.LogTag, "Clear mock location");
291 int ret = Interop.Locator.ClearMock(_handle);
292 if (((LocationError)ret != LocationError.None))
294 Log.Error(Globals.LogTag, "Error in clear up location mocking," + (LocationError)ret);
295 LocationErrorFactory.ThrowLocationException(ret);
300 /// Gets the details of the location asynchronously.
302 /// <param name="timeout"> Timeout to stop requesting single location after(seconds).</param>
303 /// <returns> A task which contains the current location details</returns>
304 public Task<Location> GetLocationAsync(int timeout)
306 var task = new TaskCompletionSource<Location>();
307 IntPtr id = IntPtr.Zero;
310 id = (IntPtr)_requestId++;
311 _callback_map[id] = (LocationError error, double latitude, double longitude, double altitude, int timestamp, double speed, double direction, double climb, IntPtr userData) =>
313 if (error != LocationError.None)
315 Log.Error(Globals.LogTag, "Error in getting up location information," + (LocationError)error);
319 Log.Info(Globals.LogTag, "Creating a current location object");
320 _location = new Location(latitude, longitude, altitude, 0.0, direction, speed, timestamp);
321 task.SetResult(_location);
325 _callback_map.Remove(userData);
330 int ret = Interop.LocatorEvent.GetSingleLocation(_handle, timeout, _callback_map[id], id);
331 if (((LocationError)ret != LocationError.None))
333 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
334 LocationErrorFactory.ThrowLocationException(ret);
341 /// Gets the details of the location.
343 /// <returns> which contains the current location details</returns>
344 public Location GetLocation()
348 double longitude = 0;
350 double direction = 0;
352 LocationAccuracy level = LocationAccuracy.None;
353 double horizontal = 0;
359 Log.Info(Globals.LogTag, "Get current location information");
360 int ret = Interop.Locator.GetLocation(_handle, out altitude, out latitude, out longitude, out climb, out direction, out speed, out level, out horizontal, out vertical, out timestamp);
361 if (((LocationError)ret != LocationError.None))
363 Log.Error(Globals.LogTag, "Error in get current location infomation," + (LocationError)ret);
364 LocationErrorFactory.ThrowLocationException(ret);
369 Log.Info(Globals.LogTag, "Get last location information");
370 int ret = Interop.Locator.GetLastLocation(_handle, out altitude, out latitude, out longitude, out climb, out direction, out speed, out level, out horizontal, out vertical, out timestamp);
371 if (((LocationError)ret != LocationError.None))
373 Log.Error(Globals.LogTag, "Error in get last location information," + (LocationError)ret);
374 LocationErrorFactory.ThrowLocationException(ret);
378 Location location = new Location(latitude, longitude, altitude, horizontal, direction, speed, timestamp);
379 _location = location;
386 /// Adds a bounds for a given locator.
388 /// <param name="locationBoundary"> The boundary object to be added to the locator.</param>
389 public void AddBoundary(LocationBoundary locationBoundary)
391 Log.Info(Globals.LogTag, "AddBoundary called");
393 int ret = Interop.Locator.AddBoundary(_handle, locationBoundary.GetHandle());
394 if ((LocationBoundError)ret != LocationBoundError.None)
396 Log.Error(Globals.LogTag, "Error Adding Boundary," + (LocationBoundError)ret);
397 LocationErrorFactory.ThrowLocationBoundaryException(ret);
402 /// Deletes a bounds for a given locator.
404 /// <param name="locationBoundary"> The boundary object to be removed from the locator.</param>
405 public void RemoveBoundary(LocationBoundary locationBoundary)
407 Log.Info(Globals.LogTag, "RemoveBoundary called");
408 int ret = Interop.Locator.RemoveBoundary(_handle, locationBoundary.GetHandle());
409 if ((LocationBoundError)ret != LocationBoundError.None)
411 Log.Error(Globals.LogTag, "Error Removing Boundary," + (LocationBoundError)ret);
412 LocationErrorFactory.ThrowLocationBoundaryException(ret);
417 /// The overidden Dispose method of the IDisposable class.
419 public void Dispose()
422 GC.SuppressFinalize(this);
425 protected virtual void Dispose(bool disposing)
434 private void DestroyHandle()
436 int ret = Interop.Locator.Destroy(_handle);
437 if (((LocationError)ret != LocationError.None))
439 Log.Error(Globals.LogTag, "Error in Destroy handle" + (LocationError)ret);
440 LocationErrorFactory.ThrowLocationException(ret);
445 /// (event) ServiceStateChanged Event is invoked when the location service state is changed.
447 public event EventHandler<ServiceStateChangedEventArgs> ServiceStateChanged
451 Log.Info(Globals.LogTag, "ServiceStateChanged called");
452 if (_serviceStateChanged == null)
454 Log.Info(Globals.LogTag, "Calling function SetServiceStateChangedCallback");
455 SetServiceStateChangedCallback();
457 _serviceStateChanged += value;
461 Log.Info(Globals.LogTag, "Callback removed");
462 _serviceStateChanged -= value;
464 if (_serviceStateChanged == null)
466 Log.Info(Globals.LogTag, "Calling function UnSetServiceStateChangedCallback");
467 UnSetServiceStateChangedCallback();
472 private void SetServiceStateChangedCallback()
474 Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.SetServiceStateChangedCallback");
475 int ret = Interop.LocatorEvent.SetServiceStateChangedCallback(_handle, ServiceStateChangedCallback, IntPtr.Zero);
476 if (((LocationError)ret != LocationError.None))
478 Log.Error(Globals.LogTag, "Error in Setting Service State Changed Callback," + (LocationError)ret);
479 LocationErrorFactory.ThrowLocationException(ret);
483 private void UnSetServiceStateChangedCallback()
485 Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.UnSetServiceStateChangedCallback");
486 int ret = Interop.LocatorEvent.UnSetServiceStateChangedCallback(_handle);
487 if (((LocationError)ret != LocationError.None))
489 Log.Error(Globals.LogTag, "Error in UnSetting Service State Changed Callback," + (LocationError)ret);
490 LocationErrorFactory.ThrowLocationException(ret);
494 private void ServiceStateChangedCallback(ServiceState state, IntPtr userData)
496 Log.Info(Globals.LogTag, "Inside ServiceStateChangedCallback");
497 _serviceStateChanged?.Invoke(this, new ServiceStateChangedEventArgs(state));
501 /// (event) ZoneChanged is invoked when the previously set boundary area is entered or left.
503 public event EventHandler<ZoneChangedEventArgs> ZoneChanged
507 Log.Info(Globals.LogTag, "ZoneChanged called");
508 if (_zoneChanged == null)
510 Log.Info(Globals.LogTag, "Calling function SetZoneChangedCallback");
511 SetZoneChangedCallback();
513 _zoneChanged += value;
517 Log.Info(Globals.LogTag, "Callback removed");
518 _zoneChanged -= value;
520 if (_zoneChanged == null)
522 Log.Info(Globals.LogTag, "Calling function UnSetZoneChangedCallback");
523 UnSetZoneChangedCallback();
528 private void SetZoneChangedCallback()
530 Log.Info(Globals.LogTag, "Inside SetZoneChangedCallback");
531 int ret = Interop.LocatorEvent.SetZoneChangedCallback(_handle, ZoneChangedCallback, IntPtr.Zero);
532 if (((LocationError)ret != LocationError.None))
534 Log.Error(Globals.LogTag, "Error in Setting Zone Changed Callback," + (LocationError)ret);
535 LocationErrorFactory.ThrowLocationException(ret);
539 private void UnSetZoneChangedCallback()
541 Log.Info(Globals.LogTag, "Inside UnSetZoneChangedCallback");
542 int ret = Interop.LocatorEvent.UnSetZoneChangedCallback(_handle);
543 if (((LocationError)ret != LocationError.None))
545 Log.Error(Globals.LogTag, "Error in UnSetting Zone Changed Callback," + (LocationError)ret);
549 private void ZoneChangedCallback(BoundaryState state, double latitude, double longitude, double altitude, int timestamp, IntPtr userData)
551 Log.Info(Globals.LogTag, "Inside ZoneChangedCallback");
552 DateTime timeStamp = DateTime.Now;
555 DateTime start = DateTime.SpecifyKind(new DateTime(1970, 1, 1).AddSeconds(timestamp), DateTimeKind.Utc);
556 timeStamp = start.ToLocalTime();
558 _zoneChanged?.Invoke(this, new ZoneChangedEventArgs(state, latitude, longitude, altitude, timeStamp));
562 /// (event) SetttingChanged is raised when the location setting is changed.
564 public event EventHandler<SettingChangedEventArgs> SettingChanged
568 Log.Info(Globals.LogTag, "Adding SettingChanged EventHandler");
569 if (_settingChanged == null)
571 Log.Info(Globals.LogTag, "Calling function SetSettingChangedCallback");
572 SetSettingChangedCallback();
574 _settingChanged += value;
578 Log.Info(Globals.LogTag, "Removing SettingChanged EventHandler");
579 _settingChanged -= value;
581 if (_settingChanged == null)
583 Log.Info(Globals.LogTag, "Calling function UnSetSettingChangedCallback");
584 UnSetSettingChangedCallback();
589 private void SetSettingChangedCallback()
591 Log.Info(Globals.LogTag, "Calling SetSettingChangedCallback");
592 int ret = Interop.LocatorEvent.SetSettingChangedCallback((int)_locationType, SettingChangedCallback, IntPtr.Zero);
593 if (((LocationError)ret != LocationError.None))
595 Log.Error(Globals.LogTag, "Error in Setting Changed Callback," + (LocationError)ret);
596 LocationErrorFactory.ThrowLocationException(ret);
600 private void UnSetSettingChangedCallback()
602 Log.Info(Globals.LogTag, "Calling UnSetSettingChangedCallback");
603 int ret = Interop.LocatorEvent.UnSetSettingChangedCallback((int)_locationType);
604 if (((LocationError)ret != LocationError.None))
606 Log.Error(Globals.LogTag, "Error in Unsetting Setting's Callback," + (LocationError)ret);
607 LocationErrorFactory.ThrowLocationException(ret);
611 private void SettingChangedCallback(LocationType method, bool enable, IntPtr userData)
613 Log.Info(Globals.LogTag, "Calling SettingChangedCallback");
614 _settingChanged?.Invoke(this, new SettingChangedEventArgs(method, enable));
618 /// (event) DistanceBasedLocationChanged is raised with updated location information.
619 /// The callback will be invoked at minimum interval or minimum distance with updated position information.
621 public event EventHandler<LocationChangedEventArgs> DistanceBasedLocationChanged
625 Log.Info(Globals.LogTag, "Adding DistanceBasedLocationChanged EventHandler");
626 if (_distanceBasedLocationChanged == null)
628 Log.Info(Globals.LogTag, "Calling function SetDistanceBasedLocationChangedCallback");
629 SetDistanceBasedLocationChangedCallback();
631 _distanceBasedLocationChanged += value;
635 Log.Info(Globals.LogTag, "Removing DistanceBasedLocationChanged EventHandler");
636 _distanceBasedLocationChanged -= value;
638 if (_distanceBasedLocationChanged == null)
640 Log.Info(Globals.LogTag, "Calling function UnSetDistanceBasedLocationChangedCallback");
641 UnSetDistanceBasedLocationChangedCallback();
646 private void SetDistanceBasedLocationChangedCallback()
648 Log.Info(Globals.LogTag, "SetDistanceBasedLocationChangedCallback");
649 int ret = Interop.LocatorEvent.SetDistanceBasedLocationChangedCallback(_handle, DistanceBasedLocationChangedCallback, _stayInterval, _distance, IntPtr.Zero);
650 if (((LocationError)ret != LocationError.None))
652 Log.Error(Globals.LogTag, "Error in Setting Distance based location changed Callback," + (LocationError)ret);
653 LocationErrorFactory.ThrowLocationException(ret);
657 private void UnSetDistanceBasedLocationChangedCallback()
659 Log.Info(Globals.LogTag, "UnSetDistanceBasedLocationChangedCallback");
660 int ret = Interop.LocatorEvent.UnSetDistanceBasedLocationChangedCallback(_handle);
661 if (((LocationError)ret != LocationError.None))
663 Log.Error(Globals.LogTag, "Error in UnSetting Distance based location changed Callback," + (LocationError)ret);
664 LocationErrorFactory.ThrowLocationException(ret);
668 private void DistanceBasedLocationChangedCallback(double latitude, double longitude, double altitude, double speed, double direction, double horizontalAccuracy, int timestamp, IntPtr userData)
670 Log.Info(Globals.LogTag, "DistanceBasedLocationChangedCallback");
671 Location location = new Location(latitude, longitude, altitude, horizontalAccuracy, direction, speed, timestamp);
672 _distanceBasedLocationChanged?.Invoke(this, new LocationChangedEventArgs(location));
676 /// (event)LocationUpdated is raised at defined intervals of time with updated location information.
677 /// The callback will be invoked periodically.
679 public event EventHandler<LocationChangedEventArgs> LocationChanged
683 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
684 if (_locationChanged == null)
686 Log.Info(Globals.LogTag, "Calling function SetLocationChangedCallback");
687 SetLocationChangedCallback();
689 _locationChanged += value;
693 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
694 _locationChanged -= value;
696 if (_locationChanged == null)
698 Log.Info(Globals.LogTag, "calling function UnSetLocationChangedCallback");
699 UnSetLocationChangedCallback();
704 private void SetLocationChangedCallback()
706 Log.Info(Globals.LogTag, "Calling SetLocationChangedCallback");
707 int ret = Interop.LocatorEvent.SetLocationChangedCallback(_handle, LocationChangedCallback, _interval, IntPtr.Zero);
708 if (((LocationError)ret != LocationError.None))
710 Log.Error(Globals.LogTag, "Error in Setting location changed Callback," + (LocationError)ret);
711 LocationErrorFactory.ThrowLocationException(ret);
715 private void UnSetLocationChangedCallback()
717 Log.Info(Globals.LogTag, "Calling UnSetLocationChangedCallback");
718 int ret = Interop.LocatorEvent.UnSetLocationChangedCallback(_handle);
719 if (((LocationError)ret != LocationError.None))
721 Log.Error(Globals.LogTag, "Error in UnSetting location changed Callback," + (LocationError)ret);
722 LocationErrorFactory.ThrowLocationException(ret);
726 private void LocationChangedCallback(double latitude, double longitude, double altitude, double speed, double direction, double horizontalAccuracy, int timestamp, IntPtr userData)
728 Log.Info(Globals.LogTag, "LocationChangedCallback has been called");
729 Location location = new Location(latitude, longitude, altitude, horizontalAccuracy, direction, speed, timestamp);
730 _location = location;
731 _locationChanged?.Invoke(this, new LocationChangedEventArgs(location));