core/tracking/ReturnToStartDetector.kt — mirror of iOS spec, TrackStats.haversineKm.
core/tracking/ReturnPromptController.kt — plain class owned by RecordingService; reads recording.state.value (paused, points.firstOrNull() start), invokes onFire when the setting allows.
core/audio/ReturnPromptSound.kt — res/raw/return_prompt.ogg (transcoded from iOS gap-ahead.caf) via MediaPlayer USAGE_ASSISTANCE_SONIFICATION + transient-may-duck focus; one-shot vibration. Self-played by the service so it works with POST_NOTIFICATIONS denied.
RecordingService.kt: feed returnPrompt.onRawFix(...) in onLocationResult before/independent of offerFix; new tracking_alerts IMPORTANCE_HIGH channel (sound null — service self-plays; existing activity_tracking is LOW + immutable); notification id 921 auto-cancel with Stop & save (ACTION_STOP_AND_SAVE) + Keep recording (ACTION_DISMISS_RETURN_PROMPT) service PendingIntents; STOP_AND_SAVE handler completes routes.saveCompleted("Untitled activity", RUN, points) before stopSelf(); ACTION_STOP/onDestroy cancel 921 + reset detector.
Settings IconButton in TrackerScreen → dialog Switch, SharedPreferences("tracker_prefs")return_prompt_enabled default true.
ReturnToStartDetectorTest.kt — matrix identical to iOS. No manifest changes.
Part of epic #997.
- `core/tracking/ReturnToStartDetector.kt` — mirror of iOS spec, `TrackStats.haversineKm`.
- `core/tracking/ReturnPromptController.kt` — plain class owned by `RecordingService`; reads `recording.state.value` (paused, `points.firstOrNull()` start), invokes onFire when the setting allows.
- `core/audio/ReturnPromptSound.kt` — `res/raw/return_prompt.ogg` (transcoded from iOS gap-ahead.caf) via MediaPlayer USAGE_ASSISTANCE_SONIFICATION + transient-may-duck focus; one-shot vibration. Self-played by the service so it works with POST_NOTIFICATIONS denied.
- `RecordingService.kt`: feed `returnPrompt.onRawFix(...)` in `onLocationResult` before/independent of `offerFix`; new `tracking_alerts` IMPORTANCE_HIGH channel (sound null — service self-plays; existing `activity_tracking` is LOW + immutable); notification id 921 auto-cancel with Stop & save (`ACTION_STOP_AND_SAVE`) + Keep recording (`ACTION_DISMISS_RETURN_PROMPT`) service PendingIntents; STOP_AND_SAVE handler completes `routes.saveCompleted("Untitled activity", RUN, points)` before `stopSelf()`; ACTION_STOP/onDestroy cancel 921 + reset detector.
- Settings IconButton in `TrackerScreen` → dialog Switch, `SharedPreferences("tracker_prefs")` `return_prompt_enabled` default true.
- `ReturnToStartDetectorTest.kt` — matrix identical to iOS. No manifest changes.
Code:spikersoft-android@04d9c7b (PR #11, feat/return-to-start-999) — every bullet in the body is present on main:
core/tracking/ReturnToStartDetector.kt + core/tracking/ReturnToStartDetectorTest.kt (the iOS-identical matrix)
core/tracking/ReturnPromptController.kt
core/audio/ReturnPromptSound.kt with the transcoded asset committed at app/src/main/res/raw/return_prompt.ogg (the only file in res/raw/)
core/tracking/RecordingService.kt — ALERT_CHANNEL_ID = "tracking_alerts" (:313), ACTION_STOP_AND_SAVE (:323) with its handler at :119 and the notification action at :231, and PREF_RETURN_PROMPT_ENABLED = "return_prompt_enabled" (:317)
the settings switch surfaced from TrackerScreen
Live: nothing runtime-observable from this box (native app).
Not migrated: nothing left to do. (The iOS twin, #998, is the piece still outstanding in this epic — migrated to spikerj/spikersoft-ios#17.)
— Opus 5 Agent
Verified complete 2026-08-07 — closing.
- **Code:** `spikersoft-android@04d9c7b` (PR #11, `feat/return-to-start-999`) — every bullet in the body is present on main:
- `core/tracking/ReturnToStartDetector.kt` + `core/tracking/ReturnToStartDetectorTest.kt` (the iOS-identical matrix)
- `core/tracking/ReturnPromptController.kt`
- `core/audio/ReturnPromptSound.kt` with the transcoded asset committed at `app/src/main/res/raw/return_prompt.ogg` (the only file in `res/raw/`)
- `core/tracking/RecordingService.kt` — `ALERT_CHANNEL_ID = "tracking_alerts"` (`:313`), `ACTION_STOP_AND_SAVE` (`:323`) with its handler at `:119` and the notification action at `:231`, and `PREF_RETURN_PROMPT_ENABLED = "return_prompt_enabled"` (`:317`)
- the settings switch surfaced from `TrackerScreen`
- **Live:** nothing runtime-observable from this box (native app).
- **Shipped by:** android PR #11.
Not migrated: nothing left to do. (The iOS twin, #998, is the piece still outstanding in this epic — migrated to spikerj/spikersoft-ios#17.)
— Opus 5 Agent
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of epic #997.
core/tracking/ReturnToStartDetector.kt— mirror of iOS spec,TrackStats.haversineKm.core/tracking/ReturnPromptController.kt— plain class owned byRecordingService; readsrecording.state.value(paused,points.firstOrNull()start), invokes onFire when the setting allows.core/audio/ReturnPromptSound.kt—res/raw/return_prompt.ogg(transcoded from iOS gap-ahead.caf) via MediaPlayer USAGE_ASSISTANCE_SONIFICATION + transient-may-duck focus; one-shot vibration. Self-played by the service so it works with POST_NOTIFICATIONS denied.RecordingService.kt: feedreturnPrompt.onRawFix(...)inonLocationResultbefore/independent ofofferFix; newtracking_alertsIMPORTANCE_HIGH channel (sound null — service self-plays; existingactivity_trackingis LOW + immutable); notification id 921 auto-cancel with Stop & save (ACTION_STOP_AND_SAVE) + Keep recording (ACTION_DISMISS_RETURN_PROMPT) service PendingIntents; STOP_AND_SAVE handler completesroutes.saveCompleted("Untitled activity", RUN, points)beforestopSelf(); ACTION_STOP/onDestroy cancel 921 + reset detector.TrackerScreen→ dialog Switch,SharedPreferences("tracker_prefs")return_prompt_enableddefault true.ReturnToStartDetectorTest.kt— matrix identical to iOS. No manifest changes.Verified complete 2026-08-07 — closing.
spikersoft-android@04d9c7b(PR #11,feat/return-to-start-999) — every bullet in the body is present on main:core/tracking/ReturnToStartDetector.kt+core/tracking/ReturnToStartDetectorTest.kt(the iOS-identical matrix)core/tracking/ReturnPromptController.ktcore/audio/ReturnPromptSound.ktwith the transcoded asset committed atapp/src/main/res/raw/return_prompt.ogg(the only file inres/raw/)core/tracking/RecordingService.kt—ALERT_CHANNEL_ID = "tracking_alerts"(:313),ACTION_STOP_AND_SAVE(:323) with its handler at:119and the notification action at:231, andPREF_RETURN_PROMPT_ENABLED = "return_prompt_enabled"(:317)TrackerScreenNot migrated: nothing left to do. (The iOS twin, #998, is the piece still outstanding in this epic — migrated to spikerj/spikersoft-ios#17.)
— Opus 5 Agent