feat: add support for geofencing#763
Conversation
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
#706) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…unknown transition types (#707) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…che (#708) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…710) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…711) Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
…716) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ion (#750) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sample app builds 📱Below you will find the list of the latest versions of the sample apps. It's recommended to always download the latest builds of the sample apps to accurately test the pull request. |
| transitionId = UUID.randomUUID().toString(), | ||
| geofenceName = androidComponent.geofenceRegionStore.getCachedRegionName(geofenceId) | ||
| ) | ||
| androidComponent.pendingGeofenceDeliveryStore.append(entry) |
There was a problem hiding this comment.
Cooldown before durable enqueue
Low Severity
After GeofenceCooldownFilter.tryAcquire succeeds, the cooldown timestamp is persisted before the transition is appended to the pending delivery store. If the disk write fails silently, the OS may fire again within the cooldown window but the SDK will suppress it, with no pending row to flush later.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit ecaf91e. Configure here.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #763 +/- ##
============================================
- Coverage 69.07% 67.76% -1.31%
- Complexity 838 1127 +289
============================================
Files 149 206 +57
Lines 4601 6400 +1799
Branches 628 888 +260
============================================
+ Hits 3178 4337 +1159
- Misses 1189 1746 +557
- Partials 234 317 +83 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
|
📏 SDK Binary Size Comparison Report
|
|
Build available to test |
…sts (#764) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| /** Null when the fired geofence isn't in the cached region set. */ | ||
| val geofenceName: String? = null | ||
| ) : PendingDeliveryStore.PendingDeliveryEntry { | ||
| override val key: String get() = "${geofenceId}_${transition.name}_$timestamp" |
There was a problem hiding this comment.
Pending delivery key collisions
Low Severity
PendingGeofenceDelivery.key uses geofence id, transition, and second-granularity timestamp only, while transitionId is excluded. Two pending rows with the same key share one WorkManager unique work (KEEP), and PendingDeliveryStore.claim/remove drop every row with that key—so a second distinct transition in the same second can be merged away and never delivered.
Reviewed by Cursor Bugbot for commit 624e065. Configure here.
|
|
|
|
…768) Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 3 total unresolved issues (including 2 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 39a89fb. Configure here.
| } catch (ce: CancellationException) { | ||
| throw ce | ||
| } catch (ex: Exception) { | ||
| callbacks.onEntryFailed(entry, ex) |
There was a problem hiding this comment.
Flush drops failed publish
Medium Severity
The geofence foreground flush removes a pending transition from the store before publishing; if publish throws, the entry is gone and neither the analytics pipeline nor WorkManager can deliver that transition again.
Reviewed by Cursor Bugbot for commit 39a89fb. Configure here.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
|
|
|


Summary
This PR adds support for the upcoming geofence feature, merging
feature/geofence-on-deviceintomain.Highlights
userIdper transition to prevent cross-user attribution.:geofenceGradle module with the on-device implementation split out of:location.Changes
Includes previously approved/merged PRs (oldest first):
Note
High Risk
Large new surface area touching location permissions, background delivery, user identity attribution, and dual-channel event delivery; misconfiguration or races could drop transitions or attribute them to the wrong user.
Overview
Introduces a new
:geofencemodule (ModuleGeofence) for on-device GMS geofencing: fetch nearby fences fromPOST /geofences/nearest, register the nearest set plus a movement-trigger circle, tiered local re-rank vs remote refresh, boot restore, and sign-out reset. OS enter/exit transitions are persisted and delivered at least once via WorkManager (direct HTTP whenuserIdis snapshotted) and a foreground flush into the analytics pipeline, coordinated by sharedPendingDeliveryFlusher/claimSendRestore/sendRemoveOnSuccessonPendingDeliveryStore(including atomicappendAllfor geoset fan-out).Core / datapipelines gain
LocationAcquiredandGeofenceTransitionEventon the event bus,SecureUserStore(encrypteduserIdfor workers/receivers),geofenceScope, injectableClock,Iso8601TimestampFormatter(replaces datapipelines’SegmentInstantFormatter), and HTTP client GET + query params.CustomerIOpersists identity on identify, clears secure store on reset, and maps geofence events toGeofence Transitiontracks with pinneduserIdand transition-time timestamps.CI adds
locationandgeofenceto lint/unit-test matrices; tests and a manual exactly-once plan document the delivery paths.Reviewed by Cursor Bugbot for commit b1e91c0. Bugbot is set up for automated code reviews on this repo. Configure here.