react-native-nitro-geolocation 0.0.1 → 0.1.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 (79) hide show
  1. package/LICENSE +4 -1
  2. package/README.md +318 -0
  3. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/GetCurrentPosition.kt +341 -0
  4. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocation.kt +76 -5
  5. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/RequestAuthorization.kt +164 -0
  6. package/android/src/main/java/com/margelo/nitro/nitrogeolocation/WatchPosition.kt +228 -0
  7. package/ios/LocationManager.swift +529 -0
  8. package/ios/NitroGeolocation.swift +96 -2
  9. package/nitrogen/generated/.gitattributes +1 -0
  10. package/nitrogen/generated/android/c++/JAuthorizationLevelInternal.hpp +62 -0
  11. package/nitrogen/generated/android/c++/JFunc_void.hpp +74 -0
  12. package/nitrogen/generated/android/c++/JFunc_void_GeolocationError.hpp +77 -0
  13. package/nitrogen/generated/android/c++/JFunc_void_GeolocationResponse.hpp +79 -0
  14. package/nitrogen/generated/android/c++/JGeolocationCoordinates.hpp +77 -0
  15. package/nitrogen/generated/android/c++/JGeolocationError.hpp +69 -0
  16. package/nitrogen/generated/android/c++/JGeolocationOptions.hpp +77 -0
  17. package/nitrogen/generated/android/c++/JGeolocationResponse.hpp +59 -0
  18. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.cpp +98 -0
  19. package/nitrogen/generated/android/c++/JHybridNitroGeolocationSpec.hpp +69 -0
  20. package/nitrogen/generated/android/c++/JLocationProviderInternal.hpp +62 -0
  21. package/nitrogen/generated/android/c++/JRNConfigurationInternal.hpp +69 -0
  22. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AuthorizationLevelInternal.kt +22 -0
  23. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void.kt +81 -0
  24. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationError.kt +81 -0
  25. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_GeolocationResponse.kt +81 -0
  26. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationCoordinates.kt +47 -0
  27. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationError.kt +41 -0
  28. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationOptions.kt +47 -0
  29. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeolocationResponse.kt +32 -0
  30. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroGeolocationSpec.kt +87 -0
  31. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderInternal.kt +22 -0
  32. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/RNConfigurationInternal.kt +38 -0
  33. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/nitrogeolocationOnLoad.kt +35 -0
  34. package/nitrogen/generated/android/nitrogeolocation+autolinking.cmake +81 -0
  35. package/nitrogen/generated/android/nitrogeolocation+autolinking.gradle +27 -0
  36. package/nitrogen/generated/android/nitrogeolocationOnLoad.cpp +50 -0
  37. package/nitrogen/generated/android/nitrogeolocationOnLoad.hpp +25 -0
  38. package/nitrogen/generated/ios/NitroGeolocation+autolinking.rb +60 -0
  39. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.cpp +56 -0
  40. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.hpp +252 -0
  41. package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Umbrella.hpp +67 -0
  42. package/nitrogen/generated/ios/NitroGeolocationAutolinking.mm +33 -0
  43. package/nitrogen/generated/ios/NitroGeolocationAutolinking.swift +25 -0
  44. package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.cpp +11 -0
  45. package/nitrogen/generated/ios/c++/HybridNitroGeolocationSpecSwift.hpp +125 -0
  46. package/nitrogen/generated/ios/swift/AuthorizationLevelInternal.swift +44 -0
  47. package/nitrogen/generated/ios/swift/Func_void.swift +47 -0
  48. package/nitrogen/generated/ios/swift/Func_void_GeolocationError.swift +47 -0
  49. package/nitrogen/generated/ios/swift/Func_void_GeolocationResponse.swift +47 -0
  50. package/nitrogen/generated/ios/swift/GeolocationCoordinates.swift +149 -0
  51. package/nitrogen/generated/ios/swift/GeolocationError.swift +79 -0
  52. package/nitrogen/generated/ios/swift/GeolocationOptions.swift +185 -0
  53. package/nitrogen/generated/ios/swift/GeolocationResponse.swift +46 -0
  54. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec.swift +54 -0
  55. package/nitrogen/generated/ios/swift/HybridNitroGeolocationSpec_cxx.swift +236 -0
  56. package/nitrogen/generated/ios/swift/LocationProviderInternal.swift +44 -0
  57. package/nitrogen/generated/ios/swift/RNConfigurationInternal.swift +104 -0
  58. package/nitrogen/generated/shared/c++/AuthorizationLevelInternal.hpp +80 -0
  59. package/nitrogen/generated/shared/c++/GeolocationCoordinates.hpp +91 -0
  60. package/nitrogen/generated/shared/c++/GeolocationError.hpp +83 -0
  61. package/nitrogen/generated/shared/c++/GeolocationOptions.hpp +91 -0
  62. package/nitrogen/generated/shared/c++/GeolocationResponse.hpp +72 -0
  63. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.cpp +26 -0
  64. package/nitrogen/generated/shared/c++/HybridNitroGeolocationSpec.hpp +79 -0
  65. package/nitrogen/generated/shared/c++/LocationProviderInternal.hpp +80 -0
  66. package/nitrogen/generated/shared/c++/RNConfigurationInternal.hpp +84 -0
  67. package/package.json +34 -10
  68. package/src/NitroGeolocation.nitro.ts +38 -3
  69. package/src/NitroGeolocationModule.ts +5 -0
  70. package/src/clearWatch.ts +13 -0
  71. package/src/getCurrentPosition.ts +14 -0
  72. package/src/index.tsx +32 -7
  73. package/src/requestAuthorization.ts +9 -0
  74. package/src/setRNConfiguration.ts +22 -0
  75. package/src/stopObserving.ts +12 -0
  76. package/src/types.ts +43 -0
  77. package/src/watchPosition.ts +26 -0
  78. package/nitro.json +0 -17
  79. package/turbo.json +0 -42
@@ -1,10 +1,81 @@
1
1
  package com.margelo.nitro.nitrogeolocation
2
-
2
+
3
3
  import com.facebook.proguard.annotations.DoNotStrip
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
+ import com.margelo.nitro.NitroModules
4
6
 
5
7
  @DoNotStrip
6
- class NitroGeolocation : HybridNitroGeolocationSpec() {
7
- override fun multiply(a: Double, b: Double): Double {
8
- return a * b
9
- }
8
+ class NitroGeolocation(
9
+ private val reactContext: ReactApplicationContext = NitroModules.applicationContext!!
10
+ ) : HybridNitroGeolocationSpec() {
11
+ private var configuration: RNConfigurationInternal =
12
+ RNConfigurationInternal(
13
+ skipPermissionRequests = false,
14
+ authorizationLevel = null,
15
+ enableBackgroundLocationUpdates = null,
16
+ locationProvider = null
17
+ )
18
+
19
+ private val requestAuthorizationHandler by lazy {
20
+ RequestAuthorization(
21
+ reactContext = reactContext,
22
+ onPermissionResult = { result, success, error ->
23
+ when (result) {
24
+ is PermissionResult.Granted -> success?.invoke()
25
+ is PermissionResult.Denied ->
26
+ error?.invoke(
27
+ createPermissionError(
28
+ "Location permission was not granted."
29
+ )
30
+ )
31
+ }
32
+ }
33
+ )
34
+ }
35
+
36
+ private val watchPositionHandler by lazy { WatchPosition(reactContext) }
37
+
38
+ override fun setRNConfiguration(config: RNConfigurationInternal) {
39
+ configuration = config
40
+ }
41
+
42
+ override fun requestAuthorization(
43
+ success: (() -> Unit)?,
44
+ error: ((error: GeolocationError) -> Unit)?
45
+ ) {
46
+ requestAuthorizationHandler.execute(success, error)
47
+ }
48
+
49
+ override fun getCurrentPosition(
50
+ success: (position: GeolocationResponse) -> Unit,
51
+ error: ((error: GeolocationError) -> Unit)?,
52
+ options: GeolocationOptions?
53
+ ) {
54
+ GetCurrentPosition(reactContext).execute(success, error, options)
55
+ }
56
+
57
+ override fun watchPosition(
58
+ success: (position: GeolocationResponse) -> Unit,
59
+ error: ((error: GeolocationError) -> Unit)?,
60
+ options: GeolocationOptions?
61
+ ): Double {
62
+ return watchPositionHandler.watch(success, error, options).toDouble()
63
+ }
64
+
65
+ override fun clearWatch(watchId: Double) {
66
+ watchPositionHandler.clearWatch(watchId.toInt())
67
+ }
68
+
69
+ override fun stopObserving() {
70
+ watchPositionHandler.stopObserving()
71
+ }
72
+
73
+ private fun createPermissionError(message: String) =
74
+ GeolocationError(
75
+ code = RequestAuthorization.PERMISSION_DENIED.toDouble(),
76
+ message = message,
77
+ PERMISSION_DENIED = RequestAuthorization.PERMISSION_DENIED.toDouble(),
78
+ POSITION_UNAVAILABLE = RequestAuthorization.POSITION_UNAVAILABLE.toDouble(),
79
+ TIMEOUT = RequestAuthorization.TIMEOUT.toDouble()
80
+ )
10
81
  }
@@ -0,0 +1,164 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.Manifest
4
+ import android.content.pm.PackageManager
5
+ import android.os.Build
6
+ import androidx.core.app.ActivityCompat
7
+ import androidx.core.content.ContextCompat
8
+ import com.facebook.react.bridge.ReactApplicationContext
9
+ import com.facebook.react.modules.core.PermissionAwareActivity
10
+ import com.facebook.react.modules.core.PermissionListener
11
+
12
+ // ===== Data Models =====
13
+ sealed class PermissionState {
14
+ object LegacyAndroid : PermissionState()
15
+ object AlreadyGranted : PermissionState()
16
+ object NeedsRequest : PermissionState()
17
+ data class Error(val message: String) : PermissionState()
18
+ }
19
+
20
+ sealed class PermissionResult {
21
+ object Granted : PermissionResult()
22
+ object Denied : PermissionResult()
23
+ }
24
+
25
+ class RequestAuthorization(
26
+ private val reactContext: ReactApplicationContext,
27
+ private val onPermissionResult:
28
+ (PermissionResult, (() -> Unit)?, ((GeolocationError) -> Unit)?) -> Unit
29
+ ) {
30
+ private var pendingAuthSuccess: (() -> Unit)? = null
31
+ private var pendingAuthError: ((error: GeolocationError) -> Unit)? = null
32
+
33
+ fun execute(success: (() -> Unit)?, error: ((error: GeolocationError) -> Unit)?) {
34
+ val state = determinePermissionState()
35
+ executePermissionAction(state, success, error)
36
+ }
37
+
38
+ // ===== State Determination (Pure Functions) =====
39
+ private fun determinePermissionState(): PermissionState =
40
+ when {
41
+ isLegacyAndroid() -> PermissionState.LegacyAndroid
42
+ else -> determineModernAndroidState()
43
+ }
44
+
45
+ private fun determineModernAndroidState(): PermissionState =
46
+ when {
47
+ hasLocationPermission(reactContext) -> PermissionState.AlreadyGranted
48
+ reactContext.currentActivity == null ->
49
+ PermissionState.Error("Current activity is null")
50
+ else -> PermissionState.NeedsRequest
51
+ }
52
+
53
+ private fun isLegacyAndroid(): Boolean = Build.VERSION.SDK_INT < Build.VERSION_CODES.M
54
+
55
+ private fun hasLocationPermission(context: ReactApplicationContext): Boolean =
56
+ LOCATION_PERMISSIONS.any { permission ->
57
+ ContextCompat.checkSelfPermission(context, permission) ==
58
+ PackageManager.PERMISSION_GRANTED
59
+ }
60
+
61
+ private fun determinePermissionResult(
62
+ permissions: Array<String>,
63
+ grantResults: IntArray
64
+ ): PermissionResult {
65
+ val hasGrantedPermission =
66
+ permissions.indices.any { i ->
67
+ isLocationPermission(permissions[i]) &&
68
+ grantResults[i] == PackageManager.PERMISSION_GRANTED
69
+ }
70
+
71
+ return when {
72
+ hasGrantedPermission -> PermissionResult.Granted
73
+ else -> PermissionResult.Denied
74
+ }
75
+ }
76
+
77
+ private fun isLocationPermission(permission: String): Boolean =
78
+ permission in LOCATION_PERMISSIONS
79
+
80
+ // ===== Actions (Side Effects) =====
81
+ private fun executePermissionAction(
82
+ state: PermissionState,
83
+ success: (() -> Unit)?,
84
+ error: ((error: GeolocationError) -> Unit)?
85
+ ) {
86
+ when (state) {
87
+ is PermissionState.LegacyAndroid -> success?.invoke()
88
+ is PermissionState.AlreadyGranted -> success?.invoke()
89
+ is PermissionState.NeedsRequest -> showPermissionDialog(success, error)
90
+ is PermissionState.Error -> error?.invoke(createPermissionError(state.message))
91
+ }
92
+ }
93
+
94
+ private fun showPermissionDialog(
95
+ success: (() -> Unit)?,
96
+ error: ((error: GeolocationError) -> Unit)?
97
+ ) {
98
+ pendingAuthSuccess = success
99
+ pendingAuthError = error
100
+
101
+ reactContext.currentActivity?.let { activity ->
102
+ requestPermissionsFromActivity(activity)
103
+ }
104
+ }
105
+
106
+ private fun requestPermissionsFromActivity(activity: android.app.Activity) {
107
+ val permissions = LOCATION_PERMISSIONS.toTypedArray()
108
+
109
+ when (val permissionAware = activity as? PermissionAwareActivity) {
110
+ null ->
111
+ ActivityCompat.requestPermissions(
112
+ activity,
113
+ permissions,
114
+ PERMISSION_REQUEST_CODE
115
+ )
116
+ else ->
117
+ permissionAware.requestPermissions(
118
+ permissions,
119
+ PERMISSION_REQUEST_CODE,
120
+ createPermissionListener()
121
+ )
122
+ }
123
+ }
124
+
125
+ private fun createPermissionListener() =
126
+ PermissionListener { requestCode, permissions, grantResults ->
127
+ when (requestCode) {
128
+ PERMISSION_REQUEST_CODE -> {
129
+ val result = determinePermissionResult(permissions, grantResults)
130
+ onPermissionResult(result, pendingAuthSuccess, pendingAuthError)
131
+ clearPendingCallbacks()
132
+ true
133
+ }
134
+ else -> false
135
+ }
136
+ }
137
+
138
+ private fun clearPendingCallbacks() {
139
+ pendingAuthSuccess = null
140
+ pendingAuthError = null
141
+ }
142
+
143
+ private fun createPermissionError(message: String) =
144
+ GeolocationError(
145
+ code = PERMISSION_DENIED.toDouble(),
146
+ message = message,
147
+ PERMISSION_DENIED = PERMISSION_DENIED.toDouble(),
148
+ POSITION_UNAVAILABLE = POSITION_UNAVAILABLE.toDouble(),
149
+ TIMEOUT = TIMEOUT.toDouble()
150
+ )
151
+
152
+ companion object {
153
+ const val PERMISSION_DENIED = 1
154
+ const val POSITION_UNAVAILABLE = 2
155
+ const val TIMEOUT = 3
156
+ const val PERMISSION_REQUEST_CODE = 2025
157
+
158
+ private val LOCATION_PERMISSIONS =
159
+ listOf(
160
+ Manifest.permission.ACCESS_FINE_LOCATION,
161
+ Manifest.permission.ACCESS_COARSE_LOCATION
162
+ )
163
+ }
164
+ }
@@ -0,0 +1,228 @@
1
+ package com.margelo.nitro.nitrogeolocation
2
+
3
+ import android.Manifest
4
+ import android.content.Context
5
+ import android.content.pm.PackageManager
6
+ import android.location.Location
7
+ import android.location.LocationListener
8
+ import android.location.LocationManager
9
+ import android.os.Bundle
10
+ import android.os.Looper
11
+ import android.util.Log
12
+ import androidx.core.content.ContextCompat
13
+ import com.facebook.react.bridge.ReactApplicationContext
14
+ import java.util.concurrent.ConcurrentHashMap
15
+ import java.util.concurrent.atomic.AtomicInteger
16
+
17
+ class WatchPosition(private val reactContext: ReactApplicationContext) {
18
+
19
+ private val watchCallbacks = ConcurrentHashMap<Int, WatchCallback>()
20
+ private val watchIdGenerator = AtomicInteger(0)
21
+ private var locationListener: LocationListener? = null
22
+ private var watchedProvider: String? = null
23
+ private var currentOptions: GeolocationOptions? = null
24
+
25
+ data class WatchCallback(
26
+ val success: (GeolocationResponse) -> Unit,
27
+ val error: ((GeolocationError) -> Unit)?,
28
+ val options: GeolocationOptions?
29
+ )
30
+
31
+ fun watch(
32
+ success: (GeolocationResponse) -> Unit,
33
+ error: ((GeolocationError) -> Unit)?,
34
+ options: GeolocationOptions?
35
+ ): Int {
36
+ val watchId = watchIdGenerator.incrementAndGet()
37
+ watchCallbacks[watchId] = WatchCallback(success, error, options)
38
+
39
+ // Start observing if this is the first watch
40
+ if (watchCallbacks.size == 1) {
41
+ startObserving(options)
42
+ }
43
+
44
+ return watchId
45
+ }
46
+
47
+ fun clearWatch(watchId: Int) {
48
+ watchCallbacks.remove(watchId)
49
+
50
+ // Stop observing if no more watches
51
+ if (watchCallbacks.isEmpty()) {
52
+ stopObserving()
53
+ }
54
+ }
55
+
56
+ fun stopObserving() {
57
+ val locationManager =
58
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
59
+
60
+ locationListener?.let { listener -> locationManager?.removeUpdates(listener) }
61
+
62
+ locationListener = null
63
+ watchedProvider = null
64
+ currentOptions = null
65
+ watchCallbacks.clear()
66
+ }
67
+
68
+ private fun startObserving(options: GeolocationOptions?) {
69
+ val locationManager =
70
+ reactContext.getSystemService(Context.LOCATION_SERVICE) as? LocationManager
71
+
72
+ if (locationManager == null) {
73
+ Log.e(TAG, "LocationManager is not available")
74
+ emitErrorToAll(
75
+ createError(
76
+ GetCurrentPosition.POSITION_UNAVAILABLE,
77
+ "LocationManager is not available"
78
+ )
79
+ )
80
+ return
81
+ }
82
+
83
+ val opts = parseOptions(options)
84
+ val provider = getValidProvider(locationManager, opts.enableHighAccuracy)
85
+
86
+ if (provider == null) {
87
+ Log.e(TAG, "No location provider available")
88
+ emitErrorToAll(
89
+ createError(
90
+ GetCurrentPosition.POSITION_UNAVAILABLE,
91
+ "No location provider available"
92
+ )
93
+ )
94
+ return
95
+ }
96
+
97
+ // If already watching with the same provider, don't restart
98
+ if (provider == watchedProvider) {
99
+ return
100
+ }
101
+
102
+ try {
103
+ // Remove old listener if exists
104
+ locationListener?.let { locationManager.removeUpdates(it) }
105
+
106
+ // Create new listener
107
+ val listener =
108
+ object : LocationListener {
109
+ override fun onLocationChanged(location: Location) {
110
+ val position = locationToPosition(location)
111
+ // Call all watch callbacks
112
+ watchCallbacks.values.forEach { callback -> callback.success(position) }
113
+ }
114
+
115
+ override fun onStatusChanged(
116
+ provider: String?,
117
+ status: Int,
118
+ extras: Bundle?
119
+ ) {}
120
+ override fun onProviderEnabled(provider: String) {}
121
+ override fun onProviderDisabled(provider: String) {}
122
+ }
123
+
124
+ locationManager.requestLocationUpdates(
125
+ provider,
126
+ opts.interval.toLong(),
127
+ opts.distanceFilter.toFloat(),
128
+ listener,
129
+ Looper.getMainLooper()
130
+ )
131
+
132
+ locationListener = listener
133
+ watchedProvider = provider
134
+ currentOptions = options
135
+ } catch (e: SecurityException) {
136
+ Log.e(TAG, "SecurityException: ${e.message}")
137
+ emitErrorToAll(
138
+ createError(
139
+ GetCurrentPosition.PERMISSION_DENIED,
140
+ "Location permission denied: ${e.message}"
141
+ )
142
+ )
143
+ }
144
+ }
145
+
146
+ private fun emitErrorToAll(error: GeolocationError) {
147
+ watchCallbacks.values.forEach { callback -> callback.error?.invoke(error) }
148
+ }
149
+
150
+ private fun parseOptions(options: GeolocationOptions?): ParsedOptions {
151
+ return ParsedOptions(
152
+ interval = options?.interval ?: DEFAULT_INTERVAL,
153
+ distanceFilter = options?.distanceFilter ?: DEFAULT_DISTANCE_FILTER,
154
+ enableHighAccuracy = options?.enableHighAccuracy ?: false
155
+ )
156
+ }
157
+
158
+ private fun getValidProvider(locationManager: LocationManager, highAccuracy: Boolean): String? {
159
+ val preferredProvider =
160
+ if (highAccuracy) LocationManager.GPS_PROVIDER else LocationManager.NETWORK_PROVIDER
161
+ val fallbackProvider =
162
+ if (highAccuracy) LocationManager.NETWORK_PROVIDER else LocationManager.GPS_PROVIDER
163
+
164
+ return when {
165
+ isProviderValid(locationManager, preferredProvider) -> preferredProvider
166
+ isProviderValid(locationManager, fallbackProvider) -> fallbackProvider
167
+ else -> null
168
+ }
169
+ }
170
+
171
+ private fun isProviderValid(locationManager: LocationManager, provider: String): Boolean {
172
+ if (!locationManager.isProviderEnabled(provider)) return false
173
+
174
+ val permission =
175
+ if (provider == LocationManager.GPS_PROVIDER)
176
+ Manifest.permission.ACCESS_FINE_LOCATION
177
+ else Manifest.permission.ACCESS_COARSE_LOCATION
178
+
179
+ return ContextCompat.checkSelfPermission(reactContext, permission) ==
180
+ PackageManager.PERMISSION_GRANTED
181
+ }
182
+
183
+ private fun locationToPosition(location: Location): GeolocationResponse {
184
+ return GeolocationResponse(
185
+ coords =
186
+ GeolocationCoordinates(
187
+ latitude = location.latitude,
188
+ longitude = location.longitude,
189
+ altitude = if (location.hasAltitude()) location.altitude else null,
190
+ accuracy = location.accuracy.toDouble(),
191
+ altitudeAccuracy =
192
+ if (android.os.Build.VERSION.SDK_INT >=
193
+ android.os.Build.VERSION_CODES.O &&
194
+ location.hasVerticalAccuracy()
195
+ )
196
+ location.verticalAccuracyMeters.toDouble()
197
+ else null,
198
+ heading =
199
+ if (location.hasBearing()) location.bearing.toDouble()
200
+ else null,
201
+ speed = if (location.hasSpeed()) location.speed.toDouble() else null
202
+ ),
203
+ timestamp = location.time.toDouble()
204
+ )
205
+ }
206
+
207
+ private fun createError(code: Int, message: String): GeolocationError {
208
+ return GeolocationError(
209
+ code = code.toDouble(),
210
+ message = message,
211
+ PERMISSION_DENIED = GetCurrentPosition.PERMISSION_DENIED.toDouble(),
212
+ POSITION_UNAVAILABLE = GetCurrentPosition.POSITION_UNAVAILABLE.toDouble(),
213
+ TIMEOUT = GetCurrentPosition.TIMEOUT.toDouble()
214
+ )
215
+ }
216
+
217
+ private data class ParsedOptions(
218
+ val interval: Double,
219
+ val distanceFilter: Double,
220
+ val enableHighAccuracy: Boolean
221
+ )
222
+
223
+ companion object {
224
+ private const val TAG = "WatchPosition"
225
+ const val DEFAULT_INTERVAL = 1000.0 // 1 second
226
+ const val DEFAULT_DISTANCE_FILTER = 100.0 // 100 meters
227
+ }
228
+ }