Integrate battery-efficient Activity Recognition and update documentation#49
Integrate battery-efficient Activity Recognition and update documentation#49manojvermamv wants to merge 15 commits into
Conversation
… GPS throttling across Android/iOS
…Recognition release
|
Hi @manojvermamv 👋 First of all, thank you! For your contribution to this library, so it genuinely means a lot. 🎉 This is a really well-put-together PR: cross-platform parity (Android ActivityRecognitionClient + iOS CoreMotion), the new optional TrackingOptions fields kept fully backward-compatible, unit tests on both the provider lifecycle and option parsing, and the docs/CHANGELOG already updated. The battery-efficiency angle pausing GPS on STILL ↔ MOVING transitions is exactly the kind of feature this library benefits from. I'll go through it carefully over the next few days, paying particular attention to the native lifecycle handling (pause/resume around requestLocationUpdates, receiver registration) and how the new flow interacts with the existing recovery and geofencing paths. I may leave a few inline questions or suggestions as I review. Thanks again for taking the time to contribute i really appreciate it. I'll follow up soon. 🙏 |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
…, pauseLocationWhenStill, activityUpdateInterval from Bundle Without this fix the 3 activity-recognition fields were silently dropped on service crash-recovery restarts (when intent is re-delivered). As a result getActivityTrackingEnabledOrDefault() always returned false and GPS was never paused when the device became stationary.
If the consumer enables activityTrackingEnabled but forgets to add NSMotionUsageDescription to their Info.plist, CMMotionActivityManager will crash the app instantly. This adds a safe check to gracefully fallback to non-activity-tracked GPS instead.
Swift requires all non-optional let properties to be initialized before calling super.init(). The activityTrackingEnabled, pauseLocationWhenStill, and activityUpdateInterval properties were missing from the early-return (dictionary == nil) branch, causing a compilation error on iOS.
… activity types TILTING fires when device angle changes relative to gravity (e.g. placed on desk) — not locomotion. UNKNOWN fires when GMS lacks confidence to classify motion. Both are now treated as stationary so GPS pauses immediately without waiting for STILL confirmation. Also persists activityTrackingEnabled, pauseLocationWhenStill, and activityUpdateInterval in TrackingStateEntity (Room) and LocationStorage so that GPS-pause behaviour survives service crash-recovery and Intent redelivery. LocationDatabase version bumped to 2 for destructive migration.
|
First off, thank you for this contribution, @manojvermamv, and welcome. This is a thoughtful, well-structured PR. The new
Critical blockers
|
| Concern | Verdict |
|---|---|
PendingIntent mutability unsafe |
✅ Safe and correct: explicit, component-locked base intent; FLAG_MUTABLE only where GMS fills result extras |
| Cross-app receiver spoofing | ✅ Closed: ActivityReceiver is exported="false" in both manifests; PendingIntents fire intra-app |
| Semver classification wrong | ✅ MINOR is correct: optional fields are backward compatible (the 1.1.0 number collision is a separate repo-state issue, M7) |
| iOS resume guard is dead code | ✅ Not dead: PASSIVE/NO_POWER are real LocationAccuracy enum strings |
| TS plumbing drops a field | ✅ Correct end-to-end: all 3 fields pass through with false/0 preserved |
| iOS retain cycle | ✅ None: weak delegate and [weak self] capture; teardown nils correctly |
| Native network egress | ✅ None: motion and location stay on-device |
package.json newline breaks CI |
✅ Will not: no JSON lint gate (see L4) |
Prioritized merge checklist
Must fix before merge (blockers)
-
C1: Add aMigration(1,2)(ALTER TABLE tracking_state ADD COLUMN×3 nullable); keep destructive only as last resort; commit exported2.json. -
C2: Never pause while automotive; require a confidence threshold; add a resume grace or timeout; removepauseLocationWhenStillfrom the default Quick Start. -
H6: Wire uprequestActivityTransitionUpdatesor remove the dead methods, branch, and test; correct the CHANGELOG to match what ships. -
H1: Resolve resume latency (wiringH6fixes this); stop claiming "resumes immediately." -
H2: Treat only high-confidenceSTILLas a pause trigger; excludeUNKNOWN/TILTING; thread confidence through. -
H3: Confine activity-state mutation and provider lifecycle to onequeue; restrictmaintoCLLocationManagerstart/stop. -
H4: EmitonLocationWarning(LOCATION_PAUSED_STILL/LOCATION_RESUMED) on both platforms; surface viauseLocationUpdates. -
H5: RemoveACTIVITY_RECOGNITIONfrom the library manifest; document consumer-side opt-in. -
H7: Add a./gradlew … testDebugUnitTestCI job; extract the pause/resume decision into a pure, unit-tested function; add TS mapper tests.
Should fix before merge
-
M1: Remove the backslashes so the Kotlin log template interpolates. -
M2: Add a runtimeACTIVITY_RECOGNITIONcheck and a warning (Android). -
M3: CheckCMMotionActivityManager.authorizationStatus()and emit a warning (iOS). -
M4: TagactivityUpdateInterval@platform Android(or drop from the iOS transport). -
M5: Persist or restore activity fields across iOS crash recovery, or document the divergence. -
M6: PropagateisAvailable()fromActivityProviderFactoryon non-GMS devices. -
M7: Drop the manual version and CHANGELOG edits; reconcile numbering (e.g.1.2.0). -
M8: Warn whenpauseLocationWhenStillis set withoutactivityTrackingEnabled. -
M9: Delete the example manifest receiver block; never export the receiver. -
M10: UpdatePrivacyInfo.xcprivacy, or document the host-app motion-disclosure duty.
Nice to have (follow-up acceptable)
-
L1: Gate activity and confidence logging behind#if DEBUG/BuildConfig.DEBUG. -
L2: Reformat the 4 new Kotlin files to 2-space indent. -
L3: Trim trailing whitespace inLocationService.kt. -
L4: Restore the trailing newline inpackage.json. -
L5: Extract a shared accuracy-dispatch helper on the iOS resume path. -
L6: Restore the deleted// MARK: - Significant Location Monitoringheader. -
L7: Use the full class name for theActivityRecognitionProviderlog tag. -
L8: RestoretripIdin the README quick-start; reword the "crash on launch" claim. -
L9: Re-title the PR with a conventional-commit prefix (e.g.feat(activity): …).
Open questions for you
A few things would help us land this faster. No rush, and thanks again:
- Transition API (
H6/H1): WasrequestActivityTransitionUpdatesmeant to be wired intoLocationService? The CHANGELOG advertises it but only polling is connected. Would you prefer to wire the transition path (preferred, since it also fixes resume latency) or remove it? - Destructive migration (
C1): WasfallbackToDestructiveMigration()on the v1→v2 bump intentional? Since the change is purely additive, anALTER TABLEmigration preserves all persisted fleet data. Any reason not to add it? activityUpdateIntervalon iOS (M4): Is this meant to affect iOS at all?CMMotionActivityManageris event-driven with no interval. Can we confirm it should be Android-only (and tag it accordingly)?- Fleet pause semantics (
C2/H2): What is the intended behavior while driving? Should the feature ever pause during automotive activity, and what confidence threshold did you have in mind? - Versioning (
M7): Both this PR and the in-flightfeature/expobranch claim1.1.0. How would you like to reconcile the numbering and CHANGELOG so the automatedrelease-itflow stays authoritative? - On-device verification (
M1/H7): Has the new Android path been run on a physical device? The literal\${…}log template suggests maybe not. Confirming just helps us scope the testing gap.
Bottom line: Strong, idiomatic architecture that is close to mergeable in shape. Resolve the two Critical blockers and the High set (ideally the Mediums too), and this becomes a valuable, well-built battery-optimization feature we would be glad to ship. Looking forward to the next revision!
Add Android unit test job to CI and finalize Android SDK setup. Add Room migration (1→2) to add activityTrackingEnabled, pauseLocationWhenStill and activityUpdateInterval columns and register it to avoid destructive drops. Clarify README: NSMotionUsageDescription now gracefully falls back and update startTracking example. Remove example AndroidManifest ActivityReceiver entry. Improve Android activity-related code (ActivityReceiver, ActivityProvider, ActivityRecognitionProvider, factory) with logging/formatting cleanups. Add tracking option validation warning (pauseLocationWhenStill requires activityTrackingEnabled) and annotate activityUpdateInterval platform. Minor iOS marker and trailing-newline/package formatting fixes.
…automotive exclusion, confidence threshold, queue confinement, permission opt-in, dead code removal, warning events, CI test job
…for missing fields
feat: Battery-Efficient Activity Recognition & Dynamic GPS Throttling
Summary
Adds cross-platform Activity Recognition support that automatically pauses and resumes GPS updates based on the user's physical motion state, significantly reducing battery drain while stationary.
What Changed
Android
ActivityRecognitionProvider.kt— Play ServicesActivityRecognitionClientwrapper (event-based transitions + polling)ActivityProvider.kt/ActivityProviderFactory.kt— Abstract interface and factoryActivityReceiver.kt— Manifest-registeredBroadcastReceiverrouting events toLocationServiceLocationService.kt— Pauses/resumesrequestLocationUpdateson STILL ↔ MOVING transitionsLocationService.kt— Added missing fields toparseTrackingOptionsFromBundleto ensure GPS pausing behavior survives service crash-recovery and Intent redelivery.LocationService.kt— ExtendedisStilldetection to includeDetectedActivity.TILTINGandDetectedActivity.UNKNOWN.TILTINGfires when the device angle changes relative to gravity (e.g. placed on a desk) but is not locomotion;UNKNOWNfires when GMS lacks confidence to classify motion. Both are now treated as stationary so GPS pauses immediately without waiting for aSTILLconfirmation event.LocationStorage.kt/TrackingStateEntity.kt— PersistsactivityTrackingEnabled,pauseLocationWhenStill, andactivityUpdateIntervalin Room so GPS-pause behaviour survives service crash-recovery.LocationDatabase.kt— Schema version bumped to2(destructive migration) to accommodate newTrackingStateEntitycolumns.AndroidManifest.xml—ACTIVITY_RECOGNITIONpermission declarationsiOS
ActivityProvider.swift—CMMotionActivityManagerwrapper viaCoreMotionActivityProvider.swift— Added a defensiveNSMotionUsageDescriptionbundle check to prevent instantaneous iOS crashes if the developer forgets to configureInfo.plist.LocationManagerWrapper.swift— ImplementsActivityProviderDelegatefor pause/resumeBackgroundLocation.mm— Bridges new options through CodegentransportDictFromCodegenSpec:TrackingOptions.swift— Fixed Swift compilation error by explicitly initializing newletproperties in thenildictionary fallback initializer.BackgroundLocation.podspec— AddedCoreMotiontos.frameworksTypeScript Bridge (both platforms)
TrackingOptions— 3 new optional fields:activityTrackingEnabled,pauseLocationWhenStill,activityUpdateIntervalNativeBackgroundLocation.ts(TurboModule spec),trackingOptionsMapper.ts,tracking.tstypes all updatedTests
ActivityRecognitionProviderTest.kt— MockK unit tests for client lifecycle and cleanupTrackingOptionsTest.kt— Validates new fields, defaults, and parsingUsage