react-native-nitro-geolocation 1.2.6 → 1.3.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.
- package/README.md +61 -272
- package/android/build.gradle +1 -0
- package/android/src/main/AndroidManifest.xml +39 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidFusedLocationProvider.kt +310 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidFusedRequestFactory.kt +31 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidGeolocationConversions.kt +71 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidGeolocationErrors.kt +85 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidGeolocationOptions.kt +92 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidLocationSettings.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidProviderRoute.kt +74 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroBackgroundLocation.kt +132 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/NitroGeolocation.kt +219 -476
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/AndroidBackgroundHttpSync.kt +134 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/AndroidBackgroundPermissions.kt +196 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/AndroidBackgroundSerialization.kt +266 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroActivityRecognitionReceiver.kt +13 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundEventHub.kt +65 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundHeadlessTaskService.kt +58 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundLocationController.kt +711 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundLocationService.kt +48 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundNotificationFactory.kt +37 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBackgroundStore.kt +655 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroBootReceiver.kt +26 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroGeofenceReceiver.kt +14 -0
- package/android/src/main/java/com/margelo/nitro/nitrogeolocation/background/NitroLocationUpdateReceiver.kt +37 -0
- package/android/src/test/java/com/margelo/nitro/nitrogeolocation/AndroidFusedLocationProviderTest.kt +64 -0
- package/android/src/test/java/com/margelo/nitro/nitrogeolocation/AndroidProviderRouteTest.kt +116 -0
- package/ios/IOSBackgroundHttpSync.swift +126 -0
- package/ios/IOSBackgroundLocationDelegate.swift +36 -0
- package/ios/IOSBackgroundMotion.swift +55 -0
- package/ios/IOSBackgroundSerialization.swift +539 -0
- package/ios/IOSGeolocationConversions.swift +131 -0
- package/ios/IOSGeolocationDelegate.swift +31 -0
- package/ios/IOSGeolocationErrors.swift +39 -0
- package/ios/IOSGeolocationOptions.swift +135 -0
- package/ios/NitroBackgroundLocation.swift +849 -0
- package/ios/NitroGeolocation.swift +14 -347
- package/nitrogen/generated/android/c++/JActivityRecognitionOptions.hpp +69 -0
- package/nitrogen/generated/android/c++/JAndroidBackgroundLocationOptions.hpp +74 -0
- package/nitrogen/generated/android/c++/JAndroidBackgroundLocationStatus.hpp +67 -0
- package/nitrogen/generated/android/c++/JAndroidBackgroundProvider.hpp +61 -0
- package/nitrogen/generated/android/c++/JAndroidForegroundServiceOptions.hpp +90 -0
- package/nitrogen/generated/android/c++/JBackgroundEventEnvelope.hpp +129 -0
- package/nitrogen/generated/android/c++/JBackgroundEventType.hpp +70 -0
- package/nitrogen/generated/android/c++/JBackgroundHttpMethod.hpp +61 -0
- package/nitrogen/generated/android/c++/JBackgroundHttpSyncOptions.hpp +131 -0
- package/nitrogen/generated/android/c++/JBackgroundHttpSyncResult.hpp +111 -0
- package/nitrogen/generated/android/c++/JBackgroundLocation.hpp +110 -0
- package/nitrogen/generated/android/c++/JBackgroundLocationOptions.hpp +162 -0
- package/nitrogen/generated/android/c++/JBackgroundLocationSource.hpp +73 -0
- package/nitrogen/generated/android/c++/JBackgroundLocationState.hpp +70 -0
- package/nitrogen/generated/android/c++/JBackgroundLocationStatus.hpp +126 -0
- package/nitrogen/generated/android/c++/JBackgroundPermissionResult.hpp +79 -0
- package/nitrogen/generated/android/c++/JBackgroundPermissionStatus.hpp +64 -0
- package/nitrogen/generated/android/c++/JBackgroundTrackingMode.hpp +61 -0
- package/nitrogen/generated/android/c++/JBatterySnapshot.hpp +61 -0
- package/nitrogen/generated/android/c++/JDetectedActivity.hpp +66 -0
- package/nitrogen/generated/android/c++/JDetectedActivityType.hpp +76 -0
- package/nitrogen/generated/android/c++/JFunc_void_BackgroundEventEnvelope.hpp +114 -0
- package/nitrogen/generated/android/c++/JFunc_void_BackgroundLocation.hpp +95 -0
- package/nitrogen/generated/android/c++/JGeofenceEvent.hpp +94 -0
- package/nitrogen/generated/android/c++/JGeofenceRegion.hpp +112 -0
- package/nitrogen/generated/android/c++/JGeofenceTransition.hpp +61 -0
- package/nitrogen/generated/android/c++/JGeofencingOptions.hpp +82 -0
- package/nitrogen/generated/android/c++/JGetStoredBackgroundEventsOptions.hpp +90 -0
- package/nitrogen/generated/android/c++/JGetStoredBackgroundLocationsOptions.hpp +69 -0
- package/nitrogen/generated/android/c++/JHybridNitroBackgroundLocationSpec.cpp +662 -0
- package/nitrogen/generated/android/c++/JHybridNitroBackgroundLocationSpec.hpp +89 -0
- package/nitrogen/generated/android/c++/JIOSBackgroundActivityType.hpp +67 -0
- package/nitrogen/generated/android/c++/JIOSBackgroundLocationOptions.hpp +79 -0
- package/nitrogen/generated/android/c++/JIOSBackgroundLocationStatus.hpp +61 -0
- package/nitrogen/generated/android/c++/JLocationProviderStatus.hpp +5 -1
- package/nitrogen/generated/android/c++/JStoredBackgroundEventEnvelope.hpp +115 -0
- package/nitrogen/generated/android/c++/JStoredBackgroundLocation.hpp +122 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Boolean_String_Double.cpp +34 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_Boolean_String_Double.hpp +100 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/ActivityRecognitionOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidBackgroundLocationOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidBackgroundLocationStatus.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidBackgroundProvider.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/AndroidForegroundServiceOptions.kt +91 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundEventEnvelope.kt +96 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundEventType.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundHttpMethod.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundHttpSyncOptions.kt +101 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundHttpSyncResult.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundLocation.kt +96 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundLocationOptions.kt +136 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundLocationSource.kt +28 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundLocationState.kt +27 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundLocationStatus.kt +116 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundPermissionResult.kt +71 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundPermissionStatus.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BackgroundTrackingMode.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/BatterySnapshot.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/DetectedActivity.kt +61 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/DetectedActivityType.kt +29 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_BackgroundEventEnvelope.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Func_void_BackgroundLocation.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeofenceEvent.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeofenceRegion.kt +96 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeofenceTransition.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GeofencingOptions.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GetStoredBackgroundEventsOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/GetStoredBackgroundLocationsOptions.kt +66 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/HybridNitroBackgroundLocationSpec.kt +174 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/IOSBackgroundActivityType.kt +26 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/IOSBackgroundLocationOptions.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/IOSBackgroundLocationStatus.kt +56 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/LocationProviderStatus.kt +7 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/StoredBackgroundEventEnvelope.kt +76 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/StoredBackgroundLocation.kt +111 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitrogeolocation/Variant_NullType_Boolean_String_Double.kt +88 -0
- package/nitrogen/generated/android/nitrogeolocation+autolinking.cmake +3 -0
- package/nitrogen/generated/android/nitrogeolocationOnLoad.cpp +20 -0
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.cpp +104 -15
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Bridge.hpp +1107 -50
- package/nitrogen/generated/ios/NitroGeolocation-Swift-Cxx-Umbrella.hpp +102 -0
- package/nitrogen/generated/ios/NitroGeolocationAutolinking.mm +8 -0
- package/nitrogen/generated/ios/NitroGeolocationAutolinking.swift +15 -3
- package/nitrogen/generated/ios/c++/HybridNitroBackgroundLocationSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridNitroBackgroundLocationSpecSwift.hpp +416 -0
- package/nitrogen/generated/ios/swift/ActivityRecognitionOptions.swift +96 -0
- package/nitrogen/generated/ios/swift/AndroidBackgroundLocationOptions.swift +76 -0
- package/nitrogen/generated/ios/swift/AndroidBackgroundLocationStatus.swift +58 -0
- package/nitrogen/generated/ios/swift/AndroidBackgroundProvider.swift +44 -0
- package/nitrogen/generated/ios/swift/AndroidForegroundServiceOptions.swift +160 -0
- package/nitrogen/generated/ios/swift/BackgroundEventEnvelope.swift +110 -0
- package/nitrogen/generated/ios/swift/BackgroundEventType.swift +56 -0
- package/nitrogen/generated/ios/swift/BackgroundHttpMethod.swift +44 -0
- package/nitrogen/generated/ios/swift/BackgroundHttpSyncOptions.swift +259 -0
- package/nitrogen/generated/ios/swift/BackgroundHttpSyncResult.swift +87 -0
- package/nitrogen/generated/ios/swift/BackgroundLocation.swift +118 -0
- package/nitrogen/generated/ios/swift/BackgroundLocationOptions.swift +292 -0
- package/nitrogen/generated/ios/swift/BackgroundLocationSource.swift +60 -0
- package/nitrogen/generated/ios/swift/BackgroundLocationState.swift +56 -0
- package/nitrogen/generated/ios/swift/BackgroundLocationStatus.swift +124 -0
- package/nitrogen/generated/ios/swift/BackgroundPermissionResult.swift +81 -0
- package/nitrogen/generated/ios/swift/BackgroundPermissionStatus.swift +48 -0
- package/nitrogen/generated/ios/swift/BackgroundTrackingMode.swift +44 -0
- package/nitrogen/generated/ios/swift/BatterySnapshot.swift +60 -0
- package/nitrogen/generated/ios/swift/DetectedActivity.swift +39 -0
- package/nitrogen/generated/ios/swift/DetectedActivityType.swift +64 -0
- package/nitrogen/generated/ios/swift/Func_void_BackgroundEventEnvelope.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_BackgroundHttpSyncResult.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_BackgroundLocation.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_BackgroundLocationStatus.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_BackgroundPermissionResult.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__optional_BackgroundLocationOptions_.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_GeofenceRegion_.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_StoredBackgroundEventEnvelope_.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_StoredBackgroundLocation_.swift +46 -0
- package/nitrogen/generated/ios/swift/GeofenceEvent.swift +50 -0
- package/nitrogen/generated/ios/swift/GeofenceRegion.swift +195 -0
- package/nitrogen/generated/ios/swift/GeofenceTransition.swift +44 -0
- package/nitrogen/generated/ios/swift/GeofencingOptions.swift +66 -0
- package/nitrogen/generated/ios/swift/GetStoredBackgroundEventsOptions.swift +102 -0
- package/nitrogen/generated/ios/swift/GetStoredBackgroundLocationsOptions.swift +96 -0
- package/nitrogen/generated/ios/swift/HybridNitroBackgroundLocationSpec.swift +81 -0
- package/nitrogen/generated/ios/swift/HybridNitroBackgroundLocationSpec_cxx.swift +654 -0
- package/nitrogen/generated/ios/swift/IOSBackgroundActivityType.swift +52 -0
- package/nitrogen/generated/ios/swift/IOSBackgroundLocationOptions.swift +125 -0
- package/nitrogen/generated/ios/swift/IOSBackgroundLocationStatus.swift +34 -0
- package/nitrogen/generated/ios/swift/LocationProviderStatus.swift +19 -1
- package/nitrogen/generated/ios/swift/StoredBackgroundEventEnvelope.swift +54 -0
- package/nitrogen/generated/ios/swift/StoredBackgroundLocation.swift +120 -0
- package/nitrogen/generated/ios/swift/Variant_NullType_Bool_String_Double.swift +34 -0
- package/nitrogen/generated/shared/c++/ActivityRecognitionOptions.hpp +95 -0
- package/nitrogen/generated/shared/c++/AndroidBackgroundLocationOptions.hpp +100 -0
- package/nitrogen/generated/shared/c++/AndroidBackgroundLocationStatus.hpp +93 -0
- package/nitrogen/generated/shared/c++/AndroidBackgroundProvider.hpp +80 -0
- package/nitrogen/generated/shared/c++/AndroidForegroundServiceOptions.hpp +116 -0
- package/nitrogen/generated/shared/c++/BackgroundEventEnvelope.hpp +140 -0
- package/nitrogen/generated/shared/c++/BackgroundEventType.hpp +92 -0
- package/nitrogen/generated/shared/c++/BackgroundHttpMethod.hpp +80 -0
- package/nitrogen/generated/shared/c++/BackgroundHttpSyncOptions.hpp +129 -0
- package/nitrogen/generated/shared/c++/BackgroundHttpSyncResult.hpp +101 -0
- package/nitrogen/generated/shared/c++/BackgroundLocation.hpp +134 -0
- package/nitrogen/generated/shared/c++/BackgroundLocationOptions.hpp +174 -0
- package/nitrogen/generated/shared/c++/BackgroundLocationSource.hpp +96 -0
- package/nitrogen/generated/shared/c++/BackgroundLocationState.hpp +92 -0
- package/nitrogen/generated/shared/c++/BackgroundLocationStatus.hpp +158 -0
- package/nitrogen/generated/shared/c++/BackgroundPermissionResult.hpp +107 -0
- package/nitrogen/generated/shared/c++/BackgroundPermissionStatus.hpp +84 -0
- package/nitrogen/generated/shared/c++/BackgroundTrackingMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/BatterySnapshot.hpp +87 -0
- package/nitrogen/generated/shared/c++/DetectedActivity.hpp +92 -0
- package/nitrogen/generated/shared/c++/DetectedActivityType.hpp +100 -0
- package/nitrogen/generated/shared/c++/GeofenceEvent.hpp +103 -0
- package/nitrogen/generated/shared/c++/GeofenceRegion.hpp +123 -0
- package/nitrogen/generated/shared/c++/GeofenceTransition.hpp +80 -0
- package/nitrogen/generated/shared/c++/GeofencingOptions.hpp +90 -0
- package/nitrogen/generated/shared/c++/GetStoredBackgroundEventsOptions.hpp +98 -0
- package/nitrogen/generated/shared/c++/GetStoredBackgroundLocationsOptions.hpp +95 -0
- package/nitrogen/generated/shared/c++/HybridNitroBackgroundLocationSpec.cpp +47 -0
- package/nitrogen/generated/shared/c++/HybridNitroBackgroundLocationSpec.hpp +133 -0
- package/nitrogen/generated/shared/c++/IOSBackgroundActivityType.hpp +88 -0
- package/nitrogen/generated/shared/c++/IOSBackgroundLocationOptions.hpp +105 -0
- package/nitrogen/generated/shared/c++/IOSBackgroundLocationStatus.hpp +87 -0
- package/nitrogen/generated/shared/c++/LocationProviderStatus.hpp +5 -1
- package/nitrogen/generated/shared/c++/StoredBackgroundEventEnvelope.hpp +108 -0
- package/nitrogen/generated/shared/c++/StoredBackgroundLocation.hpp +146 -0
- package/package.json +17 -6
- package/src/NitroGeolocation.nitro.ts +4 -4
- package/src/api/getCurrentPosition.ts +1 -1
- package/src/api/requestLocationSettings.ts +3 -2
- package/src/background/NitroBackgroundLocation.nitro.ts +83 -0
- package/src/background/index.ts +200 -0
- package/src/background/index.web.ts +120 -0
- package/src/background/task.ts +13 -0
- package/src/background/types.ts +328 -0
- package/src/compat/index.web.ts +141 -0
- package/src/index.tsx +3 -0
- package/src/index.web.tsx +41 -0
- package/src/publicTypes.ts +6 -5
- package/src/types.ts +3 -0
- package/src/web/browser.ts +171 -0
- package/src/web/index.ts +167 -0
- package/src/web/useWatchPosition.ts +76 -0
- package/src/web/watch.ts +81 -0
- package/src/devtools/index.test.ts +0 -54
- package/src/utils/errors.test.ts +0 -65
- package/src/utils/provider.test.ts +0 -303
package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidFusedLocationProvider.kt
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import android.location.Location
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import com.google.android.gms.location.CurrentLocationRequest
|
|
7
|
+
import com.google.android.gms.location.FusedLocationProviderClient
|
|
8
|
+
import com.google.android.gms.location.LocationCallback
|
|
9
|
+
import com.google.android.gms.location.LocationResult
|
|
10
|
+
import com.google.android.gms.tasks.CancellationTokenSource
|
|
11
|
+
import java.util.concurrent.atomic.AtomicBoolean
|
|
12
|
+
|
|
13
|
+
private const val FUSED_ATTEMPT_TIMEOUT_MS = 15_000L
|
|
14
|
+
private const val FUSED_FALLBACK_RESERVED_TIMEOUT_MS = 10_000L
|
|
15
|
+
|
|
16
|
+
internal class AndroidFusedLocationProvider(
|
|
17
|
+
private val fusedLocationClient: FusedLocationProviderClient,
|
|
18
|
+
private val isCachedLocationValid: (Location, ParsedOptions) -> Boolean,
|
|
19
|
+
private val effectiveMaximumAge: (ParsedOptions) -> Double,
|
|
20
|
+
private val locationToPosition: (Location, LocationProviderUsed?) -> GeolocationResponse
|
|
21
|
+
) {
|
|
22
|
+
fun getCurrentPosition(
|
|
23
|
+
success: (GeolocationResponse) -> Unit,
|
|
24
|
+
error: ((LocationError) -> Unit)?,
|
|
25
|
+
options: ParsedOptions,
|
|
26
|
+
deadlineElapsedRealtime: Long
|
|
27
|
+
) {
|
|
28
|
+
if (effectiveMaximumAge(options) > 0.0) {
|
|
29
|
+
getCachedLocation(options) { cachedLocation, fusedError ->
|
|
30
|
+
if (cachedLocation != null) {
|
|
31
|
+
success(locationToPosition(cachedLocation, LocationProviderUsed.FUSED))
|
|
32
|
+
return@getCachedLocation
|
|
33
|
+
}
|
|
34
|
+
if (fusedError != null) {
|
|
35
|
+
error?.invoke(fusedError)
|
|
36
|
+
return@getCachedLocation
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
requestFreshLocation(success, error, options, deadlineElapsedRealtime)
|
|
40
|
+
}
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
requestFreshLocation(success, error, options, deadlineElapsedRealtime)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
fun getLastKnownPosition(
|
|
48
|
+
success: (GeolocationResponse) -> Unit,
|
|
49
|
+
error: ((LocationError) -> Unit)?,
|
|
50
|
+
options: ParsedOptions
|
|
51
|
+
) {
|
|
52
|
+
getCachedLocation(options) { cachedLocation, fusedError ->
|
|
53
|
+
if (cachedLocation != null) {
|
|
54
|
+
success(locationToPosition(cachedLocation, LocationProviderUsed.FUSED))
|
|
55
|
+
return@getCachedLocation
|
|
56
|
+
}
|
|
57
|
+
if (fusedError != null) {
|
|
58
|
+
error?.invoke(fusedError)
|
|
59
|
+
return@getCachedLocation
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
error?.invoke(createLocationError(
|
|
63
|
+
POSITION_UNAVAILABLE,
|
|
64
|
+
"No cached location available"
|
|
65
|
+
))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
fun requestWatchUpdates(
|
|
70
|
+
options: ParsedOptions,
|
|
71
|
+
callback: LocationCallback,
|
|
72
|
+
onInactiveStart: () -> Unit,
|
|
73
|
+
onFailure: (LocationError?) -> Unit
|
|
74
|
+
) {
|
|
75
|
+
try {
|
|
76
|
+
fusedLocationClient.requestLocationUpdates(
|
|
77
|
+
buildFusedLocationRequest(options),
|
|
78
|
+
callback,
|
|
79
|
+
Looper.getMainLooper()
|
|
80
|
+
)
|
|
81
|
+
.addOnSuccessListener {
|
|
82
|
+
onInactiveStart()
|
|
83
|
+
}
|
|
84
|
+
.addOnFailureListener { exception ->
|
|
85
|
+
onFailure(createFusedRequestFailureError(exception))
|
|
86
|
+
}
|
|
87
|
+
.addOnCanceledListener {
|
|
88
|
+
onFailure(null)
|
|
89
|
+
}
|
|
90
|
+
} catch (e: SecurityException) {
|
|
91
|
+
onFailure(createFusedSecurityError(e.message))
|
|
92
|
+
} catch (_: Exception) {
|
|
93
|
+
onFailure(null)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private fun getCachedLocation(
|
|
98
|
+
options: ParsedOptions,
|
|
99
|
+
completion: (Location?, LocationError?) -> Unit
|
|
100
|
+
) {
|
|
101
|
+
// Fused lastLocation is not requested with LocationRequest granularity,
|
|
102
|
+
// so it cannot prove that a cached fix satisfies coarse-only callers.
|
|
103
|
+
if (options.granularity == AndroidGranularity.COARSE) {
|
|
104
|
+
completion(null, null)
|
|
105
|
+
return
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
fusedLocationClient.lastLocation
|
|
110
|
+
.addOnSuccessListener { location ->
|
|
111
|
+
completion(location?.takeIf { isCachedLocationValid(it, options) }, null)
|
|
112
|
+
}
|
|
113
|
+
.addOnFailureListener { exception ->
|
|
114
|
+
completion(null, createPermissionErrorOrNull(exception))
|
|
115
|
+
}
|
|
116
|
+
.addOnCanceledListener {
|
|
117
|
+
completion(null, null)
|
|
118
|
+
}
|
|
119
|
+
} catch (e: SecurityException) {
|
|
120
|
+
completion(null, createFusedSecurityError(e.message))
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
private fun requestFreshLocation(
|
|
125
|
+
success: (GeolocationResponse) -> Unit,
|
|
126
|
+
error: ((LocationError) -> Unit)?,
|
|
127
|
+
options: ParsedOptions,
|
|
128
|
+
deadlineElapsedRealtime: Long
|
|
129
|
+
) {
|
|
130
|
+
val handler = Handler(Looper.getMainLooper())
|
|
131
|
+
val didComplete = AtomicBoolean(false)
|
|
132
|
+
val remainingTimeoutMillis = remainingTimeoutMillis(deadlineElapsedRealtime)
|
|
133
|
+
|
|
134
|
+
if (remainingTimeoutMillis <= 0L) {
|
|
135
|
+
error?.invoke(createPositionTimeoutError(options))
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
val fusedAttemptTimeoutMillis = fusedAttemptTimeoutMillis(remainingTimeoutMillis)
|
|
139
|
+
val cancellationTokenSource = CancellationTokenSource()
|
|
140
|
+
var locationUpdateCallback: LocationCallback? = null
|
|
141
|
+
|
|
142
|
+
fun complete(result: PositionResult) {
|
|
143
|
+
if (!didComplete.compareAndSet(false, true)) return
|
|
144
|
+
|
|
145
|
+
handler.removeCallbacksAndMessages(null)
|
|
146
|
+
locationUpdateCallback?.let { callback ->
|
|
147
|
+
try {
|
|
148
|
+
fusedLocationClient.removeLocationUpdates(callback)
|
|
149
|
+
} catch (_: Exception) {
|
|
150
|
+
// Ignore cleanup races.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
locationUpdateCallback = null
|
|
154
|
+
try {
|
|
155
|
+
cancellationTokenSource.cancel()
|
|
156
|
+
} catch (_: Exception) {
|
|
157
|
+
// Ignore cleanup races.
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
when (result) {
|
|
161
|
+
is PositionResult.Success -> success(result.position)
|
|
162
|
+
is PositionResult.Failure -> error?.invoke(result.error)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
val timeoutRunnable = Runnable {
|
|
167
|
+
complete(PositionResult.Failure(createPositionTimeoutError(options)))
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
if (options.waitForAccurateLocation) {
|
|
172
|
+
val initialUpdateMaxAge = fusedInitialUpdateMaxAge(
|
|
173
|
+
options,
|
|
174
|
+
effectiveMaximumAge(options)
|
|
175
|
+
)
|
|
176
|
+
val request = buildFusedLocationRequest(
|
|
177
|
+
options.copy(maxUpdateAge = initialUpdateMaxAge),
|
|
178
|
+
maxUpdatesOverride = 1,
|
|
179
|
+
includeDistanceFilter = false
|
|
180
|
+
)
|
|
181
|
+
val callback = object : LocationCallback() {
|
|
182
|
+
override fun onLocationResult(result: LocationResult) {
|
|
183
|
+
val location = result.lastLocation
|
|
184
|
+
if (location != null) {
|
|
185
|
+
complete(PositionResult.Success(
|
|
186
|
+
locationToPosition(location, LocationProviderUsed.FUSED)
|
|
187
|
+
))
|
|
188
|
+
} else {
|
|
189
|
+
complete(PositionResult.Failure(createLocationError(
|
|
190
|
+
POSITION_UNAVAILABLE,
|
|
191
|
+
"Unable to get fused location"
|
|
192
|
+
)))
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
locationUpdateCallback = callback
|
|
197
|
+
|
|
198
|
+
fusedLocationClient.requestLocationUpdates(
|
|
199
|
+
request,
|
|
200
|
+
callback,
|
|
201
|
+
Looper.getMainLooper()
|
|
202
|
+
)
|
|
203
|
+
.addOnFailureListener { exception ->
|
|
204
|
+
complete(PositionResult.Failure(
|
|
205
|
+
createFusedRequestFailureError(exception)
|
|
206
|
+
))
|
|
207
|
+
}
|
|
208
|
+
.addOnCanceledListener {
|
|
209
|
+
complete(PositionResult.Failure(createPositionTimeoutError(options)))
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
handler.postDelayed(timeoutRunnable, fusedAttemptTimeoutMillis)
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
val request = CurrentLocationRequest.Builder()
|
|
217
|
+
.setPriority(options.androidAccuracy.gmsPriority())
|
|
218
|
+
.setGranularity(options.granularity.gmsGranularity())
|
|
219
|
+
.setMaxUpdateAgeMillis(
|
|
220
|
+
coerceNonNegativeMillis(
|
|
221
|
+
fusedInitialUpdateMaxAge(options, effectiveMaximumAge(options))
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
.setDurationMillis(fusedAttemptTimeoutMillis)
|
|
225
|
+
.build()
|
|
226
|
+
|
|
227
|
+
fusedLocationClient.getCurrentLocation(
|
|
228
|
+
request,
|
|
229
|
+
cancellationTokenSource.token
|
|
230
|
+
)
|
|
231
|
+
.addOnSuccessListener { location ->
|
|
232
|
+
if (location != null) {
|
|
233
|
+
complete(PositionResult.Success(
|
|
234
|
+
locationToPosition(location, LocationProviderUsed.FUSED)
|
|
235
|
+
))
|
|
236
|
+
} else {
|
|
237
|
+
complete(PositionResult.Failure(createLocationError(
|
|
238
|
+
POSITION_UNAVAILABLE,
|
|
239
|
+
"Unable to get fused location"
|
|
240
|
+
)))
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
.addOnFailureListener { exception ->
|
|
244
|
+
complete(PositionResult.Failure(
|
|
245
|
+
createFusedRequestFailureError(exception)
|
|
246
|
+
))
|
|
247
|
+
}
|
|
248
|
+
.addOnCanceledListener {
|
|
249
|
+
complete(PositionResult.Failure(createPositionTimeoutError(options)))
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
handler.postDelayed(timeoutRunnable, fusedAttemptTimeoutMillis)
|
|
253
|
+
} catch (e: SecurityException) {
|
|
254
|
+
complete(PositionResult.Failure(createFusedSecurityError(e.message)))
|
|
255
|
+
} catch (e: Exception) {
|
|
256
|
+
complete(PositionResult.Failure(createLocationError(
|
|
257
|
+
POSITION_UNAVAILABLE,
|
|
258
|
+
"Unable to request fused location: ${e.message}"
|
|
259
|
+
)))
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
private fun createPermissionErrorOrNull(exception: Exception): LocationError? {
|
|
264
|
+
return if (exception is SecurityException) {
|
|
265
|
+
createFusedSecurityError(exception.message)
|
|
266
|
+
} else {
|
|
267
|
+
null
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
internal fun createFusedRequestFailureError(exception: Exception): LocationError {
|
|
273
|
+
return if (exception is SecurityException) {
|
|
274
|
+
createFusedSecurityError(exception.message)
|
|
275
|
+
} else {
|
|
276
|
+
createLocationError(
|
|
277
|
+
POSITION_UNAVAILABLE,
|
|
278
|
+
"Unable to request fused location: ${exception.message}"
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
internal fun createFusedSecurityError(message: String?): LocationError {
|
|
284
|
+
return createLocationError(
|
|
285
|
+
PERMISSION_DENIED,
|
|
286
|
+
"Security exception: ${message ?: "unknown error"}"
|
|
287
|
+
)
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
internal fun fusedInitialUpdateMaxAge(
|
|
291
|
+
options: ParsedOptions,
|
|
292
|
+
effectiveMaximumAge: Double
|
|
293
|
+
): Double {
|
|
294
|
+
return options.maxUpdateAge ?: effectiveMaximumAge
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private fun fusedAttemptTimeoutMillis(remainingTimeoutMillis: Long): Long {
|
|
298
|
+
if (remainingTimeoutMillis == Long.MAX_VALUE) {
|
|
299
|
+
return FUSED_ATTEMPT_TIMEOUT_MS
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (remainingTimeoutMillis <= FUSED_FALLBACK_RESERVED_TIMEOUT_MS) {
|
|
303
|
+
return (remainingTimeoutMillis / 2L).coerceAtLeast(1L)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
return minOf(
|
|
307
|
+
FUSED_ATTEMPT_TIMEOUT_MS,
|
|
308
|
+
(remainingTimeoutMillis - FUSED_FALLBACK_RESERVED_TIMEOUT_MS).coerceAtLeast(1L)
|
|
309
|
+
)
|
|
310
|
+
}
|
package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidFusedRequestFactory.kt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import com.google.android.gms.location.LocationRequest as GmsLocationRequest
|
|
4
|
+
|
|
5
|
+
internal fun buildFusedLocationRequest(
|
|
6
|
+
options: ParsedOptions,
|
|
7
|
+
maxUpdatesOverride: Int? = null,
|
|
8
|
+
includeDistanceFilter: Boolean = true
|
|
9
|
+
): GmsLocationRequest {
|
|
10
|
+
val builder = GmsLocationRequest
|
|
11
|
+
.Builder(options.androidAccuracy.gmsPriority(), coercePositiveMillis(options.interval))
|
|
12
|
+
.setMinUpdateIntervalMillis(coercePositiveMillis(options.fastestInterval))
|
|
13
|
+
.setGranularity(options.granularity.gmsGranularity())
|
|
14
|
+
.setWaitForAccurateLocation(options.waitForAccurateLocation)
|
|
15
|
+
.setMaxUpdateDelayMillis(coerceNonNegativeMillis(options.maxUpdateDelay))
|
|
16
|
+
|
|
17
|
+
if (includeDistanceFilter) {
|
|
18
|
+
builder.setMinUpdateDistanceMeters(options.distanceFilter.toFloat())
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
options.maxUpdateAge?.let { value ->
|
|
22
|
+
builder.setMaxUpdateAgeMillis(coerceNonNegativeMillis(value))
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
val maxUpdates = maxUpdatesOverride ?: options.maxUpdates
|
|
26
|
+
if (maxUpdates != null) {
|
|
27
|
+
builder.setMaxUpdates(maxUpdates)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return builder.build()
|
|
31
|
+
}
|
package/android/src/main/java/com/margelo/nitro/nitrogeolocation/AndroidGeolocationConversions.kt
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import android.location.Address
|
|
4
|
+
import android.location.Location
|
|
5
|
+
|
|
6
|
+
internal fun Location.toGeolocationResponse(
|
|
7
|
+
providerOverride: LocationProviderUsed? = null
|
|
8
|
+
): GeolocationResponse {
|
|
9
|
+
val coords = GeolocationCoordinates(
|
|
10
|
+
latitude = latitude,
|
|
11
|
+
longitude = longitude,
|
|
12
|
+
altitude = altitudeValue(),
|
|
13
|
+
accuracy = accuracy.toDouble(),
|
|
14
|
+
altitudeAccuracy = altitudeAccuracyValue(),
|
|
15
|
+
heading = headingValue(),
|
|
16
|
+
speed = speedValue()
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
return GeolocationResponse(
|
|
20
|
+
coords = coords,
|
|
21
|
+
timestamp = time.toDouble(),
|
|
22
|
+
mocked = isMocked(),
|
|
23
|
+
provider = providerOverride ?: providerUsed()
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
internal fun Address.toGeocodedLocation(): GeocodedLocation? {
|
|
28
|
+
if (!hasLatitude() || !hasLongitude()) {
|
|
29
|
+
return null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return GeocodedLocation(
|
|
33
|
+
latitude = latitude,
|
|
34
|
+
longitude = longitude,
|
|
35
|
+
accuracy = null
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
internal fun Address.toReverseGeocodedAddress(): ReverseGeocodedAddress {
|
|
40
|
+
return ReverseGeocodedAddress(
|
|
41
|
+
country = countryName.nonBlankOrNull(),
|
|
42
|
+
region = adminArea.nonBlankOrNull(),
|
|
43
|
+
city = (locality ?: subAdminArea).nonBlankOrNull(),
|
|
44
|
+
district = subLocality.nonBlankOrNull(),
|
|
45
|
+
street = formatStreet(),
|
|
46
|
+
postalCode = postalCode.nonBlankOrNull(),
|
|
47
|
+
formattedAddress = formatAddressLines()
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
internal fun Address.formatStreet(): String? {
|
|
52
|
+
return listOf(subThoroughfare, thoroughfare)
|
|
53
|
+
.mapNotNull { it.nonBlankOrNull() }
|
|
54
|
+
.joinToString(" ")
|
|
55
|
+
.nonBlankOrNull()
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
internal fun Address.formatAddressLines(): String? {
|
|
59
|
+
if (maxAddressLineIndex < 0) {
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (0..maxAddressLineIndex)
|
|
64
|
+
.mapNotNull { index -> getAddressLine(index).nonBlankOrNull() }
|
|
65
|
+
.joinToString(", ")
|
|
66
|
+
.nonBlankOrNull()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
internal fun String?.nonBlankOrNull(): String? {
|
|
70
|
+
return this?.trim()?.takeIf { it.isNotEmpty() }
|
|
71
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import android.os.SystemClock
|
|
4
|
+
|
|
5
|
+
internal const val NO_LOCATION_PROVIDER_AVAILABLE_MESSAGE = "No location provider available"
|
|
6
|
+
internal const val NO_APPROXIMATE_LOCATION_PROVIDER_AVAILABLE_MESSAGE =
|
|
7
|
+
"No location provider is available for approximate location. " +
|
|
8
|
+
"ACCESS_COARSE_LOCATION is granted, but no enabled coarse-compatible provider is available."
|
|
9
|
+
|
|
10
|
+
internal const val INTERNAL_ERROR = -1.0
|
|
11
|
+
internal const val PERMISSION_DENIED = 1.0
|
|
12
|
+
internal const val POSITION_UNAVAILABLE = 2.0
|
|
13
|
+
internal const val TIMEOUT = 3.0
|
|
14
|
+
internal const val PLAY_SERVICE_NOT_AVAILABLE = 4.0
|
|
15
|
+
internal const val SETTINGS_NOT_SATISFIED = 5.0
|
|
16
|
+
|
|
17
|
+
internal fun createLocationAvailability(
|
|
18
|
+
available: Boolean,
|
|
19
|
+
reason: String?
|
|
20
|
+
): LocationAvailability {
|
|
21
|
+
return LocationAvailability(
|
|
22
|
+
available = available,
|
|
23
|
+
reason = reason
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
internal fun createLocationError(code: Double, message: String): LocationError {
|
|
28
|
+
return LocationError(
|
|
29
|
+
code = code,
|
|
30
|
+
message = message
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
internal fun createPlayServicesUnavailableError(): LocationError {
|
|
35
|
+
return createLocationError(
|
|
36
|
+
PLAY_SERVICE_NOT_AVAILABLE,
|
|
37
|
+
"Google Play Services location provider is not available."
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
internal fun createPositionTimeoutError(options: ParsedOptions): LocationError {
|
|
42
|
+
val timeoutSeconds = options.timeout / 1000.0
|
|
43
|
+
val message = String.format("Unable to fetch location within %.1fs.", timeoutSeconds)
|
|
44
|
+
return createLocationError(TIMEOUT, message)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
internal fun createRequestDeadlineElapsedRealtime(timeout: Double): Long {
|
|
48
|
+
val now = SystemClock.elapsedRealtime()
|
|
49
|
+
val timeoutMillis = coerceTimeoutMillis(timeout)
|
|
50
|
+
val maxTimeoutMillis = Long.MAX_VALUE - now
|
|
51
|
+
|
|
52
|
+
return if (timeoutMillis >= maxTimeoutMillis) {
|
|
53
|
+
Long.MAX_VALUE
|
|
54
|
+
} else {
|
|
55
|
+
now + timeoutMillis
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
internal fun remainingTimeoutMillis(deadlineElapsedRealtime: Long): Long {
|
|
60
|
+
return (deadlineElapsedRealtime - SystemClock.elapsedRealtime()).coerceAtLeast(0L)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
internal fun coerceTimeoutMillis(timeout: Double): Long {
|
|
64
|
+
return when {
|
|
65
|
+
timeout.isNaN() || timeout <= 0.0 -> 0L
|
|
66
|
+
timeout.isInfinite() || timeout >= Long.MAX_VALUE.toDouble() -> Long.MAX_VALUE
|
|
67
|
+
else -> timeout.toLong()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
internal fun coercePositiveMillis(value: Double): Long {
|
|
72
|
+
return when {
|
|
73
|
+
value.isNaN() || value <= 0.0 -> 1L
|
|
74
|
+
value.isInfinite() || value >= Long.MAX_VALUE.toDouble() -> Long.MAX_VALUE
|
|
75
|
+
else -> value.toLong()
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
internal fun coerceNonNegativeMillis(value: Double): Long {
|
|
80
|
+
return when {
|
|
81
|
+
value.isNaN() || value <= 0.0 -> 0L
|
|
82
|
+
value.isInfinite() || value >= Long.MAX_VALUE.toDouble() -> Long.MAX_VALUE
|
|
83
|
+
else -> value.toLong()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
import android.os.CancellationSignal
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.SystemClock
|
|
6
|
+
import java.util.UUID
|
|
7
|
+
|
|
8
|
+
internal data class ParsedOptions(
|
|
9
|
+
val timeout: Double,
|
|
10
|
+
val maximumAge: Double,
|
|
11
|
+
val androidAccuracy: AndroidAccuracyResolution,
|
|
12
|
+
val interval: Double,
|
|
13
|
+
val fastestInterval: Double,
|
|
14
|
+
val distanceFilter: Double,
|
|
15
|
+
val granularity: AndroidGranularity,
|
|
16
|
+
val waitForAccurateLocation: Boolean,
|
|
17
|
+
val maxUpdateAge: Double?,
|
|
18
|
+
val maxUpdateDelay: Double,
|
|
19
|
+
val maxUpdates: Int?
|
|
20
|
+
) {
|
|
21
|
+
companion object {
|
|
22
|
+
private const val DEFAULT_TIMEOUT = 10.0 * 60 * 1000 // 10 minutes in ms
|
|
23
|
+
private const val DEFAULT_MAXIMUM_AGE = 0.0
|
|
24
|
+
private const val DEFAULT_INTERVAL = 1000.0
|
|
25
|
+
private const val DEFAULT_FASTEST_INTERVAL = 100.0
|
|
26
|
+
private const val DEFAULT_DISTANCE_FILTER = 0.0
|
|
27
|
+
private const val DEFAULT_MAX_UPDATE_DELAY = 0.0
|
|
28
|
+
|
|
29
|
+
fun parse(
|
|
30
|
+
options: LocationRequestOptions?,
|
|
31
|
+
defaultMaximumAge: Double = DEFAULT_MAXIMUM_AGE
|
|
32
|
+
): ParsedOptions {
|
|
33
|
+
val enableHighAccuracy = options?.enableHighAccuracy ?: false
|
|
34
|
+
val maxUpdates = options?.maxUpdates?.let { value ->
|
|
35
|
+
if (!value.isFinite()) {
|
|
36
|
+
0
|
|
37
|
+
} else {
|
|
38
|
+
value.toInt()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return ParsedOptions(
|
|
43
|
+
timeout = options?.timeout ?: DEFAULT_TIMEOUT,
|
|
44
|
+
maximumAge = options?.maximumAge ?: defaultMaximumAge,
|
|
45
|
+
androidAccuracy = resolveAndroidAccuracy(
|
|
46
|
+
options?.accuracy,
|
|
47
|
+
enableHighAccuracy
|
|
48
|
+
),
|
|
49
|
+
interval = options?.interval ?: DEFAULT_INTERVAL,
|
|
50
|
+
fastestInterval = options?.fastestInterval ?: DEFAULT_FASTEST_INTERVAL,
|
|
51
|
+
distanceFilter = options?.distanceFilter ?: DEFAULT_DISTANCE_FILTER,
|
|
52
|
+
granularity = options?.granularity ?: AndroidGranularity.PERMISSION,
|
|
53
|
+
waitForAccurateLocation = options?.waitForAccurateLocation ?: false,
|
|
54
|
+
maxUpdateAge = options?.maxUpdateAge,
|
|
55
|
+
maxUpdateDelay = options?.maxUpdateDelay ?: DEFAULT_MAX_UPDATE_DELAY,
|
|
56
|
+
maxUpdates = maxUpdates
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
fun parseLastKnown(options: LocationRequestOptions?): ParsedOptions {
|
|
61
|
+
return parse(options, defaultMaximumAge = Double.POSITIVE_INFINITY)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
internal data class WatchSubscription(
|
|
67
|
+
val token: String,
|
|
68
|
+
val success: (GeolocationResponse) -> Unit,
|
|
69
|
+
val error: ((LocationError) -> Unit)?,
|
|
70
|
+
val options: ParsedOptions,
|
|
71
|
+
var deliveredUpdates: Int = 0
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
internal sealed interface PositionResult {
|
|
75
|
+
data class Success(val position: GeolocationResponse) : PositionResult
|
|
76
|
+
data class Failure(val error: LocationError) : PositionResult
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
internal data class PositionRequest(
|
|
80
|
+
val id: UUID,
|
|
81
|
+
val resolver: (PositionResult) -> Unit,
|
|
82
|
+
val options: ParsedOptions,
|
|
83
|
+
val handler: Handler,
|
|
84
|
+
val providers: List<String>,
|
|
85
|
+
val deadlineElapsedRealtime: Long,
|
|
86
|
+
var providerIndex: Int = 0,
|
|
87
|
+
var cancellationSignal: CancellationSignal? = null
|
|
88
|
+
) {
|
|
89
|
+
fun remainingTimeoutMillis(): Long {
|
|
90
|
+
return (deadlineElapsedRealtime - SystemClock.elapsedRealtime()).coerceAtLeast(0L)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -134,12 +134,15 @@ internal class AndroidLocationSettings(
|
|
|
134
134
|
private fun createProviderStatus(
|
|
135
135
|
googleLocationAccuracyEnabled: Boolean?
|
|
136
136
|
): LocationProviderStatus {
|
|
137
|
+
val googlePlayServicesAvailable = isGooglePlayServicesAvailable()
|
|
138
|
+
|
|
137
139
|
return LocationProviderStatus(
|
|
138
140
|
locationServicesEnabled = hasServicesEnabled(),
|
|
139
141
|
backgroundModeEnabled = hasBackgroundLocationPermission(),
|
|
140
142
|
gpsAvailable = isProviderEnabled(AndroidLocationManager.GPS_PROVIDER),
|
|
141
143
|
networkAvailable = isProviderEnabled(AndroidLocationManager.NETWORK_PROVIDER),
|
|
142
144
|
passiveAvailable = isProviderEnabled(AndroidLocationManager.PASSIVE_PROVIDER),
|
|
145
|
+
googlePlayServicesAvailable = googlePlayServicesAvailable,
|
|
143
146
|
googleLocationAccuracyEnabled = googleLocationAccuracyEnabled
|
|
144
147
|
)
|
|
145
148
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
package com.margelo.nitro.nitrogeolocation
|
|
2
|
+
|
|
3
|
+
internal enum class AndroidProviderRoute {
|
|
4
|
+
FUSED,
|
|
5
|
+
PLATFORM
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
internal fun selectAndroidProviderRoute(
|
|
9
|
+
locationProvider: LocationProvider?,
|
|
10
|
+
googlePlayServicesAvailable: Boolean
|
|
11
|
+
): AndroidProviderRoute {
|
|
12
|
+
if (locationProvider == LocationProvider.ANDROID_PLATFORM) {
|
|
13
|
+
return AndroidProviderRoute.PLATFORM
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return if (googlePlayServicesAvailable) {
|
|
17
|
+
AndroidProviderRoute.FUSED
|
|
18
|
+
} else {
|
|
19
|
+
AndroidProviderRoute.PLATFORM
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
internal fun selectAndroidFallbackRouteAfterFusedFailure(
|
|
24
|
+
@Suppress("UNUSED_PARAMETER") locationProvider: LocationProvider?
|
|
25
|
+
): AndroidProviderRoute {
|
|
26
|
+
return AndroidProviderRoute.PLATFORM
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private fun runAndroidProviderFallbackAfterFusedFailure(
|
|
30
|
+
locationProvider: LocationProvider?,
|
|
31
|
+
runPlatformFallback: () -> Unit,
|
|
32
|
+
failWithoutFallback: () -> Unit
|
|
33
|
+
) {
|
|
34
|
+
when (selectAndroidFallbackRouteAfterFusedFailure(locationProvider)) {
|
|
35
|
+
AndroidProviderRoute.PLATFORM -> runPlatformFallback()
|
|
36
|
+
AndroidProviderRoute.FUSED -> failWithoutFallback()
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
internal fun runAndroidCurrentPositionFallbackAfterFusedFailure(
|
|
41
|
+
locationProvider: LocationProvider?,
|
|
42
|
+
runPlatformFallback: () -> Unit,
|
|
43
|
+
failWithoutFallback: () -> Unit
|
|
44
|
+
) {
|
|
45
|
+
runAndroidProviderFallbackAfterFusedFailure(
|
|
46
|
+
locationProvider = locationProvider,
|
|
47
|
+
runPlatformFallback = runPlatformFallback,
|
|
48
|
+
failWithoutFallback = failWithoutFallback
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
internal fun runAndroidLastKnownPositionFallbackAfterFusedFailure(
|
|
53
|
+
locationProvider: LocationProvider?,
|
|
54
|
+
runPlatformFallback: () -> Unit,
|
|
55
|
+
failWithoutFallback: () -> Unit
|
|
56
|
+
) {
|
|
57
|
+
runAndroidProviderFallbackAfterFusedFailure(
|
|
58
|
+
locationProvider = locationProvider,
|
|
59
|
+
runPlatformFallback = runPlatformFallback,
|
|
60
|
+
failWithoutFallback = failWithoutFallback
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
internal fun runAndroidWatchPositionFallbackAfterFusedFailure(
|
|
65
|
+
locationProvider: LocationProvider?,
|
|
66
|
+
runPlatformFallback: () -> Unit,
|
|
67
|
+
failWithoutFallback: () -> Unit
|
|
68
|
+
) {
|
|
69
|
+
runAndroidProviderFallbackAfterFusedFailure(
|
|
70
|
+
locationProvider = locationProvider,
|
|
71
|
+
runPlatformFallback = runPlatformFallback,
|
|
72
|
+
failWithoutFallback = failWithoutFallback
|
|
73
|
+
)
|
|
74
|
+
}
|