Skip to content

Repository files navigation

C2K — Couch to 5K & 10K

Free, open-source running trainer for Android. No Google services. No tracking. No ads.

License: GPL v3 CI

Features

  • Pre-C25K — 3-week starter for absolute beginners who find C25K Week 1 too hard
  • C25K — 9-week program to run 5K
  • C210K — 14-week program to run 10K
  • Bridge to 10K — 6-week bridge for C25K graduates
  • One Hour Runner — 13-week progression to 60 minutes continuous running
  • 5K Improver — 8-week speed and stamina program for runners who can already complete 5K
  • Audible voice prompts with mid-run encouragement (Android built-in TTS — no internet needed)
  • Customizable countdown warning thresholds
  • Voice volume and speed controls
  • Music ducking during voice announcements
  • Background timer with lock-screen notification and pause/stop controls
  • Optional GPS tracking (distance & pace) — works without it too
  • Progress tracking across sessions
  • Guide screen with FAQ and glossary
  • Localised in English, Spanish, Galician, German, French, Brazilian Portuguese, and Russian
  • Landscape layouts on tablets and foldables (phones stay portrait)
  • Fully offline — no internet permission
  • Compatible with GrapheneOS and any de-Googled Android device (no Google Play Services)

Building

Requirements

  • JDK 21 (install via SDKMAN: sdk install java 21.0.5-tem)
  • Android SDK with platform API 36 and build-tools 36+ (install via Android Studio or sdkmanager)

Clone and build (debug)

git clone https://github.com/AnalogGhost/c2k.git
cd c2k
echo "sdk.dir=$HOME/Android/Sdk" > local.properties
./gradlew assembleFossDebug

APK: app/build/outputs/apk/foss/debug/app-foss-debug.apk

Run unit tests

./gradlew test

Install on device via ADB

adb install app/build/outputs/apk/foss/debug/app-foss-debug.apk

Or, to boot an emulator and install the debug build in one step: bash run-emulator.sh (uses the Pixel_10 AVD — adjust the script if yours is named differently).

Release builds

Reproducible build (for F-Droid submission)

Use the Docker build script to produce an unsigned APK in the same environment F-Droid uses:

bash docker-build.sh

APK: app/build/outputs/apk/foss/release/app-foss-release-unsigned.apk

F-Droid builds from source and applies their own signature. Build from the tagged commit before making any further commits.

CI runs this script twice on every push and fails if the two builds don't produce byte-identical output — see .github/workflows/ci.yml.

Signed (for personal sideloading)

  1. Generate a keystore (one-time):
keytool -genkeypair -v \
  -keystore ~/c2k-release.jks \
  -alias c2k \
  -keyalg RSA -keysize 4096 \
  -validity 10000
  1. Add to local.properties (this file is gitignored — never commit it):
sdk.dir=/home/YOUR_USER/Android/Sdk
storeFile=/home/YOUR_USER/c2k-release.jks
storePassword=YOUR_STORE_PASS
keyAlias=c2k
keyPassword=YOUR_KEY_PASS
  1. Build and sign:
bash docker-build.sh

$HOME/Android/Sdk/build-tools/<version>/apksigner sign \
  --ks ~/c2k-release.jks \
  --ks-key-alias c2k \
  --ks-pass pass:YOUR_STORE_PASS \
  --key-pass pass:YOUR_KEY_PASS \
  --out app/build/outputs/apk/foss/release/app-foss-release-signed.apk \
  app/build/outputs/apk/foss/release/app-foss-release-unsigned.apk

F-Droid

C2K is available on F-Droid. The app metadata file is com.hackerapps.c2k.yml.

To release a new version:

  1. Bump versionCode and versionName in app/build.gradle.kts
  2. Add a changelog at fastlane/metadata/android/en-US/changelogs/<versionCode>.txt (and the other locale folders)
  3. Commit that version bump
  4. Run bundle exec fastlane release — tags, runs the reproducible Docker build, signs, then pauses showing the real SHA-256 before pushing the tag and creating the GitHub release. F-Droid picks up new tags automatically once pushed. Run it from an interactive terminal — the confirmation prompt aborts in non-interactive shells (everything before it is local, so it's safe to rerun after deleting the local tag).

See fastlane/Fastfile for what the lane does step by step, and FDROID_PUBLISHING.md for the full initial submission guide.

Play Store

C2K also ships on Google Play, built from the same source under the play product flavor (com.hackerapps.c2k, same as foss — only the signing config differs). bundle exec fastlane playstore builds the release AAB and uploads it plus store listing metadata; it defaults to a dry run (validate_only:true) against the internal track, so pass track:production validate_only:false to actually publish. Image/screenshot uploads are skipped by default (pass skip_images:false skip_screenshots:false when they change), and bundle exec fastlane metadata pushes listing-text fixes between releases without touching the build.

Store-listing copy in fastlane/metadata/android/ feeds both Play and F-Droid. For Play, short descriptions must stay ≤80 characters and avoid price/promotion keywords ("free" and translations) and third-party brand names.

Permissions explained

Permission Why
FOREGROUND_SERVICE Keeps the timer running with screen off
FOREGROUND_SERVICE_HEALTH Required service type on Android 14+
FOREGROUND_SERVICE_LOCATION Required service type on Android 14+ when a workout is GPS-tracked
ACTIVITY_RECOGNITION Required runtime permission for the health service type on Android 14+ — requested for every workout, not just GPS ones
WAKE_LOCK Prevents CPU sleep mid-workout
POST_NOTIFICATIONS Shows workout notification with pause/stop controls
ACCESS_FINE_LOCATION Optional GPS for distance & pace — you can skip this
ACCESS_COARSE_LOCATION Coarse fallback for location permission dialog
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Prompts to exempt the app from battery optimization so a workout isn't killed mid-run
VIBRATE Optional haptic cue on interval change

No INTERNET permission — the app is fully offline.

Project structure

app/src/main/kotlin/com/hackerapps/c2k/
├── data/
│   ├── model/        # Program definitions, interval types, coaching tips
│   ├── db/           # Room database — sessions and GPS route points
│   ├── repository/   # SessionRepository
│   └── prefs/        # DataStore user preferences
├── engine/
│   ├── WorkoutEngine.kt   # Coroutine tick loop, state machine
│   ├── WorkoutState.kt    # Sealed class: Idle / Active / Paused / Completed
│   └── tts/               # TextToSpeech wrapper, audio focus, announcements
├── service/
│   └── WorkoutService.kt  # ForegroundService, wake lock, notification
├── location/              # GPS abstraction (graceful fallback if unavailable)
└── ui/
    ├── screen/home/         # Program selection, recent history, streak
    ├── screen/program/      # Week/day picker with completion badges
    ├── screen/workout/      # Live timer, interval ring, distance/pace
    ├── screen/history/      # Past sessions list with CSV/GPX export
    ├── screen/settings/     # Voice, GPS, vibration, display preferences
    ├── screen/guide/        # FAQ and glossary
    └── screen/contributors/ # Contributors credits

Contributing

See CONTRIBUTING.md for how to contribute, including translation credits.

License

Copyright (C) 2026 Matt Brown

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

See LICENSE for the full text.

About

Free, open-source Couch-to-5K & 10K trainer for Android. Offline TTS cues, no Google, no tracking, no ads.

Resources

Contributing

Stars

26 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages