expo-beacon 0.6.11 → 0.6.12
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.
|
@@ -459,8 +459,10 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
459
459
|
|
|
460
460
|
private fun scheduleTimeoutIfConfigured(region: Region) {
|
|
461
461
|
val seconds = beaconTimeouts[region.uniqueId] ?: return
|
|
462
|
-
//
|
|
463
|
-
|
|
462
|
+
// If a timer is already running, don't reset it. Miss-based exits clear
|
|
463
|
+
// enteredRegions without cancelling the timer, so a subsequent re-entry
|
|
464
|
+
// must not restart the clock — doing so would defer the timeout indefinitely.
|
|
465
|
+
if (timeoutRunnables.containsKey(region.uniqueId)) return
|
|
464
466
|
val runnable = Runnable {
|
|
465
467
|
timeoutRunnables.remove(region.uniqueId)
|
|
466
468
|
// Fire unconditionally. A miss-based exit may have cleared enteredRegions before
|
|
@@ -850,6 +850,7 @@ public class ExpoBeaconModule: Module {
|
|
|
850
850
|
postBeaconNotification(identifier: identifier, eventType: "enter")
|
|
851
851
|
scheduleEddystoneTimeout(identifier: identifier, namespace: ns, instance: inst)
|
|
852
852
|
case .exit:
|
|
853
|
+
smoothedDistances.removeValue(forKey: identifier)
|
|
853
854
|
cancelEddystoneTimeout(identifier: identifier)
|
|
854
855
|
sendLoggedEvent("onEddystoneExit", [
|
|
855
856
|
"identifier": identifier,
|
|
@@ -1078,6 +1079,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1078
1079
|
eddystoneEnterCounters[identifier] = 0
|
|
1079
1080
|
eddystoneExitCounters[identifier] = 0
|
|
1080
1081
|
eddystoneLatestSeen.removeValue(forKey: identifier)
|
|
1082
|
+
smoothedDistances.removeValue(forKey: identifier)
|
|
1081
1083
|
// Do NOT cancel the timeout here — same reason as iBeacon miss-based exit.
|
|
1082
1084
|
|
|
1083
1085
|
let ns = paired["namespace"] as? String ?? ""
|
|
@@ -1098,9 +1100,10 @@ public class ExpoBeaconModule: Module {
|
|
|
1098
1100
|
// MARK: - Timeout timer helpers
|
|
1099
1101
|
|
|
1100
1102
|
private func scheduleBeaconTimeout(identifier: String, beacon: CLBeacon) {
|
|
1101
|
-
//
|
|
1102
|
-
|
|
1103
|
-
|
|
1103
|
+
// If a timer is already running, don't reset it. Miss-based exits clear
|
|
1104
|
+
// enteredRegions without cancelling the timer, so a subsequent re-entry
|
|
1105
|
+
// must not restart the clock — doing so would defer the timeout indefinitely.
|
|
1106
|
+
guard beaconTimeoutTimers[identifier] == nil else { return }
|
|
1104
1107
|
|
|
1105
1108
|
let paired = loadPairedBeaconsRaw().first { ($0["identifier"] as? String) == identifier }
|
|
1106
1109
|
guard let seconds = paired?["timeoutSeconds"] as? Int, seconds > 0 else { return }
|
|
@@ -1123,8 +1126,8 @@ public class ExpoBeaconModule: Module {
|
|
|
1123
1126
|
}
|
|
1124
1127
|
|
|
1125
1128
|
private func scheduleEddystoneTimeout(identifier: String, namespace: String, instance: String) {
|
|
1126
|
-
|
|
1127
|
-
eddystoneTimeoutTimers
|
|
1129
|
+
// If a timer is already running, don't reset it — same reason as iBeacon timeout.
|
|
1130
|
+
guard eddystoneTimeoutTimers[identifier] == nil else { return }
|
|
1128
1131
|
|
|
1129
1132
|
let paired = loadPairedEddystonesRaw().first { ($0["identifier"] as? String) == identifier }
|
|
1130
1133
|
guard let seconds = paired?["timeoutSeconds"] as? Int, seconds > 0 else { return }
|
|
@@ -1197,16 +1200,21 @@ public class ExpoBeaconModule: Module {
|
|
|
1197
1200
|
// MARK: - Distance smoothing + enter/exit hysteresis
|
|
1198
1201
|
|
|
1199
1202
|
/// Apply exponential moving average (EMA) smoothing to a raw distance reading.
|
|
1200
|
-
///
|
|
1203
|
+
/// If the reading is a large jump (> DISTANCE_JUMP_FACTOR), resets the EMA to the new
|
|
1204
|
+
/// value instead of rejecting it — this ensures distance events keep flowing when the
|
|
1205
|
+
/// user moves away from a beacon, rather than freezing because the EMA is stuck at the
|
|
1206
|
+
/// old close-range value and every new far-range reading is rejected.
|
|
1201
1207
|
private func smoothDistance(identifier: String, rawDistance: Double) -> Double? {
|
|
1202
1208
|
guard let prev = smoothedDistances[identifier] else {
|
|
1203
1209
|
smoothedDistances[identifier] = rawDistance
|
|
1204
1210
|
return rawDistance
|
|
1205
1211
|
}
|
|
1206
|
-
// Jump guard: if the raw value is wildly different,
|
|
1212
|
+
// Jump guard: if the raw value is wildly different, reset EMA to the new reading
|
|
1213
|
+
// so the hysteresis pipeline keeps receiving data and can fire the exit event.
|
|
1207
1214
|
let ratio = prev > 0.001 ? rawDistance / prev : rawDistance
|
|
1208
1215
|
if ratio > Self.DISTANCE_JUMP_FACTOR || (ratio > 0 && ratio < 1.0 / Self.DISTANCE_JUMP_FACTOR) {
|
|
1209
|
-
|
|
1216
|
+
smoothedDistances[identifier] = rawDistance
|
|
1217
|
+
return rawDistance
|
|
1210
1218
|
}
|
|
1211
1219
|
let smoothed = Self.DISTANCE_EMA_ALPHA * rawDistance + (1 - Self.DISTANCE_EMA_ALPHA) * prev
|
|
1212
1220
|
smoothedDistances[identifier] = smoothed
|
|
@@ -1356,6 +1364,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1356
1364
|
postBeaconNotification(identifier: identifier, eventType: "enter")
|
|
1357
1365
|
scheduleBeaconTimeout(identifier: identifier, beacon: beacon)
|
|
1358
1366
|
case .exit:
|
|
1367
|
+
smoothedDistances.removeValue(forKey: identifier)
|
|
1359
1368
|
cancelBeaconTimeout(identifier: identifier)
|
|
1360
1369
|
sendLoggedEvent("onBeaconExit", makeBeaconEventParams(identifier: identifier, beacon: beacon, event: "exit"))
|
|
1361
1370
|
postBeaconNotification(identifier: identifier, eventType: "exit")
|
|
@@ -1379,6 +1388,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1379
1388
|
missCounters[identifier] = 0
|
|
1380
1389
|
enterCounters[identifier] = 0
|
|
1381
1390
|
exitCounters[identifier] = 0
|
|
1391
|
+
smoothedDistances.removeValue(forKey: identifier)
|
|
1382
1392
|
// Do NOT cancel the timeout here. A miss-based exit is triggered by
|
|
1383
1393
|
// ranging gaps (e.g. accuracy == -1), not a confirmed physical departure.
|
|
1384
1394
|
// Cancelling here prevents the timeout from firing when it is longer than
|
|
@@ -1429,6 +1439,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1429
1439
|
enterCounters.removeValue(forKey: identifier)
|
|
1430
1440
|
exitCounters.removeValue(forKey: identifier)
|
|
1431
1441
|
missCounters.removeValue(forKey: identifier)
|
|
1442
|
+
smoothedDistances.removeValue(forKey: identifier)
|
|
1432
1443
|
if wasEntered {
|
|
1433
1444
|
cancelBeaconTimeout(identifier: identifier)
|
|
1434
1445
|
sendLoggedEvent("onBeaconExit", makeBeaconEventParams(identifier: identifier, region: beaconRegion, event: "exit"))
|