react-native-nitro-geolocation 1.1.4 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/README.md +97 -9
  2. package/android/build.gradle +6 -0
  3. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidAccuracy.kt +105 -0
  4. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidHeadingManager.kt +313 -0
  5. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidLocationSettings.kt +313 -0
  6. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt +46 -45
  7. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/LocationMetadata.kt +26 -0
  8. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/LocationValues.kt +31 -0
  9. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocation.kt +1027 -140
  10. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocationCompat.kt +11 -11
  11. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/RequestAuthorization.kt +6 -6
  12. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt +46 -45
  13. package/ios/CLLocation+GeolocationMetadata.swift +32 -0
  14. package/ios/LocationManager.swift +205 -51
  15. package/ios/NitroGeolocation.swift +949 -110
  16. package/ios/NitroGeolocationCompat.swift +7 -7
  17. package/nitrogen/generated/android/c++/JAccuracyAuthorization.hpp +61 -0
  18. package/nitrogen/generated/android/c++/JAndroidAccuracyPreset.hpp +64 -0
  19. package/nitrogen/generated/android/c++/JAndroidGranularity.hpp +61 -0
  20. package/nitrogen/generated/android/c++/{JRNConfigurationInternal.hpp → JCompatGeolocationConfigurationInternal.hpp} +10 -10
  21. package/nitrogen/generated/android/c++/{JGeolocationError.hpp → JCompatGeolocationError.hpp} +10 -10
  22. package/nitrogen/generated/android/c++/JCompatGeolocationOptions.hpp +105 -0
  23. package/nitrogen/generated/android/c++/JCompatGeolocationResponse.hpp +67 -0
  24. package/nitrogen/generated/android/c++/JFunc_void_AccuracyAuthorization.hpp +77 -0
  25. package/nitrogen/generated/android/c++/JFunc_void_CompatGeolocationError.hpp +78 -0
  26. package/nitrogen/generated/android/c++/JFunc_void_CompatGeolocationResponse.hpp +84 -0
  27. package/nitrogen/generated/android/c++/JFunc_void_GeolocationResponse.hpp +2 -0
  28. package/nitrogen/generated/android/c++/JFunc_void_Heading.hpp +78 -0
  29. package/nitrogen/generated/android/c++/JFunc_void_LocationProviderStatus.hpp +78 -0
  30. package/nitrogen/generated/android/c++/JFunc_void_PermissionStatus.hpp +77 -0
  31. package/nitrogen/generated/android/c++/JFunc_void_std__vector_GeocodedLocation_.hpp +97 -0
  32. package/nitrogen/generated/android/c++/JFunc_void_std__vector_ReverseGeocodedAddress_.hpp +98 -0
  33. package/nitrogen/generated/android/c++/JGeocodedLocation.hpp +65 -0
  34. package/nitrogen/generated/android/c++/JGeocodingCoordinates.hpp +61 -0
  35. package/nitrogen/generated/android/c++/{JModernGeolocationConfiguration.hpp → JGeolocationConfiguration.hpp} +10 -10
  36. package/nitrogen/generated/android/c++/JGeolocationResponse.hpp +13 -3
  37. package/nitrogen/generated/android/c++/JHeading.hpp +69 -0
  38. package/nitrogen/generated/android/c++/JHeadingOptions.hpp +57 -0
  39. package/nitrogen/generated/android/c++/JHybridNitroGeolocationCompatSpec.cpp +46 -30
  40. package/nitrogen/generated/android/c++/JHybridNitroGeolocationCompatSpec.hpp +4 -4
  41. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.cpp +169 -33
  42. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.hpp +14 -3
  43. package/nitrogen/generated/android/c++/JIOSAccuracyPreset.hpp +73 -0
  44. package/nitrogen/generated/android/c++/JIOSActivityType.hpp +67 -0
  45. package/nitrogen/generated/android/c++/JLocationAccuracyOptions.hpp +65 -0
  46. package/nitrogen/generated/android/c++/JLocationAvailability.hpp +62 -0
  47. package/nitrogen/generated/android/c++/JLocationProviderStatus.hpp +77 -0
  48. package/nitrogen/generated/android/c++/JLocationProviderUsed.hpp +67 -0
  49. package/nitrogen/generated/android/c++/JLocationRequestOptions.hpp +49 -3
  50. package/nitrogen/generated/android/c++/{JGeolocationOptions.hpp → JLocationSettingsOptions.hpp} +28 -22
  51. package/nitrogen/generated/android/c++/JReverseGeocodedAddress.hpp +82 -0
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AccuracyAuthorization.kt +24 -0
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidAccuracyPreset.kt +25 -0
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidGranularity.kt +24 -0
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/{RNConfigurationInternal.kt → CompatGeolocationConfigurationInternal.kt} +5 -5
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/{GeolocationError.kt → CompatGeolocationError.kt} +5 -5
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/CompatGeolocationOptions.kt +68 -0
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/CompatGeolocationResponse.kt +41 -0
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_AccuracyAuthorization.kt +80 -0
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/{Func_void_GeolocationError.kt → Func_void_CompatGeolocationError.kt} +9 -9
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_CompatGeolocationResponse.kt +80 -0
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_Heading.kt +80 -0
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_LocationProviderStatus.kt +80 -0
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_PermissionStatus.kt +80 -0
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_std__vector_GeocodedLocation_.kt +80 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_std__vector_ReverseGeocodedAddress_.kt +80 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeocodedLocation.kt +44 -0
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeocodingCoordinates.kt +41 -0
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/{ModernGeolocationConfiguration.kt → GeolocationConfiguration.kt} +5 -5
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationResponse.kt +9 -3
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Heading.kt +47 -0
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HeadingOptions.kt +38 -0
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationCompatSpec.kt +7 -7
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationSpec.kt +92 -3
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/IOSAccuracyPreset.kt +28 -0
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/IOSActivityType.kt +26 -0
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationAccuracyOptions.kt +41 -0
  78. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationAvailability.kt +41 -0
  79. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderStatus.kt +53 -0
  80. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderUsed.kt +26 -0
  81. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationRequestOptions.kt +30 -3
  82. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/{GeolocationOptions.kt → LocationSettingsOptions.kt} +11 -11
  83. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/ReverseGeocodedAddress.kt +56 -0
  84. package/nitrogen/generated/android/nitrogeolocationOnLoad.cpp +18 -4
  85. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.cpp +76 -12
  86. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.hpp +519 -77
  87. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Umbrella.hpp +61 -12
  88. package/nitrogen/generated/ios/c++/HybridNitroGeolocationCompatSpecSwift.hpp +28 -16
  89. package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.hpp +131 -13
  90. package/nitrogen/generated/ios/swift/AccuracyAuthorization.swift +44 -0
  91. package/nitrogen/generated/ios/swift/AndroidAccuracyPreset.swift +48 -0
  92. package/nitrogen/generated/ios/swift/AndroidGranularity.swift +44 -0
  93. package/nitrogen/generated/ios/swift/{RNConfigurationInternal.swift → CompatGeolocationConfigurationInternal.swift} +5 -5
  94. package/nitrogen/generated/ios/swift/{GeolocationError.swift → CompatGeolocationError.swift} +5 -5
  95. package/nitrogen/generated/ios/swift/CompatGeolocationOptions.swift +208 -0
  96. package/nitrogen/generated/ios/swift/CompatGeolocationResponse.swift +34 -0
  97. package/nitrogen/generated/ios/swift/Func_void_AccuracyAuthorization.swift +46 -0
  98. package/nitrogen/generated/ios/swift/Func_void_CompatGeolocationError.swift +46 -0
  99. package/nitrogen/generated/ios/swift/Func_void_CompatGeolocationResponse.swift +46 -0
  100. package/nitrogen/generated/ios/swift/{Func_void_GeolocationError.swift → Func_void_Heading.swift} +11 -11
  101. package/nitrogen/generated/ios/swift/Func_void_LocationAvailability.swift +46 -0
  102. package/nitrogen/generated/ios/swift/Func_void_LocationProviderStatus.swift +46 -0
  103. package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
  104. package/nitrogen/generated/ios/swift/Func_void_std__vector_GeocodedLocation_.swift +46 -0
  105. package/nitrogen/generated/ios/swift/Func_void_std__vector_ReverseGeocodedAddress_.swift +46 -0
  106. package/nitrogen/generated/ios/swift/GeocodedLocation.swift +52 -0
  107. package/nitrogen/generated/ios/swift/GeocodingCoordinates.swift +34 -0
  108. package/nitrogen/generated/ios/swift/{ModernGeolocationConfiguration.swift → GeolocationConfiguration.swift} +5 -5
  109. package/nitrogen/generated/ios/swift/GeolocationResponse.swift +31 -2
  110. package/nitrogen/generated/ios/swift/Heading.swift +70 -0
  111. package/nitrogen/generated/ios/swift/HeadingOptions.swift +42 -0
  112. package/nitrogen/generated/ios/swift/HybridNitroGeolocationCompatSpec.swift +4 -4
  113. package/nitrogen/generated/ios/swift/HybridNitroGeolocationCompatSpec_cxx.swift +28 -28
  114. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec.swift +14 -3
  115. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec_cxx.swift +318 -15
  116. package/nitrogen/generated/ios/swift/IOSAccuracyPreset.swift +60 -0
  117. package/nitrogen/generated/ios/swift/IOSActivityType.swift +52 -0
  118. package/nitrogen/generated/ios/swift/LocationAccuracyOptions.swift +46 -0
  119. package/nitrogen/generated/ios/swift/LocationAvailability.swift +47 -0
  120. package/nitrogen/generated/ios/swift/LocationProviderStatus.swift +106 -0
  121. package/nitrogen/generated/ios/swift/LocationProviderUsed.swift +52 -0
  122. package/nitrogen/generated/ios/swift/LocationRequestOptions.swift +142 -1
  123. package/nitrogen/generated/ios/swift/{GeolocationOptions.swift → LocationSettingsOptions.swift} +39 -46
  124. package/nitrogen/generated/ios/swift/ReverseGeocodedAddress.swift +150 -0
  125. package/nitrogen/generated/shared/c++/AccuracyAuthorization.hpp +80 -0
  126. package/nitrogen/generated/shared/c++/AndroidAccuracyPreset.hpp +84 -0
  127. package/nitrogen/generated/shared/c++/AndroidGranularity.hpp +80 -0
  128. package/nitrogen/generated/shared/c++/{RNConfigurationInternal.hpp → CompatGeolocationConfigurationInternal.hpp} +11 -11
  129. package/nitrogen/generated/shared/c++/{GeolocationError.hpp → CompatGeolocationError.hpp} +11 -11
  130. package/nitrogen/generated/shared/c++/CompatGeolocationOptions.hpp +128 -0
  131. package/nitrogen/generated/shared/c++/CompatGeolocationResponse.hpp +88 -0
  132. package/nitrogen/generated/shared/c++/GeocodedLocation.hpp +91 -0
  133. package/nitrogen/generated/shared/c++/GeocodingCoordinates.hpp +87 -0
  134. package/nitrogen/generated/shared/c++/{ModernGeolocationConfiguration.hpp → GeolocationConfiguration.hpp} +11 -11
  135. package/nitrogen/generated/shared/c++/GeolocationResponse.hpp +14 -2
  136. package/nitrogen/generated/shared/c++/Heading.hpp +95 -0
  137. package/nitrogen/generated/shared/c++/HeadingOptions.hpp +83 -0
  138. package/nitrogen/generated/shared/c++/HybridNitroGeolocationCompatSpec.hpp +16 -16
  139. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.cpp +11 -0
  140. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.hpp +51 -12
  141. package/nitrogen/generated/shared/c++/IOSAccuracyPreset.hpp +96 -0
  142. package/nitrogen/generated/shared/c++/IOSActivityType.hpp +88 -0
  143. package/nitrogen/generated/shared/c++/LocationAccuracyOptions.hpp +92 -0
  144. package/nitrogen/generated/shared/c++/LocationAvailability.hpp +88 -0
  145. package/nitrogen/generated/shared/c++/LocationProviderStatus.hpp +103 -0
  146. package/nitrogen/generated/shared/c++/LocationProviderUsed.hpp +88 -0
  147. package/nitrogen/generated/shared/c++/LocationRequestOptions.hpp +47 -3
  148. package/nitrogen/generated/shared/c++/{GeolocationOptions.hpp → LocationSettingsOptions.hpp} +26 -24
  149. package/nitrogen/generated/shared/c++/ReverseGeocodedAddress.hpp +108 -0
  150. package/package.json +1 -1
  151. package/src/NitroGeolocation.nitro.ts +292 -18
  152. package/src/NitroGeolocationCompat.nitro.ts +12 -12
  153. package/src/api/geocode.ts +18 -0
  154. package/src/api/getAccuracyAuthorization.ts +12 -0
  155. package/src/api/getCurrentPosition.ts +5 -3
  156. package/src/api/getHeading.ts +13 -0
  157. package/src/api/getLastKnownPosition.ts +28 -0
  158. package/src/api/getLocationAvailability.ts +11 -0
  159. package/src/api/getProviderStatus.ts +16 -0
  160. package/src/api/hasServicesEnabled.ts +13 -0
  161. package/src/api/index.ts +11 -0
  162. package/src/api/requestLocationSettings.ts +29 -0
  163. package/src/api/requestPermission.ts +3 -1
  164. package/src/api/requestTemporaryFullAccuracy.ts +21 -0
  165. package/src/api/reverseGeocode.ts +23 -0
  166. package/src/api/setConfiguration.ts +8 -4
  167. package/src/api/watchHeading.ts +19 -0
  168. package/src/api/watchPosition.ts +2 -2
  169. package/src/compat/getCurrentPosition.ts +7 -7
  170. package/src/compat/index.tsx +5 -5
  171. package/src/compat/requestAuthorization.ts +2 -2
  172. package/src/compat/setRNConfiguration.ts +7 -5
  173. package/src/compat/watchPosition.ts +7 -7
  174. package/src/devtools/getCurrentPosition.ts +5 -3
  175. package/src/devtools/index.ts +1 -1
  176. package/src/devtools/watchPosition.ts +6 -7
  177. package/src/hooks/useWatchPosition.ts +2 -2
  178. package/src/index.tsx +35 -6
  179. package/src/publicTypes.ts +108 -0
  180. package/src/types.ts +113 -37
  181. package/src/utils/errors.test.ts +65 -0
  182. package/src/utils/errors.ts +45 -18
  183. package/src/utils/index.ts +2 -2
  184. package/src/utils/provider.test.ts +172 -1
  185. package/src/utils/provider.ts +50 -5
  186. package/nitrogen/generated/android/c++/JFunc_void_GeolocationError.hpp +0 -78
@@ -0,0 +1,313 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.Manifest
4
+ import android.app.Activity
5
+ import android.content.Context
6
+ import android.content.Intent
7
+ import android.content.IntentSender
8
+ import android.content.pm.PackageManager
9
+ import android.location.LocationManager as AndroidLocationManager
10
+ import android.os.Build
11
+ import android.os.Handler
12
+ import android.os.Looper
13
+ import androidx.core.content.ContextCompat
14
+ import com.facebook.react.bridge.BaseActivityEventListener
15
+ import com.facebook.react.bridge.ReactApplicationContext
16
+ import com.google.android.gms.common.ConnectionResult
17
+ import com.google.android.gms.common.GoogleApiAvailability
18
+ import com.google.android.gms.common.api.ResolvableApiException
19
+ import com.google.android.gms.location.LocationRequest as GmsLocationRequest
20
+ import com.google.android.gms.location.LocationServices
21
+ import com.google.android.gms.location.LocationSettingsRequest
22
+ import com.google.android.gms.location.Priority
23
+ import java.util.concurrent.atomic.AtomicBoolean
24
+
25
+ private const val LOCATION_SETTINGS_REQUEST_CODE = 8948
26
+ private const val GOOGLE_LOCATION_ACCURACY_TIMEOUT_MS = 2_000L
27
+
28
+ internal class AndroidLocationSettings(
29
+ private val reactContext: ReactApplicationContext,
30
+ private val locationManager: AndroidLocationManager,
31
+ private val createLocationError: (Double, String) -> LocationError,
32
+ private val createPlayServicesUnavailableError: () -> LocationError
33
+ ) {
34
+ private data class ParsedSettingsOptions(
35
+ val androidAccuracy: AndroidAccuracyResolution,
36
+ val intervalMillis: Long,
37
+ val fastestIntervalMillis: Long,
38
+ val distanceFilterMeters: Float,
39
+ val alwaysShow: Boolean,
40
+ val needBle: Boolean
41
+ ) {
42
+ companion object {
43
+ private const val DEFAULT_INTERVAL_MS = 5_000.0
44
+ private const val DEFAULT_FASTEST_INTERVAL_MS = 1_000.0
45
+ private const val DEFAULT_DISTANCE_FILTER_METERS = 0.0
46
+
47
+ fun parse(options: LocationSettingsOptions?): ParsedSettingsOptions {
48
+ val enableHighAccuracy = options?.enableHighAccuracy ?: true
49
+ return ParsedSettingsOptions(
50
+ androidAccuracy = resolveAndroidAccuracy(
51
+ options?.accuracy,
52
+ enableHighAccuracy
53
+ ),
54
+ intervalMillis = coercePositiveMillis(
55
+ options?.interval,
56
+ DEFAULT_INTERVAL_MS
57
+ ),
58
+ fastestIntervalMillis = coercePositiveMillis(
59
+ options?.fastestInterval,
60
+ DEFAULT_FASTEST_INTERVAL_MS
61
+ ),
62
+ distanceFilterMeters = (options?.distanceFilter
63
+ ?: DEFAULT_DISTANCE_FILTER_METERS)
64
+ .coerceAtLeast(0.0)
65
+ .toFloat(),
66
+ alwaysShow = options?.alwaysShow ?: true,
67
+ needBle = options?.needBle ?: false
68
+ )
69
+ }
70
+
71
+ private fun coercePositiveMillis(value: Double?, defaultValue: Double): Long {
72
+ val nextValue = value ?: defaultValue
73
+ return when {
74
+ nextValue.isNaN() || nextValue <= 0.0 -> defaultValue.toLong()
75
+ nextValue.isInfinite() || nextValue >= Long.MAX_VALUE.toDouble() -> Long.MAX_VALUE
76
+ else -> nextValue.toLong()
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ private data class PendingLocationSettingsRequest(
83
+ val success: (LocationProviderStatus) -> Unit,
84
+ val error: ((LocationError) -> Unit)?,
85
+ val options: ParsedSettingsOptions
86
+ )
87
+
88
+ private var pendingLocationSettingsRequest: PendingLocationSettingsRequest? = null
89
+ private val mainHandler = Handler(Looper.getMainLooper())
90
+
91
+ private val activityEventListener = object : BaseActivityEventListener() {
92
+ override fun onActivityResult(
93
+ activity: Activity,
94
+ requestCode: Int,
95
+ resultCode: Int,
96
+ data: Intent?
97
+ ) {
98
+ if (requestCode != LOCATION_SETTINGS_REQUEST_CODE) return
99
+
100
+ val pendingRequest = pendingLocationSettingsRequest ?: return
101
+ pendingLocationSettingsRequest = null
102
+
103
+ if (resultCode == Activity.RESULT_OK) {
104
+ checkLocationSettings(pendingRequest, shouldShowResolution = false)
105
+ return
106
+ }
107
+
108
+ pendingRequest.error?.invoke(createLocationError(
109
+ SETTINGS_NOT_SATISFIED,
110
+ "Location settings change was cancelled."
111
+ ))
112
+ }
113
+ }
114
+
115
+ init {
116
+ reactContext.addActivityEventListener(activityEventListener)
117
+ }
118
+
119
+ fun hasServicesEnabled(): Boolean {
120
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
121
+ locationManager.isLocationEnabled
122
+ } else {
123
+ isProviderEnabled(AndroidLocationManager.GPS_PROVIDER) ||
124
+ isProviderEnabled(AndroidLocationManager.NETWORK_PROVIDER)
125
+ }
126
+ }
127
+
128
+ fun getProviderStatus(success: (LocationProviderStatus) -> Unit) {
129
+ getGoogleLocationAccuracyEnabled { googleLocationAccuracyEnabled ->
130
+ success(createProviderStatus(googleLocationAccuracyEnabled))
131
+ }
132
+ }
133
+
134
+ private fun createProviderStatus(
135
+ googleLocationAccuracyEnabled: Boolean?
136
+ ): LocationProviderStatus {
137
+ return LocationProviderStatus(
138
+ locationServicesEnabled = hasServicesEnabled(),
139
+ backgroundModeEnabled = hasBackgroundLocationPermission(),
140
+ gpsAvailable = isProviderEnabled(AndroidLocationManager.GPS_PROVIDER),
141
+ networkAvailable = isProviderEnabled(AndroidLocationManager.NETWORK_PROVIDER),
142
+ passiveAvailable = isProviderEnabled(AndroidLocationManager.PASSIVE_PROVIDER),
143
+ googleLocationAccuracyEnabled = googleLocationAccuracyEnabled
144
+ )
145
+ }
146
+
147
+ fun requestLocationSettings(
148
+ success: (LocationProviderStatus) -> Unit,
149
+ error: ((LocationError) -> Unit)?,
150
+ options: LocationSettingsOptions?
151
+ ) {
152
+ if (!isGooglePlayServicesAvailable()) {
153
+ error?.invoke(createPlayServicesUnavailableError())
154
+ return
155
+ }
156
+
157
+ if (pendingLocationSettingsRequest != null) {
158
+ error?.invoke(createLocationError(
159
+ INTERNAL_ERROR,
160
+ "A location settings request is already in progress."
161
+ ))
162
+ return
163
+ }
164
+
165
+ val pendingRequest = PendingLocationSettingsRequest(
166
+ success = success,
167
+ error = error,
168
+ options = ParsedSettingsOptions.parse(options)
169
+ )
170
+
171
+ checkLocationSettings(pendingRequest, shouldShowResolution = true)
172
+ }
173
+
174
+ private fun checkLocationSettings(
175
+ pendingRequest: PendingLocationSettingsRequest,
176
+ shouldShowResolution: Boolean
177
+ ) {
178
+ val settingsClient = LocationServices.getSettingsClient(reactContext)
179
+ settingsClient
180
+ .checkLocationSettings(buildLocationSettingsRequest(pendingRequest.options))
181
+ .addOnSuccessListener {
182
+ getProviderStatus(pendingRequest.success)
183
+ }
184
+ .addOnFailureListener { exception ->
185
+ if (shouldShowResolution && exception is ResolvableApiException) {
186
+ showResolutionDialog(exception, pendingRequest)
187
+ return@addOnFailureListener
188
+ }
189
+
190
+ pendingRequest.error?.invoke(createLocationError(
191
+ SETTINGS_NOT_SATISFIED,
192
+ "Location settings do not satisfy the requested options."
193
+ ))
194
+ }
195
+ }
196
+
197
+ private fun showResolutionDialog(
198
+ exception: ResolvableApiException,
199
+ pendingRequest: PendingLocationSettingsRequest
200
+ ) {
201
+ val activity = reactContext.currentActivity
202
+ if (activity == null) {
203
+ pendingRequest.error?.invoke(createLocationError(
204
+ INTERNAL_ERROR,
205
+ "No activity available to request location settings."
206
+ ))
207
+ return
208
+ }
209
+
210
+ pendingLocationSettingsRequest = pendingRequest
211
+
212
+ try {
213
+ exception.startResolutionForResult(activity, LOCATION_SETTINGS_REQUEST_CODE)
214
+ } catch (e: IntentSender.SendIntentException) {
215
+ pendingLocationSettingsRequest = null
216
+ pendingRequest.error?.invoke(createLocationError(
217
+ INTERNAL_ERROR,
218
+ "Failed to show location settings dialog: ${e.message}"
219
+ ))
220
+ }
221
+ }
222
+
223
+ private fun buildLocationSettingsRequest(
224
+ options: ParsedSettingsOptions
225
+ ): LocationSettingsRequest {
226
+ val priority = when (options.androidAccuracy.mode) {
227
+ AndroidAccuracyMode.HIGH -> Priority.PRIORITY_HIGH_ACCURACY
228
+ AndroidAccuracyMode.BALANCED -> Priority.PRIORITY_BALANCED_POWER_ACCURACY
229
+ AndroidAccuracyMode.LOW -> Priority.PRIORITY_LOW_POWER
230
+ AndroidAccuracyMode.PASSIVE -> Priority.PRIORITY_PASSIVE
231
+ }
232
+
233
+ val request = GmsLocationRequest
234
+ .Builder(priority, options.intervalMillis)
235
+ .setMinUpdateIntervalMillis(options.fastestIntervalMillis)
236
+ .setMinUpdateDistanceMeters(options.distanceFilterMeters)
237
+ .build()
238
+
239
+ return LocationSettingsRequest
240
+ .Builder()
241
+ .addLocationRequest(request)
242
+ .setAlwaysShow(options.alwaysShow)
243
+ .setNeedBle(options.needBle)
244
+ .build()
245
+ }
246
+
247
+ private fun isProviderEnabled(provider: String): Boolean {
248
+ return try {
249
+ locationManager.isProviderEnabled(provider)
250
+ } catch (e: Exception) {
251
+ false
252
+ }
253
+ }
254
+
255
+ private fun hasBackgroundLocationPermission(): Boolean {
256
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return true
257
+
258
+ return ContextCompat.checkSelfPermission(
259
+ reactContext,
260
+ Manifest.permission.ACCESS_BACKGROUND_LOCATION
261
+ ) == PackageManager.PERMISSION_GRANTED
262
+ }
263
+
264
+ private fun getGoogleLocationAccuracyEnabled(success: (Boolean?) -> Unit) {
265
+ if (!isGooglePlayServicesAvailable()) {
266
+ success(null)
267
+ return
268
+ }
269
+
270
+ val didComplete = AtomicBoolean(false)
271
+ val timeoutRunnable = Runnable {
272
+ if (didComplete.compareAndSet(false, true)) {
273
+ success(null)
274
+ }
275
+ }
276
+
277
+ fun complete(value: Boolean?) {
278
+ if (didComplete.compareAndSet(false, true)) {
279
+ mainHandler.removeCallbacks(timeoutRunnable)
280
+ success(value)
281
+ }
282
+ }
283
+
284
+ mainHandler.postDelayed(timeoutRunnable, GOOGLE_LOCATION_ACCURACY_TIMEOUT_MS)
285
+
286
+ try {
287
+ LocationServices
288
+ .getSettingsClient(reactContext)
289
+ .isGoogleLocationAccuracyEnabled
290
+ .addOnSuccessListener { enabled ->
291
+ complete(enabled)
292
+ }
293
+ .addOnFailureListener {
294
+ complete(null)
295
+ }
296
+ .addOnCanceledListener {
297
+ complete(null)
298
+ }
299
+ } catch (e: Exception) {
300
+ complete(null)
301
+ }
302
+ }
303
+
304
+ private fun isGooglePlayServicesAvailable(): Boolean {
305
+ return GoogleApiAvailability.getInstance()
306
+ .isGooglePlayServicesAvailable(reactContext) == ConnectionResult.SUCCESS
307
+ }
308
+
309
+ private companion object {
310
+ private const val INTERNAL_ERROR = -1.0
311
+ private const val SETTINGS_NOT_SATISFIED = 5.0
312
+ }
313
+ }
@@ -16,9 +16,9 @@ import com.facebook.react.bridge.ReactApplicationContext
16
16
  class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
17
17
 
18
18
  fun execute(
19
- success: (position: GeolocationResponse) -> Unit,
20
- error: ((error: GeolocationError) -> Unit)?,
21
- options: GeolocationOptions?
19
+ success: (position: CompatGeolocationResponse) -> Unit,
20
+ error: ((error: CompatGeolocationError) -> Unit)?,
21
+ options: CompatGeolocationOptions?
22
22
  ) {
23
23
  val locationManager =
24
24
  reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
@@ -29,7 +29,7 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
29
29
  }
30
30
 
31
31
  val opts = parseOptions(options)
32
- val provider = getValidProvider(locationManager, opts.enableHighAccuracy)
32
+ val provider = getValidProvider(locationManager, opts.androidAccuracy)
33
33
 
34
34
  if (provider == null) {
35
35
  Log.e(TAG, "No location provider available")
@@ -64,11 +64,15 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
64
64
 
65
65
  // ===== Helper Functions =====
66
66
 
67
- private fun parseOptions(options: GeolocationOptions?): ParsedOptions {
67
+ private fun parseOptions(options: CompatGeolocationOptions?): ParsedOptions {
68
68
  return ParsedOptions(
69
69
  timeout = options?.timeout ?: DEFAULT_TIMEOUT,
70
70
  maximumAge = options?.maximumAge ?: DEFAULT_MAXIMUM_AGE,
71
- enableHighAccuracy = options?.enableHighAccuracy ?: false
71
+ androidAccuracy =
72
+ resolveAndroidAccuracy(
73
+ options?.accuracy,
74
+ options?.enableHighAccuracy ?: false
75
+ )
72
76
  )
73
77
  }
74
78
 
@@ -77,37 +81,42 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
77
81
  return age < options.maximumAge
78
82
  }
79
83
 
80
- private fun getValidProvider(locationManager: LocationManager, highAccuracy: Boolean): String? {
81
- val preferredProvider =
82
- if (highAccuracy) LocationManager.GPS_PROVIDER else LocationManager.NETWORK_PROVIDER
83
- val fallbackProvider =
84
- if (highAccuracy) LocationManager.NETWORK_PROVIDER else LocationManager.GPS_PROVIDER
85
-
86
- return when {
87
- isProviderValid(locationManager, preferredProvider) -> preferredProvider
88
- isProviderValid(locationManager, fallbackProvider) -> fallbackProvider
89
- else -> null
84
+ private fun getValidProvider(
85
+ locationManager: LocationManager,
86
+ accuracy: AndroidAccuracyResolution
87
+ ): String? {
88
+ return accuracy.providerOrder().firstOrNull { provider ->
89
+ isProviderValid(locationManager, provider)
90
90
  }
91
91
  }
92
92
 
93
93
  private fun isProviderValid(locationManager: LocationManager, provider: String): Boolean {
94
94
  if (!locationManager.isProviderEnabled(provider)) return false
95
95
 
96
- val permission =
97
- if (provider == LocationManager.GPS_PROVIDER)
96
+ val fineGranted =
97
+ ContextCompat.checkSelfPermission(
98
+ reactContext,
98
99
  Manifest.permission.ACCESS_FINE_LOCATION
99
- else Manifest.permission.ACCESS_COARSE_LOCATION
100
-
101
- return ContextCompat.checkSelfPermission(reactContext, permission) ==
102
- PackageManager.PERMISSION_GRANTED
100
+ ) == PackageManager.PERMISSION_GRANTED
101
+ val coarseGranted =
102
+ ContextCompat.checkSelfPermission(
103
+ reactContext,
104
+ Manifest.permission.ACCESS_COARSE_LOCATION
105
+ ) == PackageManager.PERMISSION_GRANTED
106
+
107
+ return if (provider == LocationManager.GPS_PROVIDER) {
108
+ fineGranted
109
+ } else {
110
+ coarseGranted || fineGranted
111
+ }
103
112
  }
104
113
 
105
114
  private fun requestFreshLocation(
106
115
  locationManager: LocationManager,
107
116
  provider: String,
108
117
  options: ParsedOptions,
109
- success: (GeolocationResponse) -> Unit,
110
- error: ((GeolocationError) -> Unit)?,
118
+ success: (CompatGeolocationResponse) -> Unit,
119
+ error: ((CompatGeolocationError) -> Unit)?,
111
120
  fallbackLocation: Location?
112
121
  ) {
113
122
  if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
@@ -138,8 +147,8 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
138
147
  locationManager: LocationManager,
139
148
  provider: String,
140
149
  options: ParsedOptions,
141
- success: (GeolocationResponse) -> Unit,
142
- error: ((GeolocationError) -> Unit)?,
150
+ success: (CompatGeolocationResponse) -> Unit,
151
+ error: ((CompatGeolocationError) -> Unit)?,
143
152
  fallbackLocation: Location?
144
153
  ) {
145
154
  val handler = Handler(Looper.getMainLooper())
@@ -187,8 +196,8 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
187
196
  locationManager: LocationManager,
188
197
  provider: String,
189
198
  options: ParsedOptions,
190
- success: (GeolocationResponse) -> Unit,
191
- error: ((GeolocationError) -> Unit)?,
199
+ success: (CompatGeolocationResponse) -> Unit,
200
+ error: ((CompatGeolocationError) -> Unit)?,
192
201
  fallbackLocation: Location?
193
202
  ) {
194
203
  val handler = Handler(Looper.getMainLooper())
@@ -285,32 +294,24 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
285
294
 
286
295
  // ===== Data Conversion =====
287
296
 
288
- private fun locationToPosition(location: Location): GeolocationResponse {
289
- return GeolocationResponse(
297
+ private fun locationToPosition(location: Location): CompatGeolocationResponse {
298
+ return CompatGeolocationResponse(
290
299
  coords =
291
300
  GeolocationCoordinates(
292
301
  latitude = location.latitude,
293
302
  longitude = location.longitude,
294
- altitude = if (location.hasAltitude()) NullableDouble.create(location.altitude) else null,
303
+ altitude = location.altitudeValue(),
295
304
  accuracy = location.accuracy.toDouble(),
296
- altitudeAccuracy =
297
- if (android.os.Build.VERSION.SDK_INT >=
298
- android.os.Build.VERSION_CODES.O &&
299
- location.hasVerticalAccuracy()
300
- )
301
- NullableDouble.create(location.verticalAccuracyMeters.toDouble())
302
- else null,
303
- heading =
304
- if (location.hasBearing()) NullableDouble.create(location.bearing.toDouble())
305
- else null,
306
- speed = if (location.hasSpeed()) NullableDouble.create(location.speed.toDouble()) else null
305
+ altitudeAccuracy = location.altitudeAccuracyValue(),
306
+ heading = location.headingValue(),
307
+ speed = location.speedValue()
307
308
  ),
308
309
  timestamp = location.time.toDouble()
309
310
  )
310
311
  }
311
312
 
312
- private fun createError(code: Int, message: String): GeolocationError {
313
- return GeolocationError(
313
+ private fun createError(code: Int, message: String): CompatGeolocationError {
314
+ return CompatGeolocationError(
314
315
  code = code.toDouble(),
315
316
  message = message,
316
317
  PERMISSION_DENIED = PERMISSION_DENIED.toDouble(),
@@ -324,7 +325,7 @@ class GetCurrentPosition(private val reactContext: ReactApplicationContext) {
324
325
  private data class ParsedOptions(
325
326
  val timeout: Double,
326
327
  val maximumAge: Double,
327
- val enableHighAccuracy: Boolean
328
+ val androidAccuracy: AndroidAccuracyResolution
328
329
  )
329
330
 
330
331
  companion object {
@@ -0,0 +1,26 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.location.Location
4
+ import android.location.LocationManager
5
+ import android.os.Build
6
+
7
+ private const val FUSED_PROVIDER = "fused"
8
+
9
+ internal fun Location.isMocked(): Boolean {
10
+ return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
11
+ isMock
12
+ } else {
13
+ @Suppress("DEPRECATION")
14
+ isFromMockProvider
15
+ }
16
+ }
17
+
18
+ internal fun Location.providerUsed(): LocationProviderUsed {
19
+ return when (provider) {
20
+ FUSED_PROVIDER -> LocationProviderUsed.FUSED
21
+ LocationManager.GPS_PROVIDER -> LocationProviderUsed.GPS
22
+ LocationManager.NETWORK_PROVIDER -> LocationProviderUsed.NETWORK
23
+ LocationManager.PASSIVE_PROVIDER -> LocationProviderUsed.PASSIVE
24
+ else -> LocationProviderUsed.UNKNOWN
25
+ }
26
+ }
@@ -0,0 +1,31 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.location.Location
4
+ import android.os.Build
5
+ import com.margelo.nitro.core.NullType.Companion.NULL
6
+
7
+ internal fun nullableDouble(value: Double?): NullableDouble {
8
+ return value?.let { NullableDouble.create(it) } ?: NullableDouble.create(NULL)
9
+ }
10
+
11
+ internal fun Location.altitudeValue(): NullableDouble {
12
+ return nullableDouble(if (hasAltitude()) altitude else null)
13
+ }
14
+
15
+ internal fun Location.altitudeAccuracyValue(): NullableDouble {
16
+ return nullableDouble(
17
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && hasVerticalAccuracy()) {
18
+ verticalAccuracyMeters.toDouble()
19
+ } else {
20
+ null
21
+ }
22
+ )
23
+ }
24
+
25
+ internal fun Location.headingValue(): NullableDouble {
26
+ return nullableDouble(if (hasBearing()) bearing.toDouble() else null)
27
+ }
28
+
29
+ internal fun Location.speedValue(): NullableDouble {
30
+ return nullableDouble(if (hasSpeed()) speed.toDouble() else null)
31
+ }