Foreground location service: permissions, notification, battery exemption #15
Labels
No labels
area:companion
area:docs
area:shared
area:tooling
area:watchapp
blocker
kind:chore
kind:feature
kind:spike
kind:test
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Blocks
Depends on
#20 GPX ride recording including heart rate
robert/PedalPebble
#14 Android project skeleton and Gradle setup
robert/PedalPebble
Reference
robert/PedalPebble#15
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Goal
Position updates must survive a whole ride with the screen off. This is where most Android bike apps fail.
Acceptance criteria
FOREGROUND_SERVICE_LOCATIONand a persistent notification showing ride statusACCESS_FINE_LOCATIONrequested with a clear rationaleFiles
companion/.../ride/RideService.ktUpdate — 2026-08-31: battery target and minimum Android version
the screen off (NFR-B2). Measure it; if the budget is missed, reduce the GPS rate or the map frame
rate before giving up on the target.
BLUETOOTH_SCAN/BLUETOOTH_CONNECTpermission model is needed - no legacylocation-permission-for-BLE workaround. Foreground service types are declared but not yet enforced
at this API level; declare them correctly anyway.
Closed by PR #97 (merged): RideService (:companion:ride, foregroundServiceType="location", API 34+ FOREGROUND_SERVICE_LOCATION), correctly-ordered permission flow (fine+coarse location together, background location as a separate second request only reachable after the first is granted, POST_NOTIFICATIONS gated to API 33+, battery-exemption last) via RideSetupActivity, each step with its own plain-language rationale (NFR-S6). Nothing requested at app launch \u2014 the whole flow triggers only when a ride is started. RideSetupState/RideSetupStep (:companion:core, zero android.* imports) is the pure decision logic, 8 host tests; RidePermissions is the thin Android-state bridge feeding it.\n\nVerified for real:
./gradlew :companion:assembleDebugsucceeds, merged manifest inspected directly (all permissions present, service correctly declared not-exported with the right foregroundServiceType),:companion:core:testand:companion:lintDebugboth green.\n\nOut of scope by design: real speed/distance/BLE arbitration (#17/#19) and full ride-session restoration across process death (#12) \u2014 this service's restart handling only proves the platform-survival shell resumes.