Geolocation.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using System;
  2. using System.Threading.Tasks;
  3. using System.Linq;
  4. using Xamarin.Forms;
  5. using Xamarin.Essentials;
  6. namespace InABox.Mobile
  7. {
  8. public class LocationServices
  9. {
  10. public delegate void LocationEvent(LocationServices sender);
  11. public event LocationEvent OnLocationFound;
  12. public delegate void LocationError(LocationServices sender, Exception error);
  13. public event LocationError OnLocationError;
  14. public TimeSpan ScanDelay { get; set; }
  15. public double Latitude { get; private set; }
  16. public double Longitude { get; private set; }
  17. public String Address { get; private set; }
  18. private bool bLocating = false;
  19. public DateTime TimeStamp { get; private set; }
  20. public LocationServices() : base()
  21. {
  22. TimeStamp = DateTime.MinValue;
  23. ScanDelay = new TimeSpan(0, 0, 0);
  24. Address = "Searching for GPS";
  25. }
  26. public bool RecentlyLocated
  27. {
  28. get
  29. {
  30. return (DateTime.Now.Subtract(TimeStamp).Ticks < ScanDelay.Ticks);
  31. }
  32. }
  33. private double DistanceBetween(double sLatitude, double sLongitude, double eLatitude,
  34. double eLongitude)
  35. {
  36. var radiansOverDegrees = (Math.PI / 180.0);
  37. var sLatitudeRadians = sLatitude * radiansOverDegrees;
  38. var sLongitudeRadians = sLongitude * radiansOverDegrees;
  39. var eLatitudeRadians = eLatitude * radiansOverDegrees;
  40. var eLongitudeRadians = eLongitude * radiansOverDegrees;
  41. var dLongitude = eLongitudeRadians - sLongitudeRadians;
  42. var dLatitude = eLatitudeRadians - sLatitudeRadians;
  43. var result1 = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) +
  44. Math.Cos(sLatitudeRadians) * Math.Cos(eLatitudeRadians) *
  45. Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
  46. // Using 3956 as the number of miles around the earth
  47. var result2 = 3956.0 * 2.0 *
  48. Math.Atan2(Math.Sqrt(result1), Math.Sqrt(1.0 - result1));
  49. return result2;
  50. }
  51. public void GetLocation(bool skiprecentlylocated = false)
  52. {
  53. if (bLocating || RecentlyLocated)
  54. {
  55. if (!skiprecentlylocated)
  56. return;
  57. }
  58. bLocating = true;
  59. // Don't reset this on every refresh, otherwise the final UI will randomly get "Searching for GPS" as the address
  60. //Address = "Searching for GPS";
  61. bool bOK = MobileUtils.IsPermitted<Permissions.LocationWhenInUse>().Result;
  62. Task.Run(async () =>
  63. {
  64. try
  65. {
  66. if (!bOK)
  67. {
  68. Latitude = 0.0F;
  69. Longitude = 0.0F;
  70. TimeStamp = DateTime.MinValue;
  71. Address = "GPS Services Disabled";
  72. Device.BeginInvokeOnMainThread(() =>
  73. {
  74. OnLocationError?.Invoke(this, new Exception("Please enable GPS Services to continue"));
  75. });
  76. bOK = false;
  77. bLocating = false;
  78. }
  79. else
  80. {
  81. try
  82. {
  83. var request = new GeolocationRequest(GeolocationAccuracy.Best, new TimeSpan(0, 0, 20));
  84. var location = await Geolocation.GetLocationAsync(request);
  85. if (location != null)
  86. {
  87. //if (location.IsFromMockProvider)
  88. //{
  89. // Device.BeginInvokeOnMainThread(() =>
  90. // {
  91. // OnLocationError?.Invoke(this, new Exception("Mock GPS Location Detected!\nPlease correct and restart TimeBench."));
  92. // });
  93. //}
  94. //else
  95. {
  96. Latitude = location.Latitude;
  97. Longitude = location.Longitude;
  98. TimeStamp = DateTime.Now;
  99. String sErr = "";
  100. Placemark address = null;
  101. try
  102. {
  103. var addresses = await Geocoding.GetPlacemarksAsync(Latitude, Longitude);
  104. double maxdist = double.MaxValue;
  105. foreach (var cur in addresses.Where(x => !String.IsNullOrEmpty(x.Thoroughfare)))
  106. {
  107. var delta = Location.CalculateDistance(location, cur.Location, DistanceUnits.Kilometers);
  108. if (delta < maxdist)
  109. {
  110. address = cur;
  111. maxdist = delta;
  112. }
  113. }
  114. }
  115. catch (Exception ee2)
  116. {
  117. sErr = ee2.Message;
  118. //address = null;
  119. }
  120. if (address != null)
  121. Address = String.Format("{0} {1} {2}", address.SubThoroughfare, address.Thoroughfare, address.Locality);
  122. else
  123. Address = String.Format("Lat: {0}, Lng: {1}", Latitude, Longitude);
  124. if (location.IsFromMockProvider)
  125. Address = "** " + Address;
  126. if (!String.IsNullOrEmpty(sErr))
  127. Address = String.Format("{0} (ERROR: {1})", Address, sErr);
  128. Device.BeginInvokeOnMainThread(() =>
  129. {
  130. OnLocationFound?.Invoke(this);
  131. });
  132. bLocating = false;
  133. }
  134. }
  135. else
  136. {
  137. Latitude = 0.00;
  138. Longitude = 0.00;
  139. TimeStamp = DateTime.MinValue;
  140. bLocating = false;
  141. Device.BeginInvokeOnMainThread(() =>
  142. {
  143. OnLocationError?.Invoke(this, new Exception("Unable to get GPS Location"));
  144. });
  145. }
  146. }
  147. catch (Exception e)
  148. {
  149. bLocating = false;
  150. Device.BeginInvokeOnMainThread(() =>
  151. {
  152. OnLocationError?.Invoke(this, e);
  153. });
  154. }
  155. }
  156. }
  157. catch (Exception e)
  158. {
  159. }
  160. bLocating = false;
  161. });
  162. }
  163. }
  164. }