2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections.Generic;
19 using System.Threading.Tasks;
20 using Tizen.Internals.Errors;
21 using System.Runtime.InteropServices;
23 namespace Tizen.Location
25 static internal class Globals
27 internal const string LogTag = "Tizen.Location";
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.
35 public class Locator:IDisposable
37 private int _interval = 1;
38 private int _stayInterval = 120;
39 private double _distance = 120.0;
40 private bool _isEnableMock;
41 private IntPtr _handle;
42 private LocationType _locationType;
43 private Location _location = null;
44 private bool _disposed = false;
45 private bool _isStarted = false;
46 private static Locator s_locatorReference;
47 private int _requestId = 0;
48 private Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback> _callback_map = new Dictionary<IntPtr, Interop.LocatorEvent.LocationUpdatedCallback>();
50 private EventHandler<ZoneChangedEventArgs> _zoneChanged;
51 private EventHandler<ServiceStateChangedEventArgs> _serviceStateChanged;
52 private EventHandler<SettingChangedEventArgs> _settingChanged;
53 private EventHandler<LocationChangedEventArgs> _distanceBasedLocationChanged;
54 private EventHandler<LocationChangedEventArgs> _locationChanged;
57 /// The constructor of Locator class.
59 /// <param name="locationType"> The back-end positioning method to be used for LBS.</param>
60 public Locator(LocationType locationType)
62 Log.Info(Globals.LogTag, "Locator Constructor");
63 int ret = Interop.Locator.Create((int)locationType, out _handle);
64 if (((LocationError)ret != LocationError.None))
66 Log.Error(Globals.LogTag, "Error creating Location Manager," + (LocationError)ret);
67 LocationErrorFactory.ThrowLocationException(ret);
69 _location = new Location();
70 _locationType = locationType;
74 /// The destructor of Locator class.
82 /// The time interval between callback updates.
83 /// Should be in the range [1~120] seconds.
89 Log.Info(Globals.LogTag, "Getting the Callback Interval");
94 Log.Info(Globals.LogTag, "Setting the Callback Interval");
95 if (value > 0 && value <= 120)
98 if (_locationChanged != null)
100 SetLocationChangedCallback();
105 Log.Error(Globals.LogTag, "Error setting Callback Interval");
106 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
112 /// The time interval between Distance based location callback updates.
113 /// Should be in the range [1~120] seconds.
115 public int StayInterval
119 Log.Info(Globals.LogTag, "Getting the StayInterval");
120 return _stayInterval;
124 Log.Info(Globals.LogTag, "Setting the StayInterval");
125 if (value > 0 && value <= 120)
127 _stayInterval = value;
128 if (_distanceBasedLocationChanged != null)
130 SetDistanceBasedLocationChangedCallback();
135 Log.Error(Globals.LogTag, "Error Setting the StayInterval");
136 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
142 /// The distance between callback updates.
143 /// Should be in the range [1-120] meters.
145 public double Distance
149 Log.Info(Globals.LogTag, "Getting the Distance Interval");
154 Log.Info(Globals.LogTag, "Setting the Distance Interval");
155 if (value > 0 && value <= 120)
158 if (_distanceBasedLocationChanged != null)
160 SetDistanceBasedLocationChangedCallback();
165 Log.Error(Globals.LogTag, "Error Setting the Distance");
166 LocationErrorFactory.ThrowLocationException((int)LocationError.InvalidParameter);
172 /// Gets the Location object.
174 public Location Location
178 Log.Info(Globals.LogTag, "Getting location details");
184 /// Gets the type used to obtain Location data.
186 public LocationType LocationType
190 Log.Info(Globals.LogTag, "Getting LocationType");
191 return _locationType;
196 /// Gets the status whether mock location is enabled or not.
198 public bool EnableMock
202 Log.Info(Globals.LogTag, "Getting getting Mock");
203 return _isEnableMock;
207 _isEnableMock = value;
212 internal IntPtr GetHandle()
217 private void SetEnableMock()
219 int ret = Interop.Locator.EnableMock(_isEnableMock);
220 if (((LocationError)ret != LocationError.None))
222 Log.Error(Globals.LogTag, "Error Set Enable Mock Type," + (LocationError)ret);
223 LocationErrorFactory.ThrowLocationException(ret);
228 /// Starts the Location Manager which has been created using the specified method.
232 Log.Info(Globals.LogTag, "Starting Location Manager");
233 if (Locator.s_locatorReference == null)
235 int ret = Interop.Locator.Start(_handle);
236 if (((LocationError)ret != LocationError.None))
238 Log.Error(Globals.LogTag, "Error Starting Location Manager," + (LocationError)ret);
239 LocationErrorFactory.ThrowLocationException(ret);
241 Locator.s_locatorReference = this;
243 Log.Info(Globals.LogTag, "Locator reference set");
247 Log.Error(Globals.LogTag, "Error, previous instance of Locator should be stopped before starting a new one," + LocationError.NotSupported);
248 LocationErrorFactory.ThrowLocationException((int)LocationError.NotSupported);
253 /// Stops the Location Manager which has been activated using the specified method.
254 /// Does not destroy the manager.
258 Log.Info(Globals.LogTag, "Stopping Location Manager");
259 int ret = Interop.Locator.Stop(_handle);
260 if (((LocationError)ret != LocationError.None))
262 Log.Error(Globals.LogTag, "Error stopping Location Manager," + (LocationError)ret);
263 LocationErrorFactory.ThrowLocationException(ret);
265 Locator.s_locatorReference = null;
270 /// Sets a mock location for the given location method.
272 /// <param name="location"> The location object containing the mock location details.</param>
273 public void SetMockLocation(Location location)
275 Log.Info(Globals.LogTag, "Setting mock location");
276 int ret = Interop.Locator.SetMockLocation(_handle, location.Latitude, location.Longitude, location.Altitude, location.Speed, location.Direction, location.HorizontalAccuracy);
277 if (((LocationError)ret == LocationError.None))
279 _location.Altitude = 0;
280 _location.Latitude = location.Latitude;
281 _location.Longitude = location.Longitude;
282 _location.Speed = location.Speed;
283 _location.Direction = location.Direction;
284 _location.HorizontalAccuracy = location.HorizontalAccuracy;
288 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
289 LocationErrorFactory.ThrowLocationException(ret);
294 /// Clears a mock location for the given location method.
296 public void ClearMock()
298 Log.Info(Globals.LogTag, "Clear mock location");
299 int ret = Interop.Locator.ClearMock(_handle);
300 if (((LocationError)ret != LocationError.None))
302 Log.Error(Globals.LogTag, "Error in clear up location mocking," + (LocationError)ret);
303 LocationErrorFactory.ThrowLocationException(ret);
308 /// Gets the details of the location asynchronously.
310 /// <param name="timeout"> Timeout to stop requesting single location after(seconds).</param>
311 /// <returns> A task which contains the current location details</returns>
312 public Task<Location> GetLocationAsync(int timeout)
314 var task = new TaskCompletionSource<Location>();
315 IntPtr id = IntPtr.Zero;
318 id = (IntPtr)_requestId++;
319 _callback_map[id] = (LocationError error, double latitude, double longitude, double altitude, int timestamp, double speed, double direction, double climb, IntPtr userData) =>
321 if (error != LocationError.None)
323 Log.Error(Globals.LogTag, "Error in getting up location information," + (LocationError)error);
327 Log.Info(Globals.LogTag, "Creating a current location object");
328 _location = new Location(latitude, longitude, altitude, 0.0, direction, speed, timestamp);
329 task.SetResult(_location);
333 _callback_map.Remove(userData);
338 int ret = Interop.LocatorEvent.GetSingleLocation(_handle, timeout, _callback_map[id], id);
339 if (((LocationError)ret != LocationError.None))
341 Log.Error(Globals.LogTag, "Error in setting up location mocking," + (LocationError)ret);
342 LocationErrorFactory.ThrowLocationException(ret);
349 /// Gets the details of the location.
351 /// <returns> which contains the current location details</returns>
352 public Location GetLocation()
356 double longitude = 0;
358 double direction = 0;
360 LocationAccuracy level = LocationAccuracy.None;
361 double horizontal = 0;
367 Log.Info(Globals.LogTag, "Get current location information");
368 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);
369 if (((LocationError)ret != LocationError.None))
371 Log.Error(Globals.LogTag, "Error in get current location infomation," + (LocationError)ret);
372 LocationErrorFactory.ThrowLocationException(ret);
377 Log.Info(Globals.LogTag, "Get last location information");
378 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);
379 if (((LocationError)ret != LocationError.None))
381 Log.Error(Globals.LogTag, "Error in get last location information," + (LocationError)ret);
382 LocationErrorFactory.ThrowLocationException(ret);
386 Location location = new Location(latitude, longitude, altitude, horizontal, direction, speed, timestamp);
387 _location = location;
394 /// Adds a bounds for a given locator.
396 /// <param name="locationBoundary"> The boundary object to be added to the locator.</param>
397 public void AddBoundary(LocationBoundary locationBoundary)
399 Log.Info(Globals.LogTag, "AddBoundary called");
401 int ret = Interop.Locator.AddBoundary(_handle, locationBoundary.GetHandle());
402 if ((LocationBoundError)ret != LocationBoundError.None)
404 Log.Error(Globals.LogTag, "Error Adding Boundary," + (LocationBoundError)ret);
405 LocationErrorFactory.ThrowLocationBoundaryException(ret);
410 /// Deletes a bounds for a given locator.
412 /// <param name="locationBoundary"> The boundary object to be removed from the locator.</param>
413 public void RemoveBoundary(LocationBoundary locationBoundary)
415 Log.Info(Globals.LogTag, "RemoveBoundary called");
416 int ret = Interop.Locator.RemoveBoundary(_handle, locationBoundary.GetHandle());
417 if ((LocationBoundError)ret != LocationBoundError.None)
419 Log.Error(Globals.LogTag, "Error Removing Boundary," + (LocationBoundError)ret);
420 LocationErrorFactory.ThrowLocationBoundaryException(ret);
425 /// The overidden Dispose method of the IDisposable class.
427 public void Dispose()
430 GC.SuppressFinalize(this);
433 protected virtual void Dispose(bool disposing)
442 private void DestroyHandle()
444 int ret = Interop.Locator.Destroy(_handle);
445 if (((LocationError)ret != LocationError.None))
447 Log.Error(Globals.LogTag, "Error in Destroy handle" + (LocationError)ret);
448 LocationErrorFactory.ThrowLocationException(ret);
453 /// (event) ServiceStateChanged Event is invoked when the location service state is changed.
455 public event EventHandler<ServiceStateChangedEventArgs> ServiceStateChanged
459 Log.Info(Globals.LogTag, "ServiceStateChanged called");
460 if (_serviceStateChanged == null)
462 Log.Info(Globals.LogTag, "Calling function SetServiceStateChangedCallback");
463 SetServiceStateChangedCallback();
465 _serviceStateChanged += value;
469 Log.Info(Globals.LogTag, "Callback removed");
470 _serviceStateChanged -= value;
472 if (_serviceStateChanged == null)
474 Log.Info(Globals.LogTag, "Calling function UnSetServiceStateChangedCallback");
475 UnSetServiceStateChangedCallback();
480 private void SetServiceStateChangedCallback()
482 Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.SetServiceStateChangedCallback");
483 int ret = Interop.LocatorEvent.SetServiceStateChangedCallback(_handle, ServiceStateChangedCallback, IntPtr.Zero);
484 if (((LocationError)ret != LocationError.None))
486 Log.Error(Globals.LogTag, "Error in Setting Service State Changed Callback," + (LocationError)ret);
487 LocationErrorFactory.ThrowLocationException(ret);
491 private void UnSetServiceStateChangedCallback()
493 Log.Info(Globals.LogTag, "Calling Interop.LocatorEvent.UnSetServiceStateChangedCallback");
494 int ret = Interop.LocatorEvent.UnSetServiceStateChangedCallback(_handle);
495 if (((LocationError)ret != LocationError.None))
497 Log.Error(Globals.LogTag, "Error in UnSetting Service State Changed Callback," + (LocationError)ret);
498 LocationErrorFactory.ThrowLocationException(ret);
502 private void ServiceStateChangedCallback(ServiceState state, IntPtr userData)
504 Log.Info(Globals.LogTag, "Inside ServiceStateChangedCallback");
505 _serviceStateChanged?.Invoke(this, new ServiceStateChangedEventArgs(state));
509 /// (event) ZoneChanged is invoked when the previously set boundary area is entered or left.
511 public event EventHandler<ZoneChangedEventArgs> ZoneChanged
515 Log.Info(Globals.LogTag, "ZoneChanged called");
516 if (_zoneChanged == null)
518 Log.Info(Globals.LogTag, "Calling function SetZoneChangedCallback");
519 SetZoneChangedCallback();
521 _zoneChanged += value;
525 Log.Info(Globals.LogTag, "Callback removed");
526 _zoneChanged -= value;
528 if (_zoneChanged == null)
530 Log.Info(Globals.LogTag, "Calling function UnSetZoneChangedCallback");
531 UnSetZoneChangedCallback();
536 private void SetZoneChangedCallback()
538 Log.Info(Globals.LogTag, "Inside SetZoneChangedCallback");
539 int ret = Interop.LocatorEvent.SetZoneChangedCallback(_handle, ZoneChangedCallback, IntPtr.Zero);
540 if (((LocationError)ret != LocationError.None))
542 Log.Error(Globals.LogTag, "Error in Setting Zone Changed Callback," + (LocationError)ret);
543 LocationErrorFactory.ThrowLocationException(ret);
547 private void UnSetZoneChangedCallback()
549 Log.Info(Globals.LogTag, "Inside UnSetZoneChangedCallback");
550 int ret = Interop.LocatorEvent.UnSetZoneChangedCallback(_handle);
551 if (((LocationError)ret != LocationError.None))
553 Log.Error(Globals.LogTag, "Error in UnSetting Zone Changed Callback," + (LocationError)ret);
557 private void ZoneChangedCallback(BoundaryState state, double latitude, double longitude, double altitude, int timestamp, IntPtr userData)
559 Log.Info(Globals.LogTag, "Inside ZoneChangedCallback");
560 DateTime timeStamp = DateTime.Now;
563 DateTime start = DateTime.SpecifyKind(new DateTime(1970, 1, 1).AddSeconds(timestamp), DateTimeKind.Utc);
564 timeStamp = start.ToLocalTime();
566 _zoneChanged?.Invoke(this, new ZoneChangedEventArgs(state, latitude, longitude, altitude, timeStamp));
570 /// (event) SetttingChanged is raised when the location setting is changed.
572 public event EventHandler<SettingChangedEventArgs> SettingChanged
576 Log.Info(Globals.LogTag, "Adding SettingChanged EventHandler");
577 if (_settingChanged == null)
579 Log.Info(Globals.LogTag, "Calling function SetSettingChangedCallback");
580 SetSettingChangedCallback();
582 _settingChanged += value;
586 Log.Info(Globals.LogTag, "Removing SettingChanged EventHandler");
587 _settingChanged -= value;
589 if (_settingChanged == null)
591 Log.Info(Globals.LogTag, "Calling function UnSetSettingChangedCallback");
592 UnSetSettingChangedCallback();
597 private void SetSettingChangedCallback()
599 Log.Info(Globals.LogTag, "Calling SetSettingChangedCallback");
600 int ret = Interop.LocatorEvent.SetSettingChangedCallback((int)_locationType, SettingChangedCallback, IntPtr.Zero);
601 if (((LocationError)ret != LocationError.None))
603 Log.Error(Globals.LogTag, "Error in Setting Changed Callback," + (LocationError)ret);
604 LocationErrorFactory.ThrowLocationException(ret);
608 private void UnSetSettingChangedCallback()
610 Log.Info(Globals.LogTag, "Calling UnSetSettingChangedCallback");
611 int ret = Interop.LocatorEvent.UnSetSettingChangedCallback((int)_locationType);
612 if (((LocationError)ret != LocationError.None))
614 Log.Error(Globals.LogTag, "Error in Unsetting Setting's Callback," + (LocationError)ret);
615 LocationErrorFactory.ThrowLocationException(ret);
619 private void SettingChangedCallback(LocationType method, bool enable, IntPtr userData)
621 Log.Info(Globals.LogTag, "Calling SettingChangedCallback");
622 _settingChanged?.Invoke(this, new SettingChangedEventArgs(method, enable));
626 /// (event) DistanceBasedLocationChanged is raised with updated location information.
627 /// The callback will be invoked at minimum interval or minimum distance with updated position information.
629 public event EventHandler<LocationChangedEventArgs> DistanceBasedLocationChanged
633 Log.Info(Globals.LogTag, "Adding DistanceBasedLocationChanged EventHandler");
634 if (_distanceBasedLocationChanged == null)
636 Log.Info(Globals.LogTag, "Calling function SetDistanceBasedLocationChangedCallback");
637 SetDistanceBasedLocationChangedCallback();
639 _distanceBasedLocationChanged += value;
643 Log.Info(Globals.LogTag, "Removing DistanceBasedLocationChanged EventHandler");
644 _distanceBasedLocationChanged -= value;
646 if (_distanceBasedLocationChanged == null)
648 Log.Info(Globals.LogTag, "Calling function UnSetDistanceBasedLocationChangedCallback");
649 UnSetDistanceBasedLocationChangedCallback();
654 private void SetDistanceBasedLocationChangedCallback()
656 Log.Info(Globals.LogTag, "SetDistanceBasedLocationChangedCallback");
657 int ret = Interop.LocatorEvent.SetDistanceBasedLocationChangedCallback(_handle, DistanceBasedLocationChangedCallback, _stayInterval, _distance, IntPtr.Zero);
658 if (((LocationError)ret != LocationError.None))
660 Log.Error(Globals.LogTag, "Error in Setting Distance based location changed Callback," + (LocationError)ret);
661 LocationErrorFactory.ThrowLocationException(ret);
665 private void UnSetDistanceBasedLocationChangedCallback()
667 Log.Info(Globals.LogTag, "UnSetDistanceBasedLocationChangedCallback");
668 int ret = Interop.LocatorEvent.UnSetDistanceBasedLocationChangedCallback(_handle);
669 if (((LocationError)ret != LocationError.None))
671 Log.Error(Globals.LogTag, "Error in UnSetting Distance based location changed Callback," + (LocationError)ret);
672 LocationErrorFactory.ThrowLocationException(ret);
676 private void DistanceBasedLocationChangedCallback(double latitude, double longitude, double altitude, double speed, double direction, double horizontalAccuracy, int timestamp, IntPtr userData)
678 Log.Info(Globals.LogTag, "DistanceBasedLocationChangedCallback");
679 Location location = new Location(latitude, longitude, altitude, horizontalAccuracy, direction, speed, timestamp);
680 _distanceBasedLocationChanged?.Invoke(this, new LocationChangedEventArgs(location));
684 /// (event)LocationUpdated is raised at defined intervals of time with updated location information.
685 /// The callback will be invoked periodically.
687 public event EventHandler<LocationChangedEventArgs> LocationChanged
691 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
692 if (_locationChanged == null)
694 Log.Info(Globals.LogTag, "Calling function SetLocationChangedCallback");
695 SetLocationChangedCallback();
697 _locationChanged += value;
701 Log.Info(Globals.LogTag, "Adding LocationChanged EventHandler");
702 _locationChanged -= value;
704 if (_locationChanged == null)
706 Log.Info(Globals.LogTag, "calling function UnSetLocationChangedCallback");
707 UnSetLocationChangedCallback();
712 private void SetLocationChangedCallback()
714 Log.Info(Globals.LogTag, "Calling SetLocationChangedCallback");
715 int ret = Interop.LocatorEvent.SetLocationChangedCallback(_handle, LocationChangedCallback, _interval, IntPtr.Zero);
716 if (((LocationError)ret != LocationError.None))
718 Log.Error(Globals.LogTag, "Error in Setting location changed Callback," + (LocationError)ret);
719 LocationErrorFactory.ThrowLocationException(ret);
723 private void UnSetLocationChangedCallback()
725 Log.Info(Globals.LogTag, "Calling UnSetLocationChangedCallback");
726 int ret = Interop.LocatorEvent.UnSetLocationChangedCallback(_handle);
727 if (((LocationError)ret != LocationError.None))
729 Log.Error(Globals.LogTag, "Error in UnSetting location changed Callback," + (LocationError)ret);
730 LocationErrorFactory.ThrowLocationException(ret);
734 private void LocationChangedCallback(double latitude, double longitude, double altitude, double speed, double direction, double horizontalAccuracy, int timestamp, IntPtr userData)
736 Log.Info(Globals.LogTag, "LocationChangedCallback has been called");
737 Location location = new Location(latitude, longitude, altitude, horizontalAccuracy, direction, speed, timestamp);
738 _location = location;
739 _locationChanged?.Invoke(this, new LocationChangedEventArgs(location));