This project began as a fork of Vela Maps by PimpinPumpkin. It adds full 5-key D-pad and feature-phone operability on top of their work, and still depends on the upstream project for some hosted functionality: the routing-graph, map-overlay and place-pack release assets, and the signed calibration config channel. All credit and thanks to the original project.
A degoogled maps and navigation client for Android. Runs on GrapheneOS and other no-GMS ROMs.
All testing is SIMULATED - the screen size is set with wm size/wm density on a test device;
nothing has run on the actual phones. Every target phone now runs the gate as its OWN profile
(its own full run + its own screenshot set), no profile stands in for another:
| Phone | Simulated size | Coverage (screenshots in tests/devices/) |
|---|---|---|
| Kyocera e4810 | 240x320 @ 160 | FULLY COVERED (27/27) (kyocera-e4810/screenshots/full/) |
| Kyocera DuraXV | 240x320 @ 160 | FULLY COVERED (20/20), at the older 20-surface gate (kyocera-duraxv/screenshots/full/); re-run at 27 pending |
| TCL Flip 2 | 240x320 @ 160 | FULLY COVERED (20/20), at the older 20-surface gate (tcl-flip-2/screenshots/full/); re-run at 27 pending |
| Sonim XP3 (XP3800) | 240x320 @ 160 | FULLY COVERED (20/20), at the older 20-surface gate (sonim-xp3/screenshots/full/); re-run at 27 pending |
| Sonim X320 (XP3 Plus 5G) | 480x854 @ 320 | FULLY COVERED (27/27) (sonim-x320/screenshots/full/) |
| Sonim X320 @ low density | 480x854 @ 225 | FULLY COVERED (27/27) (sonim-x320-225/screenshots/full/) |
| Kyocera DuraXe e4830 | 240x320 @ 120 | FULLY COVERED (27/27) (kyocera-duraxe-e4830/screenshots/full/) |
The 27 surfaces: first-run (Welcome + voice/offline/consent dialogs), bare map, search overlay, results, place sheet (+ expanded), Street View (+ its D-pad walk), directions, route steps, Settings incl. the deep Voice-library / Offline / Saved-places sub-sections, voice search, parking (saved spot, hub menu, parked-car sheet), and the soft-key surfaces (Options menu, Move-map and Zoom modes, the Layers panel, and the place Options menu).
The restricted flavor is scored against 25 of those: it ships no Street View, so those two are marked n/a rather than counted as gaps.
The FULLY COVERED profiles pass the full-coverage gate: bash tests/devices/full_coverage.sh <device-id> drives every
surface at the device's geometry and prints RESULT: FULLY COVERED (0 MISSED) - the hard requirement
for calling a device supported (see AGENTS.md). NOT yet in the gate: live turn-by-turn
navigation cards and transit itineraries. Real-hardware confirmation: none - the geometry is
simulated with wm size/wm density, so this is "fits and is D-pad-navigable at these simulated
sizes," not "run on the actual phones." New models drop straight into the matrix - open an issue with
the model + screen size and resolution.
- D-pad first. Fully operable with a 5-key D-pad (arrows + OK) and hardware BACK on a device with no touchscreen. Touch is a bonus.
- Tiny screens. Fits real feature-phone displays (240x320-class): the app checks its screen and
scales its own density so nothing clips. Verified per-device with screenshots in
tests/devices/. - Voice search, on-device. A mic in the search bar dictates a query. A speech engine (Whisper tiny multilingual by default, ~58 MB; SenseVoice and Moonshine optional in Settings) transcribes right on the phone - no account, no Google, nothing uploaded; or it hands off to an installed voice-input app. The mic only shows when something can service it.
- Degoogled. No Google Play Services, no account, no API key, no backend.
- NewPipe's model, for Google Maps. Open vector tiles for the basemap; the phone scrapes Google's public web endpoints per-user for POIs, routing, and traffic-aware ETAs.
Two editions per release: the standard APK, and vela-maps-v<version>-restricted.apk - a
restricted edition for users who impose the self-restrictions on themselves and want them
non-optional (no reviews, no photos, adult categories hidden, no external links; voice search
stays available; the toggles are hard-locked and absent from Settings). It installs side by side under its own app id
and self-updates only to restricted builds.
Add https://github.com/alltechdev/vela-dpad in
Obtainium to auto-track the latest
release, or grab an APK from
Releases. No Play Store, no account.
| Map & search | Search results | Place details | Directions | Navigation |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
| Public transit | Photo gallery | Light theme, search | Light theme, place |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
The same app on a phone with no touchscreen. The two hardware soft keys drive a contextual bar, and any on-screen button a key already covers is dropped, so the map keeps the screen. Everything hidden stays reachable from an Options menu.
| Bare map | Options menu | Navigation | Nav options |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
| Route preview | 240x320 screen |
|---|---|
![]() |
![]() |
What Vela does and the method behind each capability. The full feature list is in
FEATURES.md, the deeper contract in SPEC.md, and
planned work in ROADMAP.md.
| Capability | Method | Start here |
|---|---|---|
| D-pad-only operation | The whole UI runs on a 5-key D-pad: arrows pan the map, OK-at-crosshair taps, hold-OK drops a pin, on-screen zoom, focus rings, a key path for every gesture. Fits tiny feature-phone screens via AdaptiveDensity (scales the app's density to the panel) |
docs/dpad.md, app/ui/DpadFocus.kt, app/ui/map/MapDpadController.kt, app/ui/AdaptiveDensity.kt, tests/devices/ |
| Basemap | Open vector tiles (OpenFreeMap / Protomaps) via MapLibre, keyless, recoloured Google-style at runtime | core/data/tiles/, app/ui/map/VelaMapView.kt |
| Search, places, reviews, hours | Per-user keyless scrape of google.com pb endpoints; positional arrays walked by calibrated index paths |
core/data/google/, SPEC section 3 |
| Photos / transit / popular-times | Hidden anonymous WebView reads what the bare RPC is bot-degraded out of | app/web/ |
| Turn-by-turn routing | FOSSGIS OSRM (open), complete street-named steps incl. highway refs / exits / lanes | core/data/RouteGeometry.kt |
| Traffic ETA + jam reroute | Google's directions overlaid on the OSRM route; re-runs OSRM through Google's path only when they diverge | GoogleMapsDataSource.directions |
| Offline routing + geocoding | On-device GraphHopper graphs + SQLite POI/address stores + whole-region place packs, downloaded per region | core/data/GraphHopperRouteEngine.kt, app/offline/ |
| Open map overlays | Microsoft building footprints + OpenAddresses house numbers as per-region PMTiles, streamed beneath OSM | app/offline/OverlayTileStore.kt |
| Navigation | Pure NavEngine turn logic (unit-tested) into a maneuver banner (lanes / shields), AOSP TTS + a bundled neural voice, haptics |
core/nav/, app/ui/nav/, core/voice/ |
| Location | AOSP LocationManager + rotation-vector sensor, never GMS / Fused |
core/location/ |
| Fix drift without an app update | ECDSA-signed remote calibration.json verified against a pinned key |
core/config/CalibrationStore.kt, SPEC section 5 |
| Diagnostics | Local crash / ANR / jank capture (Timber, CrashCatcher, ExitInfoReader, StrictMode), shown in Settings -> Diagnostics | app/diag/ |
- The gap. A phone without Play Services cannot run Google Maps, and open datasets fall short on search, reviews, hours, and live traffic.
- The approach. Vela is a thin client that asks Google's public endpoints the way a logged-out browser does: from your own IP, no shared key, no server in between (NewPipe's legal footing).
- What Google sees. Your IP, query, and map area. Not a Google account, not an app key.
- Open where it can. The basemap is open vector tiles and streets come from OpenStreetMap, so the heaviest load never touches Google and offline detail follows OSM coverage.
- No backend, no account, no telemetry. Saved places, history, and settings never leave
the device. Full per-endpoint breakdown in
PRIVACY.md.
Never embed a static Google API key. That turns "a user scraped from their own IP" (defensible, NewPipe's footing) into "the app shipped Google's credential" (not). The per-user
GoogleSessionbootstrap is the whole point.
Three Gradle modules (AGP 8.7.3, Kotlin 2.1, Compose, Hilt, R8):
:coreis the UI-agnostic extractor (NewPipeExtractor pattern): the model, theMapDataSourceseam (a Mock source plus the Google scraper), OSRM + GraphHopper routing, offline stores, location, voice, haptics, the nav engine, and calibration.:appis the Jetpack Compose (Material 3) UI: map, search, place sheet, directions, the navigation banner, settings, the hidden-WebView scrapers, and offline downloads.:yapchikis a vendored, source-identical copy of the Yapchik softkey engine (LGPL-3.0, zero deps): the hardware LEFT/RIGHT soft-key bar for keypad phones. Kept as its own module so it stays cleanly replaceable/re-syncable. Seedocs/softkeys.md.
MapDataSource is the seam: Mock today, Google once calibrated, a future Overture/OSM
or self-hosted source drops in the same way. Full module tree in AGENTS.md.
# debug: R8-minified AND debuggable, smooth on-device, installs beside release (app.vela.debug)
./gradlew :app:assembleDebug
# distribution build: R8 + resource shrinking
./gradlew :app:assembleRelease
# unit tests for the pure logic (polyline codec, nav engine)
./gradlew :core:test- Both build types run R8; the debug build stays debuggable and installs beside release.
- Every push to
mainpublishes a signedv0.0.<run>release with both APKs, tracked by Obtainium and the in-app updater. - Out of the box the app uses the live Google source over the keyless OpenFreeMap basemap;
MockMapDataSourceis the offline fallback, and reverse-geocode uses OpenStreetMap Nominatim.
See AGENTS.md for the build variants, signing secrets, the dead-code CI gate,
and the MAPTILER_KEY basemap switch.
- Location: AOSP
LocationManager(GPS + NETWORK), neverFusedLocationProviderClient. On GrapheneOS, enabling PSDS drops the cold fix from ~30s to a few seconds. - Voice: a bundled on-device neural voice (sherpa-onnx + a downloadable Piper model,
~40 voices), plus any AOSP
TextToSpeechengine the phone has. - No GMS anywhere: no Fused location, no FCM, no Firebase, no Play Integrity.
Read CONTRIBUTING.md first: it covers the hard rules (no backend, no
static Google keys, degoogled runtime, the :core/:app boundary, D-pad-first UI,
docs-in-the-same-commit, translations for all 11 locales) and how to send a change.
Security issues go through SECURITY.md, not a public issue.
This app is a fork of Vela Maps by PimpinPumpkin. Vela is their project. The degoogled maps client, its architecture, the keyless approach to Google data, the routing and offline stack, navigation, the place and transit surfaces, the overwhelming majority of what this app is, are all their work. This fork adds 5-key D-pad and feature-phone operability on top of it. That delta is the fork; it is not the app.
The debt is ongoing, not historical:
- ~211 commits in this repo port work from upstream, and 34 features in
docs/FEATURES.mdcite the upstream commit they came from. When upstream fixes something this fork also has, the upstream fix is adopted rather than reinvented. - Vela depends on upstream at runtime: the routing-graph, map-overlay and place-pack release assets, plus the signed calibration-config channel, are all served from PimpinPumpkin/Vela. Without upstream, this app does not route, does not calibrate, and does not download offline data.
If you are not on a keypad or D-pad phone, use upstream. This fork exists to serve devices their build isn't targeting, not to replace it. All credit and thanks to PimpinPumpkin.
The LEFT/RIGHT hardware soft-key bar that makes Vela drivable on a keypad phone is
Yapchik by theonionsarewatching, vendored
here as the :yapchik module.
- Copyright © 2026 theonionsarewatching, https://github.com/theonionsarewatching/yapchik
- GNU Lesser General Public License v3.0. See
yapchik/LICENSEandyapchik/NOTICE. LGPL-3.0 inside Vela's GPL-3.0 is compatible. - Vendored source-identical and kept as its own Gradle module so it stays a cleanly replaceable library that can be re-synced from upstream. Vela does not fork it or hand-edit its files.
- Zero dependencies (framework-only), which is what makes it viable on these devices.
- On the license history: Yapchik was originally PolyForm Noncommercial, which is GPL-incompatible and would have made vendoring impossible. The author relicensed it to LGPL-3.0, and that relicense is the only reason the soft-key bar can ship inside Vela at all, and the reason this stays F-Droid-eligible. Thank you.
Integration design + the contextual key map: docs/softkeys.md.
GPLv3.















