Skip to content
This repository was archived by the owner on Aug 25, 2026. It is now read-only.

Repository files navigation

Vela Maps (D-pad edition)

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.

Phone status

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.

Install

Get it on Obtainium

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.

Screenshots

Map & search Search results Place details Directions Navigation
Public transit Photo gallery Light theme, search Light theme, place

On a keypad phone

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

How it works

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/

Why it scrapes Google

  • 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 GoogleSession bootstrap is the whole point.

Architecture

Three Gradle modules (AGP 8.7.3, Kotlin 2.1, Compose, Hilt, R8):

  • :core is the UI-agnostic extractor (NewPipeExtractor pattern): the model, the MapDataSource seam (a Mock source plus the Google scraper), OSRM + GraphHopper routing, offline stores, location, voice, haptics, the nav engine, and calibration.
  • :app is the Jetpack Compose (Material 3) UI: map, search, place sheet, directions, the navigation banner, settings, the hidden-WebView scrapers, and offline downloads.
  • :yapchik is 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. See docs/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.

Build & run

# 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 main publishes a signed v0.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; MockMapDataSource is 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.

Degoogled / GrapheneOS notes

  • Location: AOSP LocationManager (GPS + NETWORK), never FusedLocationProviderClient. 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 TextToSpeech engine the phone has.
  • No GMS anywhere: no Fused location, no FCM, no Firebase, no Play Integrity.

Contributing

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.

Credits

Vela Maps, by PimpinPumpkin: the project this is built on

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.md cite 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.

Yapchik: the hardware soft-key engine

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/LICENSE and yapchik/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.

License

GPLv3.

About

No description, website, or topics provided.

Resources

Contributing

Security policy

Stars

8 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages