react-native-bg-geolocation 0.2.0

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 (142) hide show
  1. package/BgGeolocation.podspec +39 -0
  2. package/LICENSE +20 -0
  3. package/README.md +366 -0
  4. package/android/build.gradle +69 -0
  5. package/android/src/main/AndroidManifest.xml +53 -0
  6. package/android/src/main/java/com/bggeolocation/BgGeolocationActivityRecognitionReceiver.kt +116 -0
  7. package/android/src/main/java/com/bggeolocation/BgGeolocationBootReceiver.kt +44 -0
  8. package/android/src/main/java/com/bggeolocation/BgGeolocationForegroundService.kt +373 -0
  9. package/android/src/main/java/com/bggeolocation/BgGeolocationGeofenceReceiver.kt +55 -0
  10. package/android/src/main/java/com/bggeolocation/BgGeolocationHeadlessTask.kt +138 -0
  11. package/android/src/main/java/com/bggeolocation/BgGeolocationModule.kt +1030 -0
  12. package/android/src/main/java/com/bggeolocation/BgGeolocationMotionStateMachine.kt +159 -0
  13. package/android/src/main/java/com/bggeolocation/BgGeolocationPackage.kt +31 -0
  14. package/android/src/main/res/drawable/bg_geo_notification.xml +9 -0
  15. package/ios/BgGeolocation.h +14 -0
  16. package/ios/BgGeolocation.mm +709 -0
  17. package/ios/engine/AtomicBoolean.swift +48 -0
  18. package/ios/engine/BGActivityChangeEvent.swift +20 -0
  19. package/ios/engine/BGActivityConfig.swift +71 -0
  20. package/ios/engine/BGAppConfig.swift +92 -0
  21. package/ios/engine/BGAppState.swift +147 -0
  22. package/ios/engine/BGAuthorization.swift +85 -0
  23. package/ios/engine/BGAuthorizationAlertPresenter.swift +39 -0
  24. package/ios/engine/BGAuthorizationConfig.swift +50 -0
  25. package/ios/engine/BGAuthorizationEvent.swift +40 -0
  26. package/ios/engine/BGBackgroundTaskManager.swift +143 -0
  27. package/ios/engine/BGCLRouter.swift +101 -0
  28. package/ios/engine/BGCallback.swift +19 -0
  29. package/ios/engine/BGConfig.swift +440 -0
  30. package/ios/engine/BGConfigModuleBase.swift +180 -0
  31. package/ios/engine/BGConfigOLD.swift +582 -0
  32. package/ios/engine/BGConnectivityChangeEvent.swift +15 -0
  33. package/ios/engine/BGCrashDetector.swift +122 -0
  34. package/ios/engine/BGCurrentPositionRequest.swift +87 -0
  35. package/ios/engine/BGDataStore.swift +75 -0
  36. package/ios/engine/BGDatabase.swift +677 -0
  37. package/ios/engine/BGDatabasePool.swift +220 -0
  38. package/ios/engine/BGDatabaseQueue.swift +215 -0
  39. package/ios/engine/BGDateUtils.swift +26 -0
  40. package/ios/engine/BGDeviceInfo.swift +54 -0
  41. package/ios/engine/BGDeviceManager.swift +65 -0
  42. package/ios/engine/BGEnabledChangeEvent.swift +11 -0
  43. package/ios/engine/BGEnv.swift +17 -0
  44. package/ios/engine/BGEventBus.swift +83 -0
  45. package/ios/engine/BGEventManager.swift +169 -0
  46. package/ios/engine/BGEventNames.swift +51 -0
  47. package/ios/engine/BGGeofence.swift +233 -0
  48. package/ios/engine/BGGeofenceDAO.swift +152 -0
  49. package/ios/engine/BGGeofenceEvent.swift +42 -0
  50. package/ios/engine/BGGeofenceLocationRequest.swift +94 -0
  51. package/ios/engine/BGGeofenceManager.swift +315 -0
  52. package/ios/engine/BGGeofenceTransition.swift +97 -0
  53. package/ios/engine/BGGeofencesChangeEvent.swift +26 -0
  54. package/ios/engine/BGGeolocationConfig.swift +136 -0
  55. package/ios/engine/BGHeartbeatEvent.swift +31 -0
  56. package/ios/engine/BGHeartbeatService.swift +51 -0
  57. package/ios/engine/BGHttpConfig.swift +105 -0
  58. package/ios/engine/BGHttpErrorCodes.swift +63 -0
  59. package/ios/engine/BGHttpEvent.swift +34 -0
  60. package/ios/engine/BGHttpRequest.swift +126 -0
  61. package/ios/engine/BGHttpResponse.swift +93 -0
  62. package/ios/engine/BGHttpService.swift +428 -0
  63. package/ios/engine/BGKalmanFilter.swift +105 -0
  64. package/ios/engine/BGLMActionNames.swift +55 -0
  65. package/ios/engine/BGLicenseManager.swift +26 -0
  66. package/ios/engine/BGLiveActivityManager.swift +327 -0
  67. package/ios/engine/BGLocation.swift +311 -0
  68. package/ios/engine/BGLocationAuthorization.swift +427 -0
  69. package/ios/engine/BGLocationDAO.swift +252 -0
  70. package/ios/engine/BGLocationErrors.swift +28 -0
  71. package/ios/engine/BGLocationEvent.swift +43 -0
  72. package/ios/engine/BGLocationFilter.swift +82 -0
  73. package/ios/engine/BGLocationFilterConfig.swift +57 -0
  74. package/ios/engine/BGLocationHelper.swift +54 -0
  75. package/ios/engine/BGLocationManager.swift +662 -0
  76. package/ios/engine/BGLocationMetricsEngine.swift +116 -0
  77. package/ios/engine/BGLocationRequestService.swift +459 -0
  78. package/ios/engine/BGLocationSatisfier.swift +14 -0
  79. package/ios/engine/BGLocationStreamEvent.swift +27 -0
  80. package/ios/engine/BGLog.swift +337 -0
  81. package/ios/engine/BGLogLevel.swift +26 -0
  82. package/ios/engine/BGLoggerConfig.swift +60 -0
  83. package/ios/engine/BGMotionActivity.swift +31 -0
  84. package/ios/engine/BGMotionActivityClassifier.swift +108 -0
  85. package/ios/engine/BGMotionActivityManagerAdapter.swift +40 -0
  86. package/ios/engine/BGMotionActivitySource.swift +46 -0
  87. package/ios/engine/BGMotionDetector.swift +377 -0
  88. package/ios/engine/BGMotionPermissionManager.swift +50 -0
  89. package/ios/engine/BGNativeLogger.swift +48 -0
  90. package/ios/engine/BGNotificaitons.swift +37 -0
  91. package/ios/engine/BGOdometer.swift +66 -0
  92. package/ios/engine/BGPersistenceConfig.swift +29 -0
  93. package/ios/engine/BGPolygonStreamRequest.swift +48 -0
  94. package/ios/engine/BGPowerSaveChangeEvent.swift +12 -0
  95. package/ios/engine/BGPropertySpec.swift +29 -0
  96. package/ios/engine/BGProviderChangeEvent.swift +31 -0
  97. package/ios/engine/BGQueue.swift +50 -0
  98. package/ios/engine/BGRPC.swift +194 -0
  99. package/ios/engine/BGReachability.swift +58 -0
  100. package/ios/engine/BGResultSet.swift +157 -0
  101. package/ios/engine/BGSchedule.swift +228 -0
  102. package/ios/engine/BGScheduleEvent.swift +13 -0
  103. package/ios/engine/BGScheduler.swift +116 -0
  104. package/ios/engine/BGSingleLocationRequest.swift +49 -0
  105. package/ios/engine/BGStreamLocationRequest.swift +42 -0
  106. package/ios/engine/BGTemplate.swift +54 -0
  107. package/ios/engine/BGTimerService.swift +46 -0
  108. package/ios/engine/BGTrackingAudioManager.swift +286 -0
  109. package/ios/engine/BGTrackingService.swift +879 -0
  110. package/ios/engine/BGWatchPositionRequest.swift +63 -0
  111. package/ios/engine/DatabaseQueue.swift +47 -0
  112. package/ios/engine/LogQuery.swift +10 -0
  113. package/ios/engine/SQLQuery.swift +65 -0
  114. package/ios/engine/TransistorAuthorizationToken.swift +182 -0
  115. package/ios/liveactivity/BGLiveTrackingAttributes.swift +52 -0
  116. package/ios/locationpush/BGLocationPushDeliverer.swift +260 -0
  117. package/ios/locationpush/BGLocationPushService.swift +161 -0
  118. package/ios/locationpush/BGLocationPushShared.swift +98 -0
  119. package/ios/locationpush/BGLocationPushSocketClient.swift +198 -0
  120. package/lib/module/NativeBgGeolocation.js +5 -0
  121. package/lib/module/NativeBgGeolocation.js.map +1 -0
  122. package/lib/module/events.js +20 -0
  123. package/lib/module/events.js.map +1 -0
  124. package/lib/module/index.js +706 -0
  125. package/lib/module/index.js.map +1 -0
  126. package/lib/module/package.json +1 -0
  127. package/lib/module/types.js +2 -0
  128. package/lib/module/types.js.map +1 -0
  129. package/lib/typescript/package.json +1 -0
  130. package/lib/typescript/src/NativeBgGeolocation.d.ts +57 -0
  131. package/lib/typescript/src/NativeBgGeolocation.d.ts.map +1 -0
  132. package/lib/typescript/src/events.d.ts +18 -0
  133. package/lib/typescript/src/events.d.ts.map +1 -0
  134. package/lib/typescript/src/index.d.ts +238 -0
  135. package/lib/typescript/src/index.d.ts.map +1 -0
  136. package/lib/typescript/src/types.d.ts +229 -0
  137. package/lib/typescript/src/types.d.ts.map +1 -0
  138. package/package.json +141 -0
  139. package/src/NativeBgGeolocation.ts +236 -0
  140. package/src/events.ts +17 -0
  141. package/src/index.tsx +935 -0
  142. package/src/types.ts +254 -0
@@ -0,0 +1,377 @@
1
+ import Foundation
2
+ import CoreMotion
3
+ import CoreLocation
4
+
5
+ @objc public class BGMotionDetector: NSObject, BGMotionActivitySourceDelegate {
6
+
7
+ private static var _sharedInstance: BGMotionDetector?
8
+ private static let instanceLock = NSLock()
9
+
10
+ @objc public class func sharedInstance() -> BGMotionDetector {
11
+ instanceLock.lock()
12
+ defer { instanceLock.unlock() }
13
+ if _sharedInstance == nil { _sharedInstance = BGMotionDetector() }
14
+ return _sharedInstance!
15
+ }
16
+
17
+ public class func motionAuthorizationStatus() -> CMAuthorizationStatus {
18
+ return CMMotionActivityManager.authorizationStatus()
19
+ }
20
+
21
+ @objc public class func motionHardwareAvailable() -> Bool {
22
+ return CMMotionActivityManager.isActivityAvailable()
23
+ }
24
+
25
+ // MARK: - State
26
+
27
+ @objc public var enabled: Bool = false
28
+ @objc public var debug: Bool = false
29
+ @objc public var isMoving: Bool = false
30
+ @objc public var isUpdatingMotionActivity: Bool = false
31
+ @objc public var useM7IfAvailable: Bool = true
32
+ @objc public var useAccelerometerFallback: Bool = true
33
+ @objc public var autoRequestMotionPermission: Bool = true
34
+
35
+ // Activity state
36
+ @objc public var motionType: String = "unknown"
37
+ @objc public var previousMotionType: String = "unknown"
38
+ @objc public var statedActivity: BGMotionActivity?
39
+ @objc public var currentActivity: BGMotionActivity?
40
+ @objc public var motionActivity: CMMotionActivity?
41
+ @objc public var detectorState: String = "stopped"
42
+ @objc public var history: [BGMotionActivity] = []
43
+ @objc public var diagnostics: [String: Any] = [:]
44
+
45
+ // Speed/location state
46
+ @objc public var location: CLLocation?
47
+ @objc public var currentSpeed: Double = 0
48
+
49
+ // Confidence tracking
50
+ @objc public var lastConfidence: Int = 0
51
+ @objc public var lastEmittedType: String = "unknown"
52
+ @objc public var lastEmittedConfidence: Int = 0
53
+ @objc public var lastTypeChangeAt: Date?
54
+ @objc public var confidenceDeltaThreshold: Int = 1
55
+ @objc public var minimumMotionActivityConfidence: Int = 1
56
+
57
+ // Sensor state
58
+ public var acceleration: CMAcceleration = CMAcceleration()
59
+ @objc public var accelerometerUpdateInterval: TimeInterval = 0.1
60
+ @objc public var samplesPerInterval: Int = 50
61
+ @objc public var detectMotionWindow: TimeInterval = 5.0
62
+
63
+ // M7 detection thresholds
64
+ @objc public var isUsingM7: Bool = false
65
+ @objc public var M7Authorized: Bool = false
66
+
67
+ // Motion probe settings (adaptive polling)
68
+ @objc public var probeMinInterval: TimeInterval = 5.0
69
+ @objc public var probeCooldownBase: TimeInterval = 15.0
70
+ @objc public var probeCooldownMax: TimeInterval = 120.0
71
+ @objc public var probeFreshSpeedAge: TimeInterval = 10.0
72
+ @objc public var probeFreshSpeedThreshold: Double = 0.5
73
+ @objc public var probeHighConfidence: Int = 75
74
+ @objc public var probeDwellWins: Int = 3
75
+
76
+ // Stop detection
77
+ @objc public var stopDwellWins: Int = 3
78
+ @objc public var stopHighConfidence: Int = 90
79
+ @objc public var sdConsecutiveStillWins: Int = 0
80
+ @objc public var mdConsecutiveMovingWins: Int = 0
81
+ @objc public var mdBackoffLevel: Int = 0
82
+ @objc public var mdLastProbeAt: Date?
83
+ @objc public var mdLastSpeedAt: Date?
84
+ @objc public var mdLastSpeedValue: Double = 0
85
+ @objc public var mdSuppressUntil: Date?
86
+
87
+ // Type debounce
88
+ @objc public var motionDebounceInterval: TimeInterval = 1.0
89
+ @objc public var typeDebounceInterval: TimeInterval = 2.0
90
+ @objc public var motionDetectionInterval: TimeInterval = 10.0
91
+
92
+ // Speed thresholds
93
+ @objc public var minimumSpeed: Double = 0.5
94
+ @objc public var maximumWalkingSpeed: Double = 3.0
95
+ @objc public var maximumRunningSpeed: Double = 10.0
96
+
97
+ // Sensors
98
+ @objc public var motionManager: CMMotionManager?
99
+ @objc public var motionActivityManager: CMMotionActivityManager?
100
+ @objc public var activitySource: BGMotionActivitySource?
101
+ @objc public var activityClassifier: BGMotionActivityClassifier?
102
+ @objc public var permissionMgr: BGMotionPermissionManager?
103
+ @objc public var activityProvider: AnyObject?
104
+
105
+ var accelerometerQueue: OperationQueue?
106
+ var windowTimer: Timer?
107
+ var stateQueue: DispatchQueue?
108
+
109
+ @objc public var accelerationChangedBlock: ((CMAccelerometerData) -> Void)?
110
+ @objc public var motionActivityChangedBlock: ((CMMotionActivity) -> Void)?
111
+
112
+ @objc public override init() {
113
+ super.init()
114
+ stateQueue = DispatchQueue(label: "BGMotionDetector.state")
115
+ activityClassifier = BGMotionActivityClassifier()
116
+ activityClassifier?.configureWithSampleInterval(0.1, windowSeconds: 5.0)
117
+ permissionMgr = BGMotionPermissionManager()
118
+ }
119
+
120
+ // MARK: - Authorization
121
+
122
+ @objc public func isAccelerometerAvailable() -> Bool {
123
+ return motionManager?.isAccelerometerAvailable ?? false
124
+ }
125
+
126
+ @objc public func isGyroAvailable() -> Bool {
127
+ return motionManager?.isGyroAvailable ?? false
128
+ }
129
+
130
+ @objc public func isDeviceMotionAvailable() -> Bool {
131
+ return motionManager?.isDeviceMotionAvailable ?? false
132
+ }
133
+
134
+ @objc public func isMagnetometerAvailable() -> Bool {
135
+ return motionManager?.isMagnetometerAvailable ?? false
136
+ }
137
+
138
+ @objc public func isConfidentlyStationary() -> Bool {
139
+ guard motionType == "still" else { return false }
140
+ return sdConsecutiveStillWins >= stopDwellWins
141
+ }
142
+
143
+ // MARK: - Lifecycle
144
+
145
+ @objc public func start() {
146
+ guard !enabled else { return }
147
+ enabled = true
148
+ detectorState = "running"
149
+
150
+ motionManager = CMMotionManager()
151
+ motionManager?.accelerometerUpdateInterval = accelerometerUpdateInterval
152
+
153
+ if useM7IfAvailable && BGMotionDetector.motionHardwareAvailable() {
154
+ startM7Detection()
155
+ } else if useAccelerometerFallback {
156
+ startSensorDetection()
157
+ }
158
+ }
159
+
160
+ @objc public func stop() {
161
+ guard enabled else { return }
162
+ enabled = false
163
+ detectorState = "stopped"
164
+ stopSensorDetection()
165
+ activitySource?.stop()
166
+ windowTimer?.invalidate()
167
+ windowTimer = nil
168
+ }
169
+
170
+ @objc public func startSensorDetection() {
171
+ guard let mgr = motionManager, mgr.isAccelerometerAvailable else { return }
172
+ accelerometerQueue = OperationQueue()
173
+ accelerometerQueue?.name = "BGMotionDetector.accelerometer"
174
+ mgr.startAccelerometerUpdates(to: accelerometerQueue!) { [weak self] data, error in
175
+ guard let self = self, let data = data else { return }
176
+ self.activityClassifier?.ingestAcceleration(data)
177
+ self.accelerationChangedBlock?(data)
178
+ }
179
+
180
+ if mgr.isGyroAvailable {
181
+ mgr.startGyroUpdates(to: accelerometerQueue!) { [weak self] data, error in
182
+ guard let self = self, let data = data else { return }
183
+ self.activityClassifier?.ingestRotationRate(data)
184
+ }
185
+ }
186
+
187
+ scheduleWindowTimer()
188
+ }
189
+
190
+ @objc public func stopSensorDetection() {
191
+ motionManager?.stopAccelerometerUpdates()
192
+ motionManager?.stopGyroUpdates()
193
+ accelerometerQueue?.cancelAllOperations()
194
+ accelerometerQueue = nil
195
+ windowTimer?.invalidate()
196
+ windowTimer = nil
197
+ }
198
+
199
+ private func startM7Detection() {
200
+ isUsingM7 = true
201
+ let queue = DispatchQueue(label: "BGMotionDetector.M7")
202
+ activitySource = BGMotionActivitySource()
203
+ activitySource?.delegate = self
204
+ activitySource?.start()
205
+ }
206
+
207
+ private func scheduleWindowTimer() {
208
+ DispatchQueue.main.async {
209
+ self.windowTimer?.invalidate()
210
+ self.windowTimer = Timer.scheduledTimer(withTimeInterval: self.detectMotionWindow, repeats: true) { [weak self] _ in
211
+ self?._calculateMotionTypeLocked()
212
+ }
213
+ }
214
+ }
215
+
216
+ // MARK: - Motion type calculation
217
+
218
+ @objc public func calculateMotionType() {
219
+ stateQueue?.async { self._calculateMotionTypeLocked() }
220
+ }
221
+
222
+ @objc public func _calculateMotionTypeLocked() {
223
+ guard let classifier = activityClassifier, classifier.isWindowReady() else { return }
224
+ let newType = classifier.classifyWithSpeed(currentSpeed)
225
+ _applyMotionType(fromClassifier: newType, confidence: 80, emit: true)
226
+ }
227
+
228
+ @objc public func _applyMotionType(fromClassifier type: String, confidence: Int, emit: Bool) {
229
+ previousMotionType = motionType
230
+ motionType = type
231
+
232
+ if type != previousMotionType {
233
+ lastTypeChangeAt = Date()
234
+ sdConsecutiveStillWins = 0
235
+ mdConsecutiveMovingWins = 0
236
+ }
237
+
238
+ if type == "still" {
239
+ sdConsecutiveStillWins += 1
240
+ mdConsecutiveMovingWins = 0
241
+ } else {
242
+ mdConsecutiveMovingWins += 1
243
+ sdConsecutiveStillWins = 0
244
+ }
245
+
246
+ lastEmittedType = type
247
+ lastEmittedConfidence = confidence
248
+ lastConfidence = confidence
249
+
250
+ if emit {
251
+ let activity = BGMotionActivity(type: type, confidence: confidence)
252
+ currentActivity = activity
253
+ motionActivityChangedBlock.map { _ in }
254
+ NotificationCenter.default.post(name: NSNotification.Name("BGMotionDetectorDidUpdateActivity"), object: activity)
255
+ }
256
+ }
257
+
258
+ @objc public func _applySamplingIntervalLocked(_ interval: TimeInterval) {
259
+ accelerometerUpdateInterval = interval
260
+ motionManager?.accelerometerUpdateInterval = interval
261
+ }
262
+
263
+ @objc public func _recalcFromM7Locked() {
264
+ guard let activity = motionActivity else { return }
265
+ var type = "unknown"
266
+ if activity.stationary { type = "still" }
267
+ else if activity.walking { type = "walking" }
268
+ else if activity.running { type = "running" }
269
+ else if activity.automotive { type = "in_vehicle" }
270
+ else if activity.cycling { type = "on_bicycle" }
271
+ _applyMotionType(fromClassifier: type, confidence: Int(activity.confidence.rawValue) * 25, emit: true)
272
+ }
273
+
274
+ @objc public func _maybeAdjustSamplingForActivity(_ type: String) {
275
+ switch type {
276
+ case "still":
277
+ _applySamplingIntervalLocked(0.5)
278
+ case "walking", "running":
279
+ _applySamplingIntervalLocked(0.1)
280
+ default:
281
+ _applySamplingIntervalLocked(0.2)
282
+ }
283
+ }
284
+
285
+ // MARK: - BGMotionActivitySourceDelegate
286
+
287
+ @objc public func activitySource(_ source: BGMotionActivitySource, didUpdate activity: CMMotionActivity) {
288
+ stateQueue?.async {
289
+ self.motionActivity = activity
290
+ self._recalcFromM7Locked()
291
+ self._maybeAdjustSamplingForActivity(self.motionType)
292
+ }
293
+ }
294
+
295
+ @objc public func activitySourceDidUpdate(_ activity: BGMotionActivity) {
296
+ stateQueue?.async {
297
+ self.motionActivity = nil
298
+ self._recalcFromM7Locked()
299
+ self._maybeAdjustSamplingForActivity(self.motionType)
300
+ }
301
+ }
302
+
303
+ // MARK: - Location / speed
304
+
305
+ @objc public func setLocation(_ loc: CLLocation, isMoving moving: Bool) {
306
+ location = loc
307
+ currentSpeed = max(0, loc.speed)
308
+ isMoving = moving
309
+ activityClassifier?.updateSpeed(currentSpeed)
310
+ }
311
+
312
+ @objc public func updateSpeed(_ speed: Double) {
313
+ currentSpeed = speed
314
+ activityClassifier?.updateSpeed(speed)
315
+ }
316
+
317
+ @objc public func isMoving(_ moving: Bool) -> Bool {
318
+ return isMoving
319
+ }
320
+
321
+ @objc public func threadSafeMotionType() -> String {
322
+ var result = "unknown"
323
+ stateQueue?.sync { result = self.motionType }
324
+ return result
325
+ }
326
+
327
+ @objc public func threadSafeMotionActivity() -> BGMotionActivity? {
328
+ var result: BGMotionActivity?
329
+ stateQueue?.sync { result = self.currentActivity }
330
+ return result
331
+ }
332
+
333
+ @objc public func classifyWithSpeed(_ speed: Double) -> String {
334
+ return activityClassifier?.classifyWithSpeed(speed) ?? "unknown"
335
+ }
336
+
337
+ @objc public func shouldRequestLocationProbe() -> Bool {
338
+ guard enabled else { return false }
339
+ if let suppressUntil = mdSuppressUntil, Date() < suppressUntil { return false }
340
+ if let lastProbe = mdLastProbeAt {
341
+ return Date().timeIntervalSince(lastProbe) >= probeMinInterval
342
+ }
343
+ return true
344
+ }
345
+
346
+ @objc public func noteWillRequestLocationProbe() {
347
+ mdLastProbeAt = Date()
348
+ }
349
+
350
+ public func requestMotionPermission(_ completion: @escaping (CMAuthorizationStatus) -> Void) {
351
+ permissionMgr?.requestPermission(completion: completion)
352
+ }
353
+
354
+ @objc public func queryMotionActivityHistory() {
355
+ guard let mgr = motionActivityManager else { return }
356
+ let end = Date()
357
+ let start = end.addingTimeInterval(-3600)
358
+ mgr.queryActivityStarting(from: start, to: end, to: OperationQueue.main) { [weak self] (activities: [CMMotionActivity]?, error: Error?) in
359
+ guard let self = self, let acts = activities else { return }
360
+ for act in acts {
361
+ self.motionActivityChangedBlock?(act)
362
+ }
363
+ }
364
+ }
365
+
366
+ @objc public func getDiagnosticsData() -> [String: Any] {
367
+ return [
368
+ "motionType": motionType,
369
+ "isMoving": isMoving,
370
+ "enabled": enabled,
371
+ "lastEmittedType": lastEmittedType,
372
+ "lastEmittedConfidence": lastEmittedConfidence,
373
+ "sdConsecutiveStillWins": sdConsecutiveStillWins,
374
+ "mdConsecutiveMovingWins": mdConsecutiveMovingWins
375
+ ]
376
+ }
377
+ }
@@ -0,0 +1,50 @@
1
+ import Foundation
2
+ import CoreMotion
3
+
4
+ @objc public class BGMotionPermissionManager: NSObject {
5
+
6
+ private static var _sharedInstance: BGMotionPermissionManager?
7
+ private static let lock = NSLock()
8
+
9
+ private let motionManager = CMMotionActivityManager()
10
+
11
+ @objc public class func sharedInstance() -> BGMotionPermissionManager {
12
+ lock.lock()
13
+ defer { lock.unlock() }
14
+ if _sharedInstance == nil {
15
+ _sharedInstance = BGMotionPermissionManager()
16
+ }
17
+ return _sharedInstance!
18
+ }
19
+
20
+ @objc public override init() {
21
+ super.init()
22
+ }
23
+
24
+ public class func authorizationStatus() -> CMAuthorizationStatus {
25
+ return CMMotionActivityManager.authorizationStatus()
26
+ }
27
+
28
+ public func requestPermission(completion: @escaping (_ status: CMAuthorizationStatus) -> Void) {
29
+ motionManager.queryActivityStarting(from: Date(), to: Date(), to: .main) { _, _ in
30
+ completion(CMMotionActivityManager.authorizationStatus())
31
+ self.motionManager.stopActivityUpdates()
32
+ }
33
+ }
34
+
35
+ @objc public func isAuthorized() -> Bool {
36
+ return CMMotionActivityManager.authorizationStatus() == .authorized
37
+ }
38
+
39
+ @objc public func isDenied() -> Bool {
40
+ return CMMotionActivityManager.authorizationStatus() == .denied
41
+ }
42
+
43
+ @objc public func isRestricted() -> Bool {
44
+ return CMMotionActivityManager.authorizationStatus() == .restricted
45
+ }
46
+
47
+ @objc public func notDetermined() -> Bool {
48
+ return CMMotionActivityManager.authorizationStatus() == .notDetermined
49
+ }
50
+ }
@@ -0,0 +1,48 @@
1
+ import Foundation
2
+ import os.log
3
+
4
+ @objc public class BGNativeLogger: NSObject {
5
+
6
+ private static let subsystem = "com.transistorsoft.BGLocationManager"
7
+ private static let category = "general"
8
+
9
+ @objc public class func log(_ level: Int, tag: String, message: String) {
10
+ if #available(iOS 14.0, *) {
11
+ let logger = Logger(subsystem: subsystem, category: tag)
12
+ switch level {
13
+ case 0: break
14
+ case 1: logger.error("\(message)")
15
+ case 2: logger.warning("\(message)")
16
+ case 3: logger.info("\(message)")
17
+ case 4: logger.debug("\(message)")
18
+ default: logger.log("\(message)")
19
+ }
20
+ } else {
21
+ let prefix: String
22
+ switch level {
23
+ case 1: prefix = "ERROR"
24
+ case 2: prefix = "WARN"
25
+ case 3: prefix = "INFO"
26
+ case 4: prefix = "DEBUG"
27
+ default: prefix = "LOG"
28
+ }
29
+ print("[\(prefix)] [\(tag)] \(message)")
30
+ }
31
+ }
32
+
33
+ @objc public class func error(_ tag: String, message: String) {
34
+ log(1, tag: tag, message: message)
35
+ }
36
+
37
+ @objc public class func warn(_ tag: String, message: String) {
38
+ log(2, tag: tag, message: message)
39
+ }
40
+
41
+ @objc public class func info(_ tag: String, message: String) {
42
+ log(3, tag: tag, message: message)
43
+ }
44
+
45
+ @objc public class func debug(_ tag: String, message: String) {
46
+ log(4, tag: tag, message: message)
47
+ }
48
+ }
@@ -0,0 +1,37 @@
1
+ import Foundation
2
+ import UserNotifications
3
+
4
+ @objc public final class BGNotifications: NSObject {
5
+
6
+ @objc public var prepared: Bool = false
7
+
8
+ @objc public static let shared = BGNotifications()
9
+
10
+ @objc public func prepareIfNeeded(_ context: Any?) {
11
+ guard !prepared else { return }
12
+ prepared = true
13
+ let center = UNUserNotificationCenter.current()
14
+ center.delegate = self
15
+ center.getNotificationSettings { settings in
16
+ if settings.authorizationStatus != .notDetermined {
17
+ NSLog("[TS] notif status=%ld", settings.authorizationStatus.rawValue)
18
+ } else {
19
+ center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
20
+ NSLog("[TS] notif auth: granted=%d err=%@", granted, error?.localizedDescription ?? "")
21
+ }
22
+ }
23
+ }
24
+ }
25
+
26
+ public func userNotificationCenter(_ center: UNUserNotificationCenter,
27
+ willPresent notification: UNNotification,
28
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
29
+ if #available(iOS 14.0, *) {
30
+ completionHandler([.banner, .list, .sound])
31
+ } else {
32
+ completionHandler([.alert, .badge, .sound])
33
+ }
34
+ }
35
+ }
36
+
37
+ extension BGNotifications: UNUserNotificationCenterDelegate {}
@@ -0,0 +1,66 @@
1
+ import Foundation
2
+ import CoreLocation
3
+
4
+ @objc public class BGOdometer: NSObject {
5
+
6
+ private static var _sharedInstance: BGOdometer?
7
+ private static let lock = NSLock()
8
+
9
+ @objc public var value: Double = 0
10
+ private var lastLocation: CLLocation?
11
+ private let userDefaultsKey = "BGLocationManager_odometer"
12
+
13
+ @objc public class func sharedInstance() -> BGOdometer {
14
+ lock.lock()
15
+ defer { lock.unlock() }
16
+ if _sharedInstance == nil {
17
+ _sharedInstance = BGOdometer()
18
+ }
19
+ return _sharedInstance!
20
+ }
21
+
22
+ @objc public override init() {
23
+ super.init()
24
+ value = UserDefaults.standard.double(forKey: userDefaultsKey)
25
+ }
26
+
27
+ @objc public func addDistance(from location: CLLocation) -> Double {
28
+ guard let last = lastLocation else {
29
+ lastLocation = location
30
+ return value
31
+ }
32
+ let delta = location.distance(from: last)
33
+ value += delta
34
+ lastLocation = location
35
+ persist()
36
+ return value
37
+ }
38
+
39
+ @objc public func setOdometer(_ newValue: Double, location: CLLocation?) {
40
+ value = newValue
41
+ lastLocation = location
42
+ persist()
43
+ }
44
+
45
+ @objc public func reset() {
46
+ value = 0
47
+ lastLocation = nil
48
+ persist()
49
+ }
50
+
51
+ @objc public func getOdometer() -> Double {
52
+ return value
53
+ }
54
+
55
+ @objc public func setLastLocation(_ location: CLLocation?) {
56
+ lastLocation = location
57
+ }
58
+
59
+ @objc public func lastKnownLocation() -> CLLocation? {
60
+ return lastLocation
61
+ }
62
+
63
+ private func persist() {
64
+ UserDefaults.standard.set(value, forKey: userDefaultsKey)
65
+ }
66
+ }
@@ -0,0 +1,29 @@
1
+ import Foundation
2
+
3
+ @objc public class BGPersistenceConfig: BGConfigModuleBase {
4
+
5
+ @objc public var maxDaysToPersist: Int = 1
6
+ @objc public var maxRecordsToPersist: Int = -1
7
+ @objc public var persistMode: Int = 2
8
+ @objc public var locationsOrderDirection: String = "ASC"
9
+
10
+ @objc public override func applyDefaults() {
11
+ maxDaysToPersist = 1
12
+ maxRecordsToPersist = -1
13
+ persistMode = 2
14
+ locationsOrderDirection = "ASC"
15
+ }
16
+
17
+ @objc public override func propertySpecs() -> [BGPropertySpecImpl] {
18
+ return [
19
+ BGPropertySpec(name: "maxDaysToPersist", type: "int"),
20
+ BGPropertySpec(name: "maxRecordsToPersist", type: "int"),
21
+ BGPropertySpec(name: "persistMode", type: "int"),
22
+ BGPropertySpec(name: "locationsOrderDirection", type: "string")
23
+ ]
24
+ }
25
+
26
+ @objc public override var description: String {
27
+ return "<BGPersistenceConfig maxDaysToPersist=\(maxDaysToPersist) maxRecordsToPersist=\(maxRecordsToPersist)>"
28
+ }
29
+ }
@@ -0,0 +1,48 @@
1
+ import Foundation
2
+ import CoreLocation
3
+
4
+ @objc public class BGPolygonStreamRequest: NSObject {
5
+
6
+ @objc public var identifier: String
7
+ @objc public var vertices: [[CLLocationDegrees]]
8
+ @objc public var interval: Double
9
+ @objc public var success: ((Any?) -> Void)?
10
+ @objc public var failure: ((Int) -> Void)?
11
+
12
+ @objc public init(
13
+ identifier: String,
14
+ vertices: [[CLLocationDegrees]],
15
+ interval: Double,
16
+ success: @escaping (Any?) -> Void,
17
+ failure: @escaping (Int) -> Void
18
+ ) {
19
+ self.identifier = identifier
20
+ self.vertices = vertices
21
+ self.interval = interval
22
+ self.success = success
23
+ self.failure = failure
24
+ super.init()
25
+ }
26
+
27
+ @objc public override init() {
28
+ identifier = UUID().uuidString
29
+ vertices = []
30
+ interval = 1000
31
+ super.init()
32
+ }
33
+
34
+ @objc public func containsCoordinate(_ coord: CLLocationCoordinate2D) -> Bool {
35
+ guard vertices.count >= 3 else { return false }
36
+ var inside = false
37
+ var j = vertices.count - 1
38
+ for i in 0..<vertices.count {
39
+ let xi = vertices[i][0], yi = vertices[i][1]
40
+ let xj = vertices[j][0], yj = vertices[j][1]
41
+ let intersect = ((yi > coord.latitude) != (yj > coord.latitude)) &&
42
+ (coord.longitude < (xj - xi) * (coord.latitude - yi) / (yj - yi) + xi)
43
+ if intersect { inside = !inside }
44
+ j = i
45
+ }
46
+ return inside
47
+ }
48
+ }
@@ -0,0 +1,12 @@
1
+ import Foundation
2
+
3
+ @objc public final class BGPowerSaveChangeEvent: NSObject {
4
+
5
+ @objc public private(set) var isPowerSaveMode: Bool
6
+
7
+ @objc public override init() {
8
+ self.isPowerSaveMode = false
9
+ super.init()
10
+ self.isPowerSaveMode = ProcessInfo.processInfo.isLowPowerModeEnabled
11
+ }
12
+ }