Modernize the app: Compose Material 3 rewrite, engine fixes, tests and CI - #49
Modernize the app: Compose Material 3 rewrite, engine fixes, tests and CI#49BKPepe wants to merge 10 commits into
Conversation
Gradle 9 with AGP 9 built-in Kotlin, a version catalog, SDK 37 and the org.librespeed.speedtest application id. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Corrects the malformed User-Agent header, accepts any 2xx response, tracks the IP version, estimates loss from unreturned pings and submits telemetry to the tested server. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Four-tab UI following the design mockups: gauge with live graphs, server management with favorites and distances, history with result and test details, sharing as image, link or text, Czech translation and an adaptive icon. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pull requests run lint, unit tests and a debug build plus dependency review; tags build signed releases and fail without signing secrets. Dependabot watches Gradle and Actions weekly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README with current screenshots, privacy policy, security policy and fastlane metadata in English and Czech. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stability and bufferbloat measurements, server comparison, history filters with export and trends, a diagnostic report, a licenses screen, cellular details and a tabletop layout for foldables. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Licenses generated by licensee, scheduled background tests, bufferbloat guidance, a per-app language switch, 4G/5G labels, fold-crease layouts, a baseline profile, NaN-safe stats, stricter URL validation and the telemetry contract asserted through the real app path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Database migration, export, network detection and boundary tests, screenshot goldens verified in CI, a recreation smoke test, the device matrix with API 33, a docker LibreSpeed integration job, buildless CodeQL and hardened workflows. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Since Google Play verification and costs are hindering us to use Play Store, the way for using F-Droid should be described better |
|
F-Droid is a fine alternative, but I wouldn't frame it as F-Droid instead of Google Play. Most regular users will only look for apps on Google Play or the App Store, and since there are already many existing alternatives for speed tests, I doubt they will specifically look for this app on F-Droid. Google Play is a one-time $25 registration with no recurring fees. The initial verification and closed testing are a one-off hurdle, but I don't think that's a reason to avoid it. Sideloading isn't a realistic option for ordinary users either. So I'd go with both: Play for mainstream users, F-Droid/Obtainium as alternatives. Over time, we could drop some of the alternative distribution channels to reduce the maintenance and support burden. |
The CLIs send <product>/<version> (<os>; <arch>; <platform detail>), so send that same shape here: the app version, the Android release, the primary ABI, and the device product, which bounds what a connection can show in the first place. Build properties are set by whoever built the ROM, so they are reduced to a conservative alphabet and bounded before going into a header, where a stray line break would split the request itself. The engine's built-in default follows the same shape for the case where the app never sets one.
Summary
This PR turns the template into a production-oriented LibreSpeed Android client: Jetpack Compose + Material 3 UI, a fixed and extended test engine, opt-in telemetry with a tested privacy contract, and CI/release workflows.
It is intentionally large, but the history is structured for review — 9 commits, each a self-contained block (build system → engine → UI → tests → CI → docs → features → hardening → coverage). Reviewing commit by commit is recommended.
The app now uses
applicationId org.librespeed.speedtest(previouslycom.dosse.speedtest). On Google Play this is a new app, not an update — existing installations will not upgrade to it. This was a deliberate choice to move the app under the project's own namespace, but it is a decision the maintainers should explicitly confirm before any store publishing.Screenshots
What's new for users
Engine fixes (kept in Java, same architecture)
User-Agentheader (CRLF injection into the request) fixed; UA is now set at runtime with the real versionPrivacy
Telemetry is off by default. When enabled, the result (including the IP address) goes to the tested server's results backend — the app has no central telemetry collection endpoint; the in-app "What is sent?" dialog explains this. The IP address is shown only in the technical details screen and is never part of any shared text or image. The new runtime permissions are optional and degrade gracefully:
ACCESS_COARSE_LOCATION(server distances on demand, on-device only),READ_PHONE_STATE(4G/5G label) andPOST_NOTIFICATIONS(scheduled-test results).Testing
CI / release
vX.Y.Z: release build that fails without signing secrets, verifies tag vsversionName, attaches the signed APK to a draft release (suitable for Obtainium; enables F-Droid Auto Update #45, Download .apk from github directly with Obtainium #41) and keeps the AAB as an artifactMaintainer checklist: secrets and Google Play
Nothing in this PR publishes anywhere by itself. To get signed releases and a Play listing, the repository owner has to do the following one-time setup:
1. Release signing (required for tagged releases)
The release workflow refuses to build without these repository secrets:
SIGNING_KEYSTORE_BASE64base64 -i upload.jks)SIGNING_STORE_PASSWORDSIGNING_KEY_ALIASSIGNING_KEY_PASSWORDCreate the keystore once with
keytool -genkeypair -v -keystore upload.jks -alias upload -keyalg RSA -keysize 4096 -validity 9125and keep an offline backup — with Play App Signing (recommended, see below) a lost upload key can be reset, but a lost keystore without it means losing the ability to update the app. The keystore is written only to the runner's temp directory and never appears in logs or artifacts.2. Google Play (optional, for the store listing)
Because of the new
org.librespeed.speedtestapplication ID this is a brand-new app in the Play Console:librespeed-releaseartifact.fastlane/metadatadirectory in this PR has en-US and cs-CZ ready), content rating questionnaire, privacy policy URL (PRIVACY.md needs to be reachable as a public URL — the raw GitHub link works), and the Data safety form — declare: no data collected by default; optional telemetry sends measurements, client info and IP address to the user-chosen test server; optional coarse location used on-device only, never transmitted.PLAY_SERVICE_ACCOUNT_JSONsecret. The manual publish workflow then uploads to internal/alpha/beta only (production is deliberately not offered).versionCodeandversionNameinapp/build.gradle.kts, tagv<versionName>— the workflow fails if the tag andversionNamedisagree.targetSdk 36meets the Google Play target-API requirement for new apps and updates effective 31 Aug 2026.3. Without Play
Tagged releases attach the signed APK to a draft GitHub release — that alone is enough for Obtainium users and for an F-Droid inclusion request later (reproducible-build tweaks for F-Droid would be a separate PR).
Known limitations / possible follow-ups
androidx.baselineprofileplugin supports AGP 9