This project was built with help from AI tools (Cursor). The author has a neurological condition related to dyscalculia that makes programming harder in a way similar to how dyscalculia makes maths harder. AI was used to turn design ideas into working code and docs. The author still chose the product rules, reviewed the work, and ran the testing. It is written in rust,so as many as standard crates are used. The AI assistant has written minimum of code to "tie" them together. The crates used in the project is listed here: https://github.com/Supermagnum/Navi/blob/dev/docs/crates.md
Navi does not currently ship with a ready-made international routing database the way many commercial GPS / head-unit products do (those usually include precomputed indexes from the vendor). On the pack-server path (green pills), a full region download still needs pack fetch + Geofabrik extract + offline basemap + on-device place index — typically about 20–22 minutes for a large landsdel such as Østlandet on the reference tablet, or about 5 minutes for a small region such as Luxembourg. On the local-bake path (blue pills / server down), add on-device routing-pack convert as well (Østlandet convert alone is on the order of ~7–11 minutes). These are current baseline measurements, not guarantees — see Download and place-index timing (measured) and Known issues. It must be done when you download or update map data for your region. These steps can look stuck in Tools — be patient, but they start automatic.
In Tools, region chips (pills) show how the download will run:
- Green pills — the region is published on the pack server (or already indexed on the device). Download region is green and installs published routing packs first, then still fetches a real Geofabrik extract and builds the place index on device (search). That place-index step is still minutes of work; leave the app alone until status shows done.
- Blue / default pills — the path is not on the pack server or the server is down. The button reads Download region + build place index and falls back to a full local bake: Geofabrik PBF download, on-device pack convert, and place index (the slower path).
Fallback chain (automatic; you do not pick hosts by hand): try the public
pack host
(navi-server /
navigate-me.duckdns.org). If it does not answer or the region is missing,
Navi uses Geofabrik + on-device convert (local-bake). Same idea if a pack
fetch fails mid-download (network, checksum, etc.). Details:
docs/pack-server-client.md.
Precomputed town-to-town corridors and globe disk ballparks (packs from live
current.json, plus optional highway OD caches):
docs/precomputed-index-and-route-cache.md.
Estimated server space needed (includes measured pack / ops figures, not only order-of-magnitude guesses): https://github.com/Supermagnum/Navi/blob/main/docs/indexed-map-format-plan.md
Geofabrik source PBF sizes vs Navi baked pack sizes (complete per-country
tables, continent and global totals, coverage gaps, and a sampled annualized
PBF growth rate with a decade projection):
docs/pbf-source-sizes.md.
Background indexing is still slow on region-scale extracts, but improved (Østlandet convert on SM-P613 ~14.8 → ~10.6 → ~7.4 min). Of the reduced ~7.4 min total: graph build is the largest share (~58%), wetland extraction ~32%, and a shared POI + barrier/danger-geometry two-pass parallel PBF walk ~9% (~38 s; was ~3.6 min of mutex-wrapped re-reads). Those percentages are shares of the new total, not a comparison with the old ~41/~24/~34 split of 10.6 min; POI+barrier dropped in absolute time. You can still plan while indexing runs; plans are much faster once packs are ready.
Long-distance route planning is slow. Cross-border / multi-region plans
(especially with Long trip enabled, or when packs are still cold) take
time for the app to compute. The progress label can sit at 0% for a long
phase while graph build or densify work runs — that is expected, not a hang.
Pack-hit planning is much faster — see Known issues.
Patience is a virtue, especially on corridors that touch Swedish län
(or any country with subregion packs but only a single country PBF):
ferry-overlay densify can re-scan the full ~840 MB sweden-latest.osm.pbf
for several minutes per län stem — see the long-distance bullet under
Known issues. A request to the team at
Geofabrik for Sweden extracts split by län
(and the same for Finland) would remove that shared-country scan; ideally
every country would publish matching subregion extracts so leaf packs pair
with leaf PBFs.
We need people to try Navi on real devices — car head units, tablets, and
phones. Reference checks so far: Samsung Galaxy Tab S6 Lite (SM-P613) and
Google Pixel 9a (tegu, phone cutout / API 36+). Cars and other shapes still
differ for GPS, maps, GPU, and layout. Checklist:
docs/real-hardware-testing.md.
On-device and emulator results:
docs/android-test-results.md.
CAT radio corridor / importer evidence, dummy-rigctld CI, Hamlib APK packaging,
and radio/baud UI notes (branch CAT): docs/CAT.md,
docs/CAT-test-report.md,
docs/cat-test.md.
Install from F-Droid (recommended for most users). Navi is listed on F-Droid
as no.navi.app — see F-Droid. Prefer that when you want updates
through the F-Droid client.
Install the signed release APK (sideload / testers). Download and sideload
compiled/navi-release.apk — a properly signed,
installable release APK (upload keystore; not the debug build). Current
dev sideload build: 0.3.30-beta (versionName 0.3.30-beta,
versionCode 33; matches app/build.gradle.kts). The F-Droid client index can
lag behind that tag — see F-Droid. Release process:
docs/RELEASING.md. Download a tester build from the
dev branch when
present. Android validates the APK signature on install; the separate GPG files
(compiled/SHA256SUMS,
compiled/SHA256SUMS.asc) are optional provenance
only — not a substitute for APK signing. Install steps:
Install a prebuilt APK.
How to report a bug. Prefer a GitHub issue so it is tracked in public:
- Register a free GitHub account (if you do not have one): open github.com/signup, choose a username, password, and an email you can access, then confirm the account from the email GitHub sends. Optional but recommended: two-factor authentication. Official walkthrough: Creating an account on GitHub.
- Sign in, open github.com/Supermagnum/Navi/issues, and click New issue.
- Describe what you expected, what happened, device model / OS, Navi version
(tag or
versionName), and steps to reproduce. Attach screenshots or a diagnostic log when you can (Tools → Diagnostic logging).
An email address for bug reports will be provided at a later time for people who cannot use GitHub. Until then, please use GitHub issues (or ask someone with an account to file one for you).
Translators wanted. UI language packs are specified but not shipped
(English-only chrome today). Fill or review the working table and follow the
spec: docs/plugins/i18n-translation-spec.md
(catalog: docs/plugins/translations.csv;
word/phrase context:
docs/plugins/translations-context.md).
The English column header lists countries/regions; dialect columns use
country, - area, - dialect (see the spec). Do not add a language toggle
until that plugin exists.
How to help: testers, docs, translations, and code all start in
docs/CONTRIBUTING.md. That page is the contribution
guide: how to fork the repo and work on dev (not main), basic GitHub
usage (clone your fork, sync with upstream, open a pull request against
dev), and which kinds of help are useful. Hardware testers can follow the
checklist above and file an issue; you do not need to write code.
- What this is
- Support Navi
- F-Droid
- Features
- Settings
- Break timer vs trip ETA
- Routing safety
- Minimum hardware and storage
- Screenshots
- Documents
- Code inspection / CI tests
- Plugins
- i18n / UI languages — not implemented
- Right-to-roam camping — not implemented
- Safety resupply — not implemented
- Traffic information — not implemented (research)
- DATEX road situations — implemented (opt-in, Norway/NPRA)
- DATEX NPRA client — not implemented (legacy sketch; unused by APK)
- Weather overlay — implemented (opt-in)
- Weather icons reference — reference (assets shipped with weather)
- Instrument cluster (AGL) — not implemented
- Animated icons — not implemented
- CAT radio plugin — implemented (opt-in; Hamlib + Benshi; never transmits)
- CAT radio control — full spec
- CATS WASM guest — implemented (opt-in; wasmtime auto-tune / network follow)
- CAT test report — CI / emulator / hardware evidence
- APRS — not implemented (station display + range exist; RF decode / ignored callsign planned)
- Custom alert sounds — not implemented
- Horse trekking — not implemented
- Adaptive speed warning — not implemented
- Nearby attractions (POI look-ahead) — implemented (opt-in)
- IMU (pitch / tilt / compass, mount calibration) — implemented (opt-in; Map / Tools → Plugins)
- LoRa convoy — not implemented
- Voice guidance (turn-by-turn) — not implemented
- Voice command — not implemented
- Icons (where they live) — documentation (assets in-repo)
- Coding standards and contributing
- Building and installing
- Where the map data comes from
- Known issues
- TODO
More detail lives in linked docs (architecture, truck rest rules, map styles,
debugging, and so on). To contribute, start with
docs/CONTRIBUTING.md: fork from dev, GitHub
basics, and what to work on.
Navi is an offline-first navigation app. You download map data once, then plan routes on the device without needing the internet for every trip.
It can:
- Plan routes for car, bicycle, e-bike, hiking, motorcycle, truck, and motorhome
- For bicycle / e-bike, pick Road / Gravel / MTB so unsuitable tracks are skipped
- Prefer gentler / less energy-hungry roads when eco mode is on (hills matter)
- Suggest rest stops and overnight places along longer trips
- Opt-in Long trip mode: estimate which Geofabrik regions a cross-border route needs, download those packs on Wi‑Fi/Ethernet (optional SD card), then plan offline with soft rest / overnight stops on multi-day legs
- Respect truck driving-time rules where it knows the country rules
- Show a simple map with your route, turns, and place names
- Optional elevation contours and hillshade from Mapterhorn terrain (independent toggles)
The map picture on screen comes from MapLibre. Online it can use OpenFreeMap Liberty tiles; offline it uses a downloaded regional map file (Protomaps). Routing uses a separate OpenStreetMap extract you download in Tools — that is the “brain” for finding roads and paths, not just the pretty map.
License: see LICENSE (GPL-3.0-or-later unless noted). Many small icons are
from Navit (GPL v2); see docs/icons.md.
Navi is free and open source, developed independently. If you'd like to support its development, donations are welcome via direct bank transfer:
- IBAN: NO02 1802 0334 084
- BIC/SWIFT: SHEDNO22
Please include "Navi donation" as the payment reference/message, so it's identifiable on your statement.
This is entirely optional support, not a paywall — Navi is and will remain free.
Navi is on the main F-Droid index as package no.navi.app.
- Package page: https://f-droid.org/packages/no.navi.app/ (same app: en locale)
- Build metadata:
fdroiddata
no.navi.app.yml - Rebuild checks: verification.f-droid.org
Prefer the F-Droid client for install and updates. The suggested version on
the package page can lag GitHub / dev sideloads: when last checked, the index
suggested 0.3.26-beta (versionCode 31) while app/build.gradle.kts
and compiled/navi-release.apk were
0.3.30-beta (versionCode 33). fdroiddata master already listed
CurrentVersion 0.3.30-beta / 33. Sideload steps:
Install a prebuilt APK.
| Feature | In plain words | Status |
|---|---|---|
| Travel modes | Choose car, bike, e-bike, hiking, motorcycle, truck, or motorhome. | Done |
| Vehicle size | Save height/width/length/weight limits so the route skips roads that are too tight. | Done |
| E-bike specs | Battery size, motor torque, and wheel size help estimate battery use and steep climbs. Live cable telemetry is planned later. | Done (planning); live data later |
| Avoidances | You can ask to avoid motorways, tolls, or ferries. Motorways here means OSM highway=motorway / motorway_link, motorroad=yes / expressway=yes, or a dual carriageway with lanes>=2 and maxspeed>=90 — not every E-road or urban arterial. |
Done |
| Stay in Country | Avoid crossing international borders, even if a foreign route is faster. Uses your trip origin country (Natural Earth Admin-0). Off by default. | Done |
| Official trails | For hiking/cycling, optionally prefer marked long-distance trails (off by default). Normal paths still work if the marked trail has a gap. | Done |
| Bike surface suitability | Bicycle / e-bike Drive setting: Road / Gravel / MTB. Unsuitable OSM surfaces and tracks are hard-excluded after the graph loads (does not rebuild packs). Default is Gravel (trekking). | Done |
| Motor surface preference | Car, truck, motorhome, and motorcycle: soft preference for good driveable surfaces (surface / tracktype) on connector snaps and along the route; untagged highway=track is treated cautiously. Internal costing only — no warnings in the UI. Default Car; Offroad / 4×4 relaxes the weighting (stored in config; no Drive-menu toggle yet). |
Done |
| Basemap POI icons | Offline Protomaps amenity icons (fuel, hospital, alcohol shops, cycle/repair, and the rest of the allow-list) use dedicated sprites, not a generic dot. Kind list: docs/poi-icon-whitelist.md. |
Done |
| Peak heights | Named mountain peaks show OSM elevation on the label (metres, or feet in the US unit profile — UK stays metres, same as HUD altitude). | Done |
| Glacier outlines | Ice polygons get a teal dashed outline so they stay visible against pale fill (same dash as nature reserves, different colour). | Done |
| Elevation contours | Opt-in brown isolines from the same Mapterhorn DEM as hillshade (not OSM contour vectors). Independent of 3D. Spacing follows Kartverket map-series intervals (minor / index 5×). Index lines labelled with elevation (metres, or feet in the US unit profile). Needs DEM: online tiles, or Download terrain DEM for offline. Off by default. Detail: docs/map-styles.md. |
Done |
| 3D hillshade | Optional hill shading from Mapterhorn DEM. Independent of contours — either, both, or neither. Offline needs Download terrain DEM. | Done |
| Eco routing | Prefer routes that use less energy by taking hills into account. A small leaf icon shows when eco is on. Pack-hit reweight is typically tens–hundreds of ms (eco_reweight_ms); long waits mean missing region packs or cold PBF, not eco math — incomplete corridors fail fast (missing_regions). Perf: docs/perf/region-to-region-graph-build.md. |
Done |
| Offline planning | Download a region once, then plan and see the route on the device. | Done |
| Long trip | Opt-in under Drive settings (off by default). With From/To set, Navi estimates a corridor of Geofabrik regions (adjacency graph; online BRouter primary / OpenRouteService fallback for the preliminary polyline), queues pack downloads on Wi‑Fi/Ethernet only, and can store those packs on a removable volume. Place index and Tools downloads stay on internal storage. Offline planning then uses multi-region packs with soft rest / overnight POIs on chunked multi-day legs. Privacy disclosure is shown in settings when enabled. | Done |
| Indexing | After a region download, a background job turns the OSM extract into compact routing packs so later plans are fast. You can plan while it runs; convert and place-index pause during a foreground plan so the PBF fallback is not starved. Interrupted place-index builds resume without wiping already-written rows; OSM updates skip a full place-index rebuild when the catalog generation is unchanged. | Done |
| Place search | Search places and set From / Via / To from the local place index (always). Optional Online place search is off by default; when on, an explicit Search submit may query Nominatim. Details: docs/online-place-search.md. |
Done |
| Multiple vias | Up to 4 intermediate stops for car / truck / bicycle (and hiking waypoints). The Via chip shows Via (n/4); each pick adds a stop and clears the search box for the next. A list under the chips has Remove / Clear all. Off-route replan keeps remaining vias. | Done |
| Use GPS | Fill From / Via / To from the live fix: coordinates appear immediately, then an optional nearby road-name upgrade. The field is the chip active when you tap — not whichever chip is selected after resolution finishes. GPS as Via upgrades the last via in place (does not duplicate). | Done |
| Map mark & saved places | Hold on the map ~4 s to mark a point; set From / Add as Via / To or save a named place (separate from Saved routes). Via adds until the 4-stop cap. | Done |
| Off-route / reroute | Sustained deviation shows Off route; motor profiles auto-replan from the live position only when From is empty or was set with Use GPS / My position. A typed or picked From stays sticky (never GPS-overwritten by auto-replan), even within 1 km of the fix. Hiking prompts first. | Done |
| Cancel planning | While Planning route… or Recalculating route… is shown, Cancel stops the in-flight native plan. Recalc cancel keeps the original route. | Done |
| Breaks & rest | Reminds you when a break is due and can suggest stops. Cars use hours between breaks; hiking/cycling use rest distances; trucks use legal driving-time rules where known. What is searched and used as pause POIs: docs/poi.md. |
Done |
| Drive bars | Top: altitude (cutout-aware padding; metres, or feet in the US unit profile). Bottom: zoom, live GPS speed, posted limit when known, break timer, trip ETA, current street, eco leaf. Speed and distance follow Display units. Speed line turns the error colour when GPS speed is over the applicable limit (display only — not a spoken nag). | Done |
| Display units | Drive settings: Metric (km, km/h), US (ft / mi, mph, altitude ft), or UK (yd then mi, mph, altitude m). First install infers once from SIM/network country (GB → UK, US/LR/MM → US, else metric; emulators stay metric). The chips always override; the choice is never re-inferred on travel. Internal values stay metric. | Done |
| GPS follow | Map follows you by default. Pan away, then tap Recenter. | Done |
| Map rotation | North-up, compass, or direction of travel. | Done |
| Moving icons | Can draw nearby tracked markers on the map. A live radio feed is not built in yet. | Partial |
| Seasonal road closures | OSM motor_vehicle:conditional / access:conditional hard-filtered against the planned departure time (Car/Truck honour it; Hiking/Bicycle do not). Verified on Friisvegen (way 361797686) on both bbox/PBF fallback and pack-hit (graph pack v3). Purely OSM-tag-driven — no jurisdiction pack. v1 limitation: multi-day trips that cross a season boundary are evaluated only at the planned departure instant (not re-evaluated day-by-day along the trip). |
Done |
| Norwegian road-sign warnings | Vendored NO: catalogue approach icons in Norway; explicit OSM traffic_sign / hazard tags. Same 750 / 150 / 25 m approach phases as maneuvers. See docs/road-signs.md. |
Done |
| Look forward | Without a planned route, GPS position + heading look ahead 300 m (±60°) for catalogue road signs, speed humps (NO:109), children facilities (generic 142), opted-in speed cameras, and an upcoming posted speed-limit plate from the existing road-label cell graph — same approach box (750 / 150 / 25 m) and jurisdiction gates as the route-corridor path. Dedicated 362 plates cover every-5 km/h values including 12 generated plates; odd OSM speeds still snap to the nearest shipped plate. Compact points load once per region. Detail: docs/road-signs.md. |
Done |
| Nearby attractions | Opt-in under Map / Tools → Plugins → Nearby attractions (off by default). Quiet top-right HUD chip for attractions, fishing, and craft alcohol (incl. cider) in an 850 m / ±30° heading cone — open-now filtered, not a hazard warning. Distinct from Look forward. Spec: docs/plugins/poi-lookahead-cone-spec.md. |
Done |
| IMU pitch / tilt / compass | Opt-in under Map / Tools → Plugins → IMU pitch / tilt / compass (off by default). Made for a phone or tablet mounted in a vehicle: live pitch, tilt and compass heading from the device sensors. A mounted unit is never perfectly aligned with the vehicle, so calibrate once: Find a level concrete surface, like the floor of your garage, then tap Calibrate. The unit will then use the current values as level. Reset removes the calibration; the status line shows whether the unit is calibrated and on which date. Calibration is rejected while the vehicle is moving. Wasm guest plus Android SensorManager bridge; detail: docs/plugins/imu-plugin.md. |
Done |
| Tunnel / GNSS-gap positioning | When GPS is lost or badly degraded (tunnels, deep cuts), the host keeps the map mark moving along the active route (or the current road edge) using the last GNSS speed, changed only by longitudinal acceleration outside a deadband, and a braking-aware standstill gate — same mount calibration as the IMU plugin. The mark turns amber while estimated, grey with Position lost after a time/distance give-up, then blends back when a good fix returns. No Google Play services (LocationManager + SensorManager). Detail: docs/tunnel-dead-reckoning.md. Validation: stationary on a real tablet; moving and tunnel behaviour in simulation and by on-device injection only, no real drive. On-device crawl exit 48.7 m against the 50 m limit. Speed changes gentler than 0.20 m/s² are not tracked in a tunnel. With no route, or on v8 packs, give-up is 6 min / 15 km. |
Done |
| CAT radio | Opt-in under Map / Tools → Plugins (off by default). Look up amateur repeaters within 150 km, auto-tune VFO A/1, follow LA5MR-style networks with hysteresis (leave after the last site — decision C), leave VFO B/2 to the user, and never transmit. Radios: Hamlib (Stable only) and native Benshi Bluetooth (VR-N76). Licence on the toggle: You may listen, but do not transmit without an amateur radio licence. Detail: CAT radio plugin, docs/CAT.md. |
Done |
| Children facilities nearby | When no tagged children / school sign is active, schools, kindergartens, and playgrounds still trigger a generic 142 Children approach warning (nearest facility wins; tagged NO:142 outranks this fallback). With a planned route: facilities within 200 m of the corridor. Without a route: covered by Look forward (300 m cone). Detail: docs/road-signs.md. |
Done |
| Speed camera warnings | Point cameras use the existing approach distance-phase UX; average-speed / section-control zones use a distinct enter/exit box. maxspeed:conditional is evaluated against live local time. Jurisdiction-gated like EC561 / allemannsretten: Norway/UK opt-in (OSM-sourced, may be incomplete); Germany/France/Switzerland and unknown jurisdictions decline — see docs/jurisdiction-rules.md. First-run opt-in dialog required (not silently enabled). Works on both planned-route corridor and Look forward. |
Done (display/warning only — no route-avoidance toggle, by deliberate product decision) |
| Map updates | Only when you ask — check for OpenStreetMap updates or download a fresh region. Never silent. On-screen copy is plain language (no internal planner dumps). | Done |
| Cross-region / cross-country prompts | Destinations outside downloaded data (including another country, e.g. Sweden) show Map data needed with the correct Geofabrik extract — not a silent partial route. Evidence: android-test-results.md Item 10. |
Done |
| Diagnostic logging | Tools → Diagnostic logging (off by default). When on, writes a dated session log under Internal storage → Documents → debug (navi_session_*.log) for copy over USB/MTP — no adb required. Covers GPS, camera, toggles, route plan/stages, eco, POIs, pauses, instructions, fuel, system. Not uploaded. Export diagnostic log shares the latest file. Detail: Settings → Tools and docs/debugging.md. |
Done |
| Weather overlay (HUD) | Map → Plugins → Weather overlay (also under Tools → Plugins; off by default). Opt-in MET Norway → Open-Meteo fetch with SQLite cache, fill-style Meteocons icons, stale labeling when offline/throttled. Host UniFFI path; product does not yet link the WASM plugin-host. | Done |
| Weather symbols on map | Nested Show weather symbols on map under Plugins (off by default; inert unless Weather overlay is on). place:city only at MapLibre zoom ≤ 8; max 10 symbols; 56 px min spacing; nearest-to-viewport-center priority. Town/village tiers and corridor overlay not shipped. |
Done |
| Plugins | A safe sandbox for future add-ons exists; most product plugins are not shipped yet. Weather and Nearby attractions use the host UniFFI path today (see rows above). IMU and CAT radio are opt-in (see rows above). DATEX road situations (opt-in, default OFF) use the navi-server feed — Norway / NPRA only today. | Host ready |
Hardware note: Real-device checks include Samsung Galaxy Tab S6 Lite
(SM-P613) and Google Pixel 9a. Car head units still need more real-world
testing before treating this as ship-ready. See Screenshots,
docs/real-hardware-testing.md, and
docs/android-test-results.md.
Nothing useful ships pre-loaded. Use Tools in the app (with internet), then you can go offline.
| Download | Need it? | What it is | Button in Tools |
|---|---|---|---|
| Map region (roads & places) | Yes for routing and search | OpenStreetMap extract from Geofabrik (example path: europe/norway/ostlandet), or published packs from the pack server when listed |
Download region (green, when pack server has the path) or Download region + build place index |
| Elevation | Strongly recommended for eco / hills | Height data for the area | Usually comes with region provision |
| Offline basemap | Needed for map graphics without internet | Visual map tiles (Protomaps) | Included in Download region (before place index; part of that region's full download) |
| 3D terrain | Optional | Height tiles for hillshade and elevation contours | Download terrain DEM (Mapterhorn) |
| OSM updates | Optional | Fresher roads/POIs | Check for OSM updates (never automatic) |
Minimum to plan a route: region download + place index.
Minimum for a usable offline map picture: Download region also pulls
basemap PMTiles (or stay online for Liberty).
Prefer a region (not a whole huge country) on tablets with limited RAM —
see Minimum hardware and storage.
Published pack-server countries and nested subregions (from live
current.json): docs/coverage.md.
After the region file is on disk, Navi indexes it in the background so later plans are fast — see Indexing (background after download).
Be patient — this takes time. After you download a new region or update map data from the internet (for example Check for OSM updates or a fresh region download), Navi must build the place index (search names for From / Via / To) and, on the local-bake path, the indexed routing packs. Both scan the full region file and can run for many minutes on a large extract. That is expected; leave the app open or return to it later.
Nothing to index → no indexing UI. Cold start and Tools do not start place-index / pack convert (and do not show an “In progress” indexing footer) when there is no real region PBF, no installed graph packs, and no pending extract/job. A selected Geofabrik path in the picker alone is not enough. (Previously, idle status lines and fixture/stub PBFs could look like indexing was running on an empty install.)
Baseline, not a guarantee. Numbers below were measured on a Samsung Galaxy
Tab S6 Lite (SM-P613, serial R52TB0JQEDE), Wi-Fi, pack-server path
(car + foot packs published; place index still built on device from the
Geofabrik PBF). Wall-clock comes from PHASE_TIMING logs (2026-09-17/18).
Other devices, networks, thermal state, or flash write pressure can be slower —
including a still-open unreproduced outlier where place index alone once took
~28 min on this same tablet (see Known issues).
Østlandet (europe/norway/ostlandet, PBF ≈ 434 MiB / 455 006 900 bytes):
| Phase | Wall-clock (approx.) |
|---|---|
| Pack fetch + install | ~8.0 min (483 s) |
| Geofabrik PBF download | ~0.7 min (41 s) |
| DEM corridor | ~0.3 min (18 s) |
| PMTiles basemap extract | ~7.4 min (445 s) |
| Place index (post named-routes fix) | ~5.8–6.2 min (350–369 s; four back-to-back rebuilds) |
| Pack-server path total (sum) | ~20–22 min |
Place-index sub-phases on that tablet after the named-routes streaming fix (representative run): admin ~50 s, ways ~10 s, nodes ~110 s, named routes ~35 s, SQLite FTS insert ~145 s.
Luxembourg (europe/luxembourg, PBF ≈ 45 MiB / 47 519 380 bytes):
| Phase | Wall-clock (approx.) |
|---|---|
| Pack fetch + install | ~0.6 min (37 s) |
| Geofabrik PBF + DEM | ~0.3 min |
| PMTiles basemap | ~0.7 min (43 s) |
| Place index | ~3.6 min (214 s) |
| Pack-server path total | ~4.6–5.5 min (pipeline ~279 s) |
Scaling: in the same instrumented session (before the named-routes fix), place-index wall time scaled roughly with PBF size — about 7.8× time for about 9.6× PBF bytes (Østlandet vs Luxembourg). Use that as a rough rule of thumb for other regions; it is not linear for every extract, and network / basemap cost is separate from place index.
Published pack payloads from the live pack-server catalog (car + foot profiles
only — sizes will grow when additional profiles such as bicycle are baked
server-side). Figures match docs/coverage.md live
generation sizes:
| Region | Pack payload (approx.) |
|---|---|
Østlandet (europe/norway/ostlandet) |
2.43 GiB |
Niedersachsen (europe/germany/niedersachsen) |
2.76 GiB |
Bremen (europe/germany/bremen) |
0.08 GiB |
Île-de-France (europe/france/ile-de-france) |
1.31 GiB |
Champagne-Ardenne (europe/france/champagne-ardenne) |
0.62 GiB |
Also budget the Geofabrik PBF, place index DB, offline PMTiles basemap, and
optional DEM on top of the pack payload (often another 1–2+ GiB for a large
landsdel). Full country tables:
docs/pbf-source-sizes.md,
docs/coverage.md.
When you request more than one region, Navi downloads and indexes them sequentially (never in parallel across regions):
- Priority: the region that contains the device's current GPS fix runs first (if that region is in the request set). Remaining regions keep the order they were requested.
- Per region: finish all downloads for that region (published packs and/or Geofabrik extract, elevation when provisioned, and the offline basemap PMTiles). Only then build on-device indexes (local-bake routing packs when needed, then the place index). The next region does not start downloading until this region's place index has finished.
- Search scope: From / Via / To place search only returns hits for regions
that have completed download and place-index build (
place-index-ready.json). A region that is still downloading, queued, or failed does not appear in search — including partial index rows from an interrupted build.
When Download region + build place index has saved the OpenStreetMap
extract (Geofabrik path), or Download region has installed published packs
from the pack server, Navi finishes the remaining downloads for that region
(basemap), then builds the place index — that is when the region becomes
usable for routing and search. Pack-server installs skip on-device routing pack
rebuild (packs are already baked) but still fetch the extract for place search.
That is not the map picture on screen (basemap tiles) and not the raw .osm.pbf
file itself alone — routing uses the packs; search uses the place index built
from the extract.
Until the place index for a region is marked ready, planning may use the slower
raw .osm.pbf path and place search omits that region. Tools shows progress as
Indexed maps / Place index during those phases; when it says Indexed
maps: ready (pack-hit), the next plan uses the packs — typically about 1.5–2
seconds on the reference tablet instead of tens of seconds. Live labels and
percent for these jobs are listed under
Progress status box.
If you leave or force-stop the app mid-download, the next launch resumes from
region-download.json (phase: packs, basemap, or place index), the download
queue file, and any .partial Geofabrik file — Tools shows Resuming download
of… / Resuming basemap… / Resuming place index… without needing to tap
Download again. Pack install restarts from the current file when mid-file resume
is unavailable; basemap reuses on-disk work where supported. An incomplete
place index keeps already-written SQLite rows on resume (it does not clear
the region and start from zero). After an OSM update, if the catalog generation
is unchanged, the place-index path skips a forced full rebuild.
Place-index size and compaction. Upgrading the place index from schema v5
to v6 copies every row into a new table. That leaves free pages inside
place_index.db and keeps a one-shot pre-migrate copy,
place_index.db.bak-pk-v6, next to it, so the volume can briefly hold the
index two or three times over. While the app is idle, a place index
compaction job reclaims this:
- It starts when the backup exists and the live file is much larger than it (more than 1.5 times). Nothing runs during a plan or an index build.
- It needs free space on the index volume of at least the live size plus a margin (the larger of 64 MB and 10 percent). Without that it defers, logs the reason, and retries at most once an hour.
- It writes a compacted copy with
VACUUM INTOto a temp file beside the live index, checks it (PRAGMA quick_check, per-region row counts equal to the live file), and swaps it in with one atomic rename under the place-index build lock. If rows were written since the snapshot, nothing is swapped. The live index is never written before that rename.VACUUM INTOneeds Android 11 or later; older devices skip the rewrite. - The backup is deleted only when every region present in both the backup and
the compacted index has the same row count. On any mismatch it is kept and
the regions are logged (
PlaceIndexCompacttag). - A plan or index build aborts the job at its next check; the stamp
(
place_index_compact.txt) stays, so it resumes on the next idle pass. A temp file left by a force-close is discarded and the job starts again.
While a Plan route (or auto-reroute) is running on that PBF fallback, background convert and place-index yield so they do not contend for the same extract. GPS-triggered speed-limit cone / road-near bbox builds skip for that window (one missed HUD update) and resume on the next fix after the plan finishes. Plan progress uses its own channel so convert/cone labels do not move the plan bar. The UI may also remind you that planning is faster once background indexing finishes.
What the background job writes:
| Pack | What it is for |
|---|---|
| Road / path graph | The network A* follows, per travel mode (car, foot, bicycle, and so on). Large regions are split into spatial tiles so a 4 GB-class device does not have to hold the whole region in RAM at once. |
| POIs and barriers | Huts, rest stops, lodgings, overnight buildings, glacier polygons, and similar features used for rest / overnight planning and hiking safety filters. |
| Wetland | Marsh and water polygons hiking uses to stay out of bogs (boardwalks stay on the graph). |
A separate place index (names for From / Via / To search) is built as part of the download button (after packs/extract and basemap on both pack-server and local-bake paths). On the local-bake path, indexed routing packs convert after downloads and before the place index; on the pack-server path those packs are already installed.
If packs are missing, stale, or still converting, planning still works via the
PBF fallback. Rebuild from a file already on the device with Rebuild indexed
maps (local PBF, background) — no re-download. More detail:
docs/indexed-map-format-plan.md. Memory
margin on lower-end 4 GB devices during conversion: Known issues.
Long-running work shows a pale yellow / translucent status chip near the bottom-right of the map, with a short label and often a percent done. The same text is mirrored in a pinned footer at the bottom of Tools (outside the scrollable region picker), in a fixed order: region download → basemap/DEM → place index → indexed maps. You do not need to scroll Tools to find active job status. When Tools is open, the map chip is suppressed for those same progress lines so the percent is not shown twice. When every tracked phase for the current download session has finished (packs + basemap/DEM + place index — fully done), that footer shows Ready! instead of the per-process lines.
While Download region is running, Tools keeps one progress line for the non-basemap phases of that job (place-index / indexed-maps duplicate lines are hidden so you do not see two competing percents); basemap/DEM labels use the PMTiles line in the same footer.
The chip clears when the job finishes (it must not stay stuck at 100%). Idle does not show the pale yellow box; Tools may still show Ready! until you start another download.
Every process that drives this progress UI:
| Process | How you start it | Typical labels you will see | Where else it appears |
|---|---|---|---|
| Download region (pack server) — green Download region when the path is published | Tools → region chip → Download region | Checking pack server… → Fetching packs… / Installing packs… → Downloading extract… → basemap (Downloading map tiles… / Planning extract… / Writing map archive…) → Place index: phases → (usable / Place index ready) | Tools region-download progress line; basemap/DEM-style labels may also show on the PMTiles line |
| Download region (local bake) — blue / default button when packs are missing or the server is down | Tools → Download region + build place index | Downloading region… (or Resuming…) with byte % → optional Downloading elevation… → basemap labels as above → Building indexed maps… → Place index: phases → (usable) | Same Tools progress line during the download |
| Place index (search names) | Part of Download region, or a background rebuild after an OSM update / local PBF | Place index: starting… / admin boundaries… / scanning ways… / scanning nodes… / named routes… / resolving context… / writing database… / Place index ready (phase-based %) | Tools place-index line when not inside an active region download |
| Indexed maps convert (routing packs) | Auto after local-bake downloads (before place index); Tools → Rebuild indexed maps; or when packs are stale | Building indexed maps: scanning bounds / graph tiling / POI + barriers… (~90%) / wetlands… (~95%) / Indexed maps ready; Tools idle text Indexed maps: ready (pack-hit) | Tools indexed-maps line; phase % jumps when a phase starts, not continuously inside the phase |
| Offline basemap only (PMTiles extract) | Included in Download region; also covered when that job writes map-tile labels | Downloading map tiles for region…, Planning extract…, Writing map archive… | Tools PMTiles progress line when those labels are active |
| Terrain DEM | Tools → Download terrain DEM (Mapterhorn) | Downloading terrain DEM… with byte % | Tools PMTiles/DEM progress line; Pause / Resume / Cancel apply to this job |
| Plan route | Route panel → Plan route | Loading map data for this route… / Combining map data from multiple regions… / Planning route: indexing area, reading roads, loading geometry, linking graph, break stops, done | Progress line + bar under Plan route; orange top banner Planning route… (Cancel); status chip |
| Recalculate / off-route replan | Auto (motor) or confirm (hiking) after leaving the route | Same plan labels; UI title Recalculating route… | Orange top banner with Cancel; status chip |
| Apply pending OSM update | Tools → Check for OSM updates then Apply pending OSM update | Download in progress…, then Map data updated. Preparing search and routes in the background. (place index + indexed maps continue as above) | Status chip / Tools status |
Related but not percent chips: the red SIMULATING banner is only for route simulation playback. Short one-shot messages (settings saved, profile changed, and so on) use the same chip briefly without a lasting percent.
Be patient. Place index and indexed-map convert on a large region can run for many minutes; the percent may sit still during a long phase. That is expected — see Indexing and Known issues.
A region download (OSM extract + indexed packs) and the offline basemap only cover that extract’s area. Navi does not silently invent roads or tiles outside it.
Planning a trip that leaves your data. Before Plan route, From / Via / To are checked against the bounding boxes of downloaded Geofabrik extracts.
- If any waypoint is outside every downloaded area, planning is blocked (no partial or guessed route).
- A Map data needed dialog offers a suggested download (for example Vestlandet or Nord-Norge). You can download from there, or dismiss and pick another destination.
- If From and To need different landsdels and those packs are already installed, planning uses the same corridor tile loader as a single landsdel: intersecting tiles are loaded from each Ready pack in one pass (no country extract and no separate stitch job).
- If a destination landsdel is not downloaded, the prompt suggests that missing region — not a full-country fallback.
- Cross-border destinations (e.g. Sweden) get a country-specific suggestion
when the waypoint lies in another catalog entry — see
android-test-results.mdItem 10.
Already navigating. There is no continuous “you left the map” fence while you drive.
- Basemap: tiles stop where the downloaded Protomaps region ends (or you fall back to online Liberty if the network is available).
- Guidance: keeps following the route you already planned while you stay on it.
- Off-route recalculation: uses the local region extract again. Outside that extract, snap / pathfinding can fail; you do not get the planning download dialog on auto-reroute. Download the covering region in Tools before you need to replan there.
Indexed packs match the extract they were built from. Leaving that area means no offline graph for new plans — not a soft fade-out.
Before Navi can search for a path, it builds an area graph for the corridor your trip needs: it loads the map tiles that cover the regions the route passes through and joins them into one routable network. That is normal preparation, not a hang — the progress line under Plan route, the orange top banner while planning, and the pale yellow status chip all explain what is happening (full label list: Progress status box).
Time depends on how much map data the corridor needs, not only on crow-flies distance:
- A short local trip inside one downloaded region typically plans in a few seconds.
- A long corridor (large bounding box / generous search pad) loads more tiles from that region and can take longer, even when From and To look close on a map.
- A trip that crosses between region packs (for example Østlandet and Vestlandet) loads tiles from each installed pack in the same step and joins them. That can take several seconds up to roughly half a minute on current devices for long cross-region corridors — still the same kind of work as a single-region plan, just more tiles.
If a needed region is not downloaded, planning stops with Map data needed instead of trying to parse a whole-country extract. Download the missing region in Tools, then plan again.
Step-by-step end-user guide (planning, Tools, breaks, saved places/routes, per-mode options, pilgrim coverage): How to use Navi.
A worked example of a multi-region road trip (OSM cider producers, south to
north): docs/cider-route.md.
Planning a route. Set From and To (and optional Via stops), pick a travel mode, then Plan route. You can add up to four vias: select the Via chip, pick a place (or Use GPS / map long-press Add as Via), then search again for the next — the chip shows Via (n/4) and a removable list appears under the summary. From is often set with Use GPS (select the From / To / Via chip first; the button label follows the chip). A typed or searched From stays as entered: auto off-route replan does not replace it with the live GPS fix (only empty From or Use GPS / My position follows GPS). Hiking paths need the Hiking mode — planning with Car uses the road network and will not follow foot trails properly. A Planning route… banner includes Cancel if you want to stop an in-flight plan. Percent and stage labels are documented under Progress status box.
Trip ETA and OSM speeds. Pre-departure motor ETA prefers OSM
maxspeed:practical, then posted maxspeed, then maxspeed:advisory, then a
highway-class fallback. minspeed floors motor ETA and excludes those edges
from foot/bicycle access. Live HUD / speed-camera limits still honour
maxspeed:conditional against local time. Graph packs are format v7 for
these fields — use Tools → Rebuild indexed maps (or re-download) if an
older pack is still installed.
Eco vs shortest. Shortest ignores hills. Eco makes steep climbs “cost” more.
Electric modes get some credit for downhill recovery. On installed graph packs,
eco reweight is a short overlay (eco_reweight_ms typically 50–260 ms); planning
time should stay in line with eco off. If a destination region pack is not
installed, the plan fails fast with a clear “Install … to plan this route”
message instead of spinning on a cold PBF build.
Official networks. Optional soft preference for marked hiking/cycle routes (Follow official hiking/cycling networks). Ordinary paths remain available so a gap never traps you. Separate toggles control networked cabins as waypoints and whether you are a network hut member for overnight planning (see Drive / vehicle).
Motor surface quality. For car-like profiles (car, truck, motorhome,
motorcycle), the planner prefers paved or well-graded connectors when a
better-surfaced snap point exists within budget, and applies soft edge costs
plus transition penalties when the route drops onto poor or unknown tracks.
This is silent — no pop-ups or log lines about surface class. Default mode is
Car (strict); Offroad / 4×4 turns the weighting off. Today the mode is
stored via the config API (surface_routing_mode); a Drive-settings chip is
not shipped yet.
Contours and hillshade. Tap the top bar: Contours draws elevation
isolines; 3D (experimental) draws hillshade. They are independent — either,
both, or neither. Both use the same Mapterhorn DEM (online tiles, or
Download terrain DEM for offline). Interval ladder, index labels, and
flat-terrain limits: docs/map-styles.md.
Places. Search fills From / Via / To. What counts as a hut, rest area, and so
on is documented in docs/poi.md.
Map long-press and saved places. Hold one finger on the map for about
4 seconds to mark a point, then set it as From / Via / To or save it under
Saved places (a single named coordinate — not a full Saved route).
How-to: docs/map-marking-saved-places.md
(Norwegian: docs/kartmerking-lagrede-steder.md).
Rest and overnight. Each mode has its own defaults. Long truck trips can
split into days with legal rest rules (EU or US packs where known). Long
car/bike/hiking trips can suggest overnight stops. Hiking overnight sites are
filtered away from buildings and glaciers (1 km to the glacier polygon edge);
rejected pins show a clear reason (for example Excluded: within 1 km of a glacier). With Network hut member off (default), overnight prefers
non-network cabins; a DNT/STF-style network hut is only a last resort and is
labelled as membership-required. Membership does not grant entry — it only
changes overnight preference. The bottom-bar Breaks toggle only shows or
hides the reminder — it does not invent a new rest law.
Map bars. Tap the top bar for map/display settings. Tap the bottom status
area for drive/vehicle settings (mode, break interval, fuel, e-bike, and so on).
The bottom bar also shows live GPS speed / posted limit when a fix
and an applicable limit are known (km/h or mph per Display units); overspeed is a colour change only today
(docs/current-street.md). Spoken escalating
warnings are a plugin spec, not shipped:
docs/plugins/adaptive-speed-warning-spec.md.
Children facilities nearby. If OSM has no tagged children / school warning
sign, Navi still warns when a school, kindergarten, or playground is nearby —
generic sign 142, same approach box timing as other road-sign warnings.
Along a planned route that means within 200 m of the corridor; on a
live drive without a route, Look forward covers them inside the
300 m heading cone. An explicit tagged NO:142 (or equivalent) wins over
this fallback. See docs/road-signs.md.
Look forward. Without a planned route, GPS position + heading look ahead
300 m (±60°) and drive the same approach chrome for catalogue signs, speed
humps, children zones, opted-in cameras, and an upcoming posted speed-limit
plate from the existing road-label cell graph. Compact point sets load once per
region (not re-parsed every GPS tick). Detail:
docs/road-signs.md,
docs/route-simulation.md.
Language: the app chrome is English only today. There is no language
menu yet, and Navi does not pick UI language from GPS or SIM country (that
would override the language already set on the phone). Docs may exist in
Norwegian (docs/Norwegian.md); that is documentation, not an in-app language
pack. A future translation plugin (selectable packs, fallback to English
when a key is missing) is described in
docs/plugins/i18n-translation-spec.md.
A working CSV for translators lives next to that spec:
docs/plugins/translations.csv.
Sense notes for words and phrases:
docs/plugins/translations-context.md.
English source strings list countries/regions in the column header; dialect
headers use country, - area, - dialect (documented in the i18n spec).
Settings are saved on the device (rest/fuel/vehicle in a small database; map display choices in app preferences).
| Setting | Plain meaning |
|---|---|
| Compass / Travel / N-up | How the map rotates |
| Snap rotation back to mode | After a manual rotate, return to the selected mode (on by default) |
| Trip ETA | Show time left to the destination on the bottom bar |
| Breaks | Show the “Break in …” reminder line (does not change how stops are planned) |
| Auto-zoom | Keep a chosen zoom while moving |
| 3D (experimental) | Optional hill shading on the map (independent of contours) |
| Contours | Opt-in elevation isolines from the Mapterhorn DEM (independent of 3D; off by default) |
| Map tilt | Tip the camera (0° / 35° / 45° / 60°) |
| Plugins | Per-plugin enable toggles (Weather overlay + optional map city symbols; Nearby attractions + optional hide hours-unknown; DATEX; all off by default) |
| Setting | Plain meaning |
|---|---|
| Travel mode | Car, bike, hiking, truck, … |
| Bike type | Bicycle / e-bike: Road / Gravel / MTB surface capability (hard-excludes unsuitable tracks) |
| Surface routing mode | Car / truck / motorhome / motorcycle only: car (default) prefers good surfaces; offroad / 4x4 relaxes surface costing. Config/API today — not a Drive-menu chip yet |
| Follow official hiking/cycling networks | Hiking / bicycle / e-bike: soft preference for waymarked networks (ordinary paths still usable) |
| Use networked cabins | Hiking / bicycle / e-bike: allow DNT/STF-style network huts as auto-via / waypoint candidates (off by default). Does not change overnight membership rules |
| Network hut member (DNT/STF/…) | Hiking only: when on, overnight may prefer network huts; when off (default), prefer non-network cabins and flag network stops as membership-required |
| Follow pilgrim routes | Hiking only; soft preference (off by default), falls back to normal hiking |
| Long trip | Opt-in multi-region corridor downloads (off by default). When on: Wi‑Fi/Ethernet-only pack queue along the route, optional removable storage for those packs, and a privacy note about BRouter / OpenRouteService for the preliminary region estimate. Status line shows needed / downloading / indexed regions |
| Stay in Country | Avoid crossing international borders, even if a foreign route is faster (off by default). Origin country from Natural Earth; may be longer/slower than a cross-border shortcut |
| Hours between breaks | How often you want a break (cars), or truck mandatory break-after time |
| Rest time | How long a break should last (suggestion / truck continuous break) |
| Next break as Time / Distance | Show break countdown in minutes, or as km/mi at an assumed cruising speed |
| Units | Metric, US (ft / mph), or UK (mi / mph). First-install default from SIM/network country; always overridable. UK altitude stays metres (not US feet). |
| Eco mode | Hill-aware energy costing (locked on for hiking/cycling) |
| POI search radius | How far aside the planner may look for huts / stops |
| Vehicle limits | Height/width/length/axle weight for clearance |
Route planning chrome (Route): From / To / Via, Plan, Simulate, avoidances
(Avoid motorways excludes highway=motorway / motorway_link, motorroad=yes / expressway=yes, and dual carriageways with lanes>=2 and maxspeed>=90; E-road ref is display-only;
Stay in Country keeps the route inside the starting country),
saved routes.
Open Tools from the planning panel (same screen as region / basemap downloads).
| Setting / action | Plain meaning |
|---|---|
| Download region / basemap / DEM | Offline map data (see What you need to download). Progress labels and percent: Progress status box |
| Pause / Resume / Cancel | Control an in-progress download. Region downloads also resume after a force-stop (HTTP Range from the .partial file) instead of starting over |
| Check for OSM updates / Apply pending | Opt-in refresh; never silent auto-download |
| Weekly update reminder | Optional nag only — does not download by itself |
| Diagnostic logging | Debug toggle (off by default). When on, Navi appends a pipe-delimited session log on the device so you can diagnose planning, GPS, and setting changes without adb logcat. When off, no new session file is written and native per-stage route-plan timing stays gated off |
| Export diagnostic log | Opens the Android share sheet for the latest session file (or tells you to turn logging on first) |
| Weather overlay | Opt-in internet weather under Plugins (off by default). Shows a HUD chip near your position with fill-style icons; MET Norway primary, Open-Meteo failover; throttled ~45 min; last-known cache when offline |
| Nearby attractions | Opt-in under Plugins (off by default). Quiet top-right chip for attractions / fishing / craft alcohol ahead in an 850 m cone; hides known-closed venues; optional “Hide when hours unknown” |
| DATEX road situations | Opt-in under Plugins (off by default). Live feed via navi-server is Norway / NPRA only today |
| Show weather symbols on map | Independent toggle under Plugins / Weather overlay (also off by default). When both are on, draws city weather icons at zoom ≤ 8 (place:city only, cap 10, 56 px spacing). Turning Weather overlay off clears map symbols too |
What the diagnostic log is for: bug reports, planning timing (ROUTE_PLAN /
ROUTE_PLAN_STAGES), and confirming toggles/settings on real hardware. It is
not a crash dump mirror of logcat, and it is not uploaded by Navi.
Where the file lives (USB file transfer / MTP — no adb required):
Internal storage → Documents → debug → navi_session_YYYY-MM-DD_HH-mm-ss.log
(Fallback: Download/debug, then app-private storage if Documents is not
writable.) Older sessions are rotated (last 10 kept). Full categories and
retrieval steps: docs/debugging.md.
Full control lists and truck/jurisdiction detail stay in the older deep docs linked from Documents when you need them.
These two numbers on the bottom bar answer different questions. They are not supposed to always match.
| Line | What it means |
|---|---|
| Break in XXX min (or km/mi) | “When is the next planned break due?” — based on your break interval (for example every 2 hours) minus how long you have already been driving since the last break. |
| ETA XXX min | “When do we expect to arrive at the destination?” — based on the remaining route. |
So if your trip is only 45 minutes but breaks are set to every 2 hours, you can see something like Break in 120 min next to ETA 45 min. That is expected: the break reminder is following the interval you configured, not the end of the trip. On a short trip you may finish before the break is “due.”
Other common reasons they diverge:
- Interval longer than the trip — set a shorter “hours between breaks” (or accept that no mid-trip break is needed).
- You are part-way along the route — break time counts down from the interval; ETA counts down the remaining road.
- Break shown as distance — minutes are turned into km/mi with a fixed assumed cruising speed (~80 km/h for display). That is not your live GPS speed, so the distance line is only a rough conversion.
- Truck legal clocks — for truck modes the interval can follow driving-time rules (for example a break after 4.5 h of driving), which still is not the same thing as “time to destination.”
- Before you start moving — both lines use planning estimates (posted speeds or a fixed walking/cycling pace). They update from real progress once GPS or simulation is moving.
Tip: choose a break interval that fits inside a typical day’s driving for your trip. There is currently no “split this trip into N equal legs” button — use the interval (and suggested stops) instead.
Navi helps you plan; it does not replace judgement, local law, or trail conditions.
- Hiking and off-trail segments may need care — use your eyes and local advice.
- Leaving the planned route (wrong turn, road closure, intentional detour)
is detected via cross-track distance. The approach box shows Off route
instead of turn distances that would be wrong. Motor profiles auto-replan
after a short sustained debounce; Hiking asks first (trail wander is often
intentional). Recalculation uses the same planner as Plan (pack-hit when packs
are ready; otherwise the slower PBF fallback) — see Known issues
and
docs/route-simulation.md. - Wild-camping distance defaults follow a Norway-oriented “right to roam” idea and may not apply in other countries.
- Hiking overnight exclusion (buildings / glaciers) uses the downloaded OSM region and barrier pack, not the visual basemap tiles — those can disagree; see Known issues.
- Truck rest packs only apply where the app can recognise the jurisdiction; otherwise it will not pretend to be a legal tachograph.
- Always treat map data (OpenStreetMap) as possibly incomplete or outdated until you refresh it yourself.
Minimum required hardware for the intended Automotive / embedded class of device:
| Piece | Minimum / practical note |
|---|---|
| CPU | 8 cores, about 2 GHz class |
| RAM | 4 GB. Prefer regional extracts on that class; whole large countries in one go are often too heavy. On the reference SM-P613 (~3.5 GB total), region use is fine via pack-hit or PBF fallback; background pack conversion still has thin system memory margin — see Known issues. |
| Storage | Leave room for the region file, place index, offline basemap, optional DEM, and indexed packs — often several GB for a region. Example pack payloads (car+foot only): Østlandet 2.43 GiB, Niedersachsen 2.76 GiB, Bremen 0.08 GiB — see Pack on-disk size. |
| GPU | MapLibre GLES is the default path (verified on SM-P613 Adreno and Pixel 9a Mali). |
Mitigations already in the design: regional downloads by default, preprocess-once
indexed packs (background convert after download; region usable immediately via
bbox/PBF fallback), and worker pools that leave room for the UI. Details:
docs/indexed-map-format-plan.md and
docs/architecture.md.
Planning latency note: when indexed packs are ready, motor pack-hit plans are
typically ~1.5–2 s on the reference tablet. Cold / missing-pack fallback is still
dominated by sequential .osm.pbf loads (graph build + POI/barrier), not A*
itself — see Known issues and reproduce with
Tools → Diagnostic logging
(ROUTE_PLAN / ROUTE_PLAN_STAGES).
Lead examples (Samsung Galaxy Tab S6 Lite SM-P613 and route simulation):
Landscape with optional 3D hillshade (offline Protomaps + local terrain):
Hiking corridor Skolla → Rondvassbu (SIMULATING):
GPS follow during simulation:
Portrait, offline Ostlandet Protomaps, 3D off:
Offline Protomaps military landuse (muted red) and glacier fill, Rena / Gjende:
More zoom ladder shots: docs/images/military-glacier/.
Offline Protomaps also labels glacier names from ~z12 (pois.kind=glacier);
online Liberty still has fill-only ice (upstream OpenMapTiles gap). Details:
docs/map-styles.md.
Car head-unit testing is still open —
docs/real-hardware-testing.md.
Idle HUD:
Map tilt 45° (3D off / on):
Follow / pan / Recenter / rotation:
Full gallery: docs/pictures.md (Norwegian:
docs/bilder.md).
| Document | What it is for |
|---|---|
docs/CONTRIBUTING.md |
How to help: fork from dev, GitHub basics (PR against dev), testing, docs, plugins, CI |
CodeInspection.md |
Complete list of per-PR CI jobs and what each Rust/Kotlin test suite checks |
docs/crates.md |
First-party Rust crates created here, and unaltered crates.io dependencies |
docs/architecture.md |
How the pieces fit together |
docs/codebase-map.md |
Where to change code for a given feature |
docs/pictures.md / docs/bilder.md |
Screenshot galleries |
docs/icons.md |
Where icon files live, licensing, and how to add SVGs |
docs/map-styles.md |
Online vs offline map look; 3D hillshade; elevation contours |
docs/poi-icon-whitelist.md |
Which offline POI kinds draw, and which shop kinds are held back |
docs/poi.md |
Place types and search |
| How to use Navi | End-user how-to (planning, Tools, breaks, saved places/routes, profiles) |
docs/online-place-search.md |
Optional Nominatim place search: setting, usage policy, limiter |
docs/cider-route.md |
Suggested Norwegian Cider Route (Siderveien): OSM brewery=cider stops south→north, with Navi region/leg notes |
docs/road-signs.md |
Norwegian road-sign catalogue, children-zone proximity, Look forward (300 m cone), approach phases |
docs/map-marking-saved-places.md |
Map long-press (4 s) and Saved places detail (Norwegian: kartmerking-lagrede-steder.md) |
docs/ec-561-truck-rest.md |
EU truck driving-time rules |
docs/fmcsa-truck-rest.md |
US truck hours-of-service |
docs/jurisdiction-rules.md |
Country/region rule packs |
docs/osm-updates.md |
Opt-in map updates |
docs/android-build.md |
Build/install Android APK (Linux, macOS, Windows hosts) |
docs/build-linux.md |
Linux host: tools, gpsd, adb, Android install |
docs/build-macos.md |
macOS host: tools, Android NDK, adb, Android install |
docs/build-windows.md |
Windows host: MSVC, tools, Android NDK, adb, Android install |
docs/debugging.md |
Debugging |
docs/real-hardware-testing.md |
Physical device checklist |
docs/android-test-results.md |
Chronological on-device / emulator instrumented evidence |
docs/CAT.md |
CAT / CATS radio control (Hamlib, auto-tune, network follow, safety) |
docs/cat-test.md |
CAT test report: dummy-rigctld CI, Hamlib in APKs, radio/baud UI, Espa→Dombås logs, CSV import |
docs/bevensen-mobilehome-campaign.md |
Bad Bevensen → Norway MobileHome AVD campaign (setup, bug fixes, corrected retest) |
docs/status.md |
Which docs are live status vs historical evidence |
docs/future-proofing-audit-2026-07.md |
Tracked future-proofing / open risk items |
docs/indexed-map-format-plan.md |
Phased evaluation of preprocess-once indexed routing maps |
docs/precomputed-index-and-route-cache.md |
Server / mirror of precomputed packs, commercial DB contrast, town-to-town route cache (direction; not shipped) |
docs/coverage.md |
Pack-server countries and subregions from current.json (TOC + region ids) |
docs/plugins.md |
Plugin host and roadmap (enable/disable; USB/Bluetooth I/O) |
docs/plugins/imu-plugin.md |
IMU pitch / tilt / compass for a vehicle-mounted unit: level calibration (opt-in plugin) |
docs/tunnel-dead-reckoning.md |
Host IMU-assisted tunnel / GNSS-gap dead reckoning (estimated mark, give-up, GPS hand-back) |
docs/plugins/lora-convoy-spec.md |
LoRa convoy status over Meshtastic (Meshstick USB / BLE radio; not shipped) |
See the docs/ folder for more specialised topics (voice, APRS, ECU, formulas,
and so on).
Per-PR GitHub Actions jobs and what each Rust / Kotlin test suite checks:
CodeInspection.md. Local commands before a PR:
docs/CONTRIBUTING.md.
A sandboxed plugin host exists so future add-ons can run safely. Most product
plugins do not ship in the app yet — that is intentional. Weather conditions
and Nearby attractions (850 m look-ahead discovery cone) are available today
via a host-owned UniFFI path (Map/Tools → Plugins; default OFF), not via
a linked WASM guest. The IMU plugin (pitch / tilt / compass for a vehicle-mounted
unit) is the exception: its wasm guest is built from source and staged into the APK
like the camping guest, and Android SensorManager feeds it through UniFFI.
Calibration: Find a level concrete surface, like the floor of your garage, then
tap Calibrate. The unit will then use the current values as level. Detail:
docs/plugins/imu-plugin.md.
CAT radio is also opt-in — see CAT radio plugin
below. DATEX road situations (Map/Tools → Plugins; default OFF) pull from
navi-server; the live feed currently covers Norway only (NPRA). Overview:
docs/plugins.md. The system requires a per-plugin
enable/disable control, and host-mediated USB / Bluetooth I/O for
hardware-facing plugins.
Opt-in under Map / Tools → Plugins (off by default). Host radio I/O lives in
navi-cat (Hamlib TCP/FFI and native Benshi Bluetooth); guest logic for
repeater select / network follow is the CATS wasmtime plugin
(plugins/CATS-plugin/). Spec:
docs/CAT.md.
What it does
- Repeater lookup within 150 km.
- Auto-tune of VFO A/1 (output frequency, duplex offset/shift, CTCSS/DCS).
- LA5MR-style network follow with hysteresis, and leaving the network after its last site (decision C).
- VFO B/2 left to the user (not programmed by Navi).
- Never transmits.
Supported radios and paths
- Hamlib —
rigctldover TCP, or Android FFI (libhamlib.so); Stable backends only. - Native Benshi Bluetooth — VGC/Vero VR-N76 (
productId0x0002/0x0103). UV-Pro / GA-5WB not yet confirmed.
Repeater sources
- OSM (currently all repeaters in Norway are mapped there).
- OpenRepeater.
- RadioID via navi-server.
- RepeaterBook only from KML/KMZ/CSV the user copies into
Android/data/no.navi.app/files/repeaters. The app never contacts repeaterbook.com. Android deletes that folder on uninstall. - AnyTone CSV from
filesDir/cat/import/. - The Update button in the plugin UI.
- Consensus relocation (default off): "Move non-OSM repeaters to the most likely site". When on, a repeater with no OSM row is moved only if at least two independent sources (RadioID, RepeaterBook KML, CSV) agree within 1 km. The target is a tall structure (
man_made=mast|tower|communications_tower,tower:type=communication) when its top is at least 15 m above the highest Mapterhorn sample in that circle, otherwise that sample. Elevation iselevation_at(ElevationService/ElevationCache). A missing DEM tile means no move. Turning the setting off restores each original position. An OSM repeater is never moved. The published Norway bundle does not include structure tags, so a structure is used only when a caller supplies one.
Licence sentence on the toggle (exact copy):
You may listen, but do not transmit without an amateur radio licence.
What is tested
- Hamlib backend: automated tests with the Hamlib dummy rig (model 1) on
desktop (Hamlib 4.7.0) and the Android emulator (Hamlib 4.7.2, guest
6 cores — emulator maximum). Verified: Espa→Dombås / Espa→Litjfossen switch
order for LA5MR, Standalone, and auto (unplanned and planned-route), named
model pills with green connected state, read-back fields (
get_freq, shift/offset, CTCSS/DCS), 60 s hysteresis, VFO 2 untouched, 1750 Hz handling (CTCSS off, no burst call), mid-replay Disconnect (OK: disconnected, no crash), empty drop-folder Update after fixture cleanup. - Real Hamlib radios: not tested.
- VGC VR-N76 and similar Benshi-protocol radios (Bluetooth): no automated test; VR-N76 tested manually over Bluetooth by the maintainer (5 s VFO A stepping on Espa→Dombås and Espa→Litjfossen); other Benshi radios not tested.
- 1750 Hz burst repeaters: the app tunes them but never sends the burst; the user does that manually.
- Consensus relocation: the published OSM bundle has no structure tags, so in production it moves to the highest DEM point only.
- Licence: you may listen, but do not transmit without an amateur radio licence.
Evidence and how to re-run: docs/CAT-test-report.md.
Guest overview: plugins/CATS-plugin/README.md.
| Spec | Topic | Status |
|---|---|---|
docs/plugins/i18n-translation-spec.md |
Future UI languages (English-only today). Translator table: translations.csv; context: translations-context.md |
Not implemented |
docs/plugins/right-to-roam-camping-spec.md |
Wild-camping suggestions (plugin, not core) | Not implemented |
docs/plugins/safety-resupply.md |
Fuel/water resupply ideas | Not implemented |
docs/plugins/traffic-information.md |
Traffic data sourcing research (DATEX II limits, RTL-SDR TMC/TPEG) | Not implemented (research) |
docs/plugins/datex-plugin.md |
DATEX road situations via navi-server (Norway / NPRA only today; default OFF). How to enable services + poll cadence on the server | Implemented (opt-in) |
docs/plugins/datex-npra-client.md |
NPRA DATEX II v3.1 pull client sketch (access, Basic Auth, endpoints; not used by the product APK — credentials stay on navi-server) | Not implemented (legacy sketch) |
docs/plugins/weather-plugin.md |
Weather overlay — HUD chip + optional city map symbols (host UniFFI; WASM guest scaffolded, not linked into the product APK) | Implemented (opt-in) |
docs/plugins/weather-icons-reference.md |
What each weather icon slug means (fill style) | Reference (assets shipped with weather) |
docs/plugins/instrument-cluster-agl-spec.md |
Export nav state + approach warnings to instrument clusters | Not implemented |
docs/plugins/animated-icons-spec.md |
Animated icons | Not implemented |
docs/CAT.md |
CAT radio control — Hamlib RigBackend (TCP rigctld + FFI), native Benshi, CatStatusSheet model/baud, never auto-TX; licence: You may listen, but do not transmit without an amateur radio licence. See What is tested in that doc. |
Implemented (opt-in) |
plugins/CATS-plugin/ |
CATS WASM guest — repeater select / auto-tune / network follow under wasmtime (plugin.json name cat) |
Implemented (opt-in) |
docs/APRS.md |
APRS protocol / moving stations — display + range filtering exist; RF decode, ignored callsign (hide own station), and IQ test links documented there; DSP notes in docs/APRS-SDR.md |
Not implemented (partial core display) |
docs/plugins/custom-alert-sounds-spec.md |
Short alert tones (road signs, cameras, overspeed earcon) | Not implemented |
docs/plugins/horse-trekking-spec.md |
Equestrian lookahead and access guidance (Hiking is the interim stopgap) | Not implemented |
docs/plugins/adaptive-speed-warning-spec.md |
Spoken escalating overspeed (percentage tiers) | Not implemented |
docs/plugins/poi-lookahead-cone-spec.md |
Nearby attractions look-ahead cone (host UniFFI + quiet HUD; WASM scaffold; default OFF) | Implemented (opt-in) |
docs/plugins/imu-plugin.md |
IMU pitch / tilt / compass for a vehicle-mounted unit, level calibration (wasm guest staged into the APK, Android sensor bridge; default OFF). Calibration: Find a level concrete surface, like the floor of your garage, then tap Calibrate. The unit will then use the current values as level. | Implemented (opt-in) |
docs/plugins/lora-convoy-spec.md |
LoRa convoy status over Meshtastic — Meshstick USB SX1262 stick or BLE node; location/speed/fuel/charge | Not implemented |
docs/voice-guidance.md |
Turn-by-turn spoken maneuver guidance — pre-recorded clips only; distinct from docs/plugins/voice-command.md |
Not implemented |
docs/plugins/voice-command.md |
Spoken navigate / save-place / nearest-POI alternative (on-device ASR/TTS). Distinct from turn-by-turn docs/voice-guidance.md |
Not implemented |
| Icons (where they live) | Map/turn/POI/status icon paths and licences — see docs/icons.md |
Documentation (assets in-repo) |
Map, turn, POI, and status icons are files in the repo — they are not generated
at runtime. Authoring, resolution order, and licences:
docs/icons.md.
| Path | What is there |
|---|---|
core/src/icons/ |
Full set (source of truth for desktop / core). Mostly Navit (GPL v2). Custom Navi files here include leaf.svg (eco) and speed_camera.svg. |
app/src/main/assets/icons/ |
Android lean pack — a size-trimmed copy shipped in every APK. Keys missing here fall back to unknown.svg on device. |
core/src/icons/road-signs/ |
Norwegian traffic-sign SVGs (NLOD 2.0, not Navit). Android copy: app/src/main/assets/icons/road-signs/. |
core/src/icons/aprs/ |
APRS moving-icon symbols. Android copy: app/src/main/assets/icons/aprs/. |
plugins/weather/icons/ |
Meteocons static weather SVGs (MIT). Animated SMIL set: plugins/weather/animated-icons/. Spec: docs/plugins/weather-plugin.md. |
app/src/main/res/mipmap-* |
Android launcher (home screen / app drawer). Separate Navi brand art, not from Navit. |
docs/icons/open-app.svg |
Splash / open-app brand mark (Inkscape source). Android drawables: app/src/main/res/drawable/ic_splash*.xml. |
To add or override a map/POI icon, put an SVG in core/src/icons/ (and copy it
into the Android lean pack if it must appear on device). See
docs/icons.md.
Please read docs/CONTRIBUTING.md first. It covers
how to fork github.com/Supermagnum/Navi,
check out dev, keep your fork in sync, and open a pull request with
base branch dev. Clone steps in Building and installing
are for a local build; they are not a substitute for a fork if you want to send
a change.
Short version of CI expectations:
| Area | Expectation |
|---|---|
| Rust | cargo fmt, Clippy with warnings denied, tests |
| Kotlin | ktlint, detekt, unit tests |
| Android | ./gradlew :app:assembleDebug |
Clone from GitHub first. Development is on dev (newest features); main
is the default clone target (a plain git clone checks out main). Install Git
if needed (sudo apt install git on Debian/Ubuntu — other systems in
docs/build-linux.md).
To build or install locally (no pull request):
git clone https://github.com/Supermagnum/Navi.git
cd Navi
git checkout devTo contribute a change: do not only clone this URL. Fork the repository,
clone your fork, and work on dev — step-by-step in
docs/CONTRIBUTING.md.
See the top-level F-Droid section for the package URL
(no.navi.app), fdroiddata recipe, and how the index version can lag
dev sideloads. The APKs below are for testers and developers who need a
specific dev build (or cannot use F-Droid).
Use the signed release build — this is what hardware testers should install when they are not using F-Droid. The APK is signed with the project upload keystore so Android accepts it as a normal install (not an unsigned or debug-only package).
| Artifact | Role |
|---|---|
compiled/navi-release.apk |
Install this — signed release APK (arm64-v8a, versionName 0.3.30-beta, versionCode 33) |
compiled/SHA256SUMS |
SHA-256 checksum for integrity checks |
compiled/SHA256SUMS.asc |
Detached GPG provenance signature (not Android APK signing) |
You do not need a Rust/NDK toolchain to install it.
- On the device: enable Developer options and allow installs from your
browser or file manager (USB debugging only needed for
adb). - Download
navi-release.apk(latest ondev). - Optional integrity check on a PC:
cd compiled
sha256sum -c SHA256SUMS
gpg --verify SHA256SUMS.asc SHA256SUMS- If an older Navi build with a different signature is already installed,
uninstall it first (
adb uninstall no.navi.appor Settings → Apps). - Install and launch:
adb install -r compiled/navi-release.apk
adb shell am start -n no.navi.app/.MainActivityOn the device you can also open the raw download link in the browser and tap the downloaded APK (allow installs from the browser if prompted).
This APK is signed with the project upload keystore (local sideload key — not Play production signing). It is the intended tester build, not the debug keystore.
A debug-signed APK remains in compiled/navi-debug.apk
(arm64-v8a + x86_64, same package as ./gradlew :app:assembleDebug). Use it only for quick
local smoke tests when you are not exercising the release signing path.
adb install -r compiled/navi-debug.apk
adb shell am start -n no.navi.app/.MainActivityBrowser download:
compiled/navi-debug.apk
or
raw/main/compiled/navi-debug.apk.
To rebuild from source, follow the sections below.
The product APK is built the same way on Linux, macOS, and Windows:
compile libnavi.so with the NDK, then assemble/install with Gradle. Host-specific
setup (SDK paths, NDK clang, adb) lives in the OS guides; the shared recipe is
docs/android-build.md.
| Host OS | Install tools, NDK, adb |
Then follow |
|---|---|---|
| Linux | docs/build-linux.md (SDK/adb sections + Android install) |
docs/android-build.md |
| macOS | docs/build-macos.md |
same |
| Windows | docs/build-windows.md (use Git Bash for scripts/*.sh; .\gradlew.bat from PowerShell is fine) |
same |
Once per machine: Rust Android targets, JDK 17, Android SDK (API 36), NDK,
and ANDROID_HOME / ANDROID_NDK_HOME (see the OS guide). Point
.cargo/config.toml linkers at your NDK’s host prebuilt (linux-x86_64,
darwin-arm64 / darwin-x86_64, or windows-x86_64).
# From the repo root (bash: Linux/macOS Terminal, or Git Bash on Windows)
export ANDROID_HOME=… # see OS guide for typical path
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/<version>"
rustup target add x86_64-linux-android # once
./scripts/build-android-native.sh x86_64-linux-android release
./gradlew :app:assembleDebug # Windows PowerShell: .\gradlew.bat …
./gradlew :app:installDebug
./scripts/launch-navi-emulator.shexport ANDROID_HOME=…
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/<version>"
rustup target add aarch64-linux-android # once
./scripts/build-android-native.sh aarch64-linux-android release
./gradlew :app:assembleDebug
./gradlew :app:installDebug
# Equivalent:
# adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n no.navi.app/.MainActivityConfirm the APK contains the arm64 library:
unzip -l app/build/outputs/apk/debug/app-debug.apk | grep 'lib/arm64-v8a/libnavi.so'On Windows PowerShell you can use Gradle install (.\gradlew.bat :app:installDebug)
or adb install -r app\build\outputs\apk\debug\app-debug.apk.
Debug installs use the Android debug keystore. A release package is what you sideload as release, hand to F-Droid-style checks, or smoke-test as an AAB.
A prebuilt upload-key-signed release APK for testers is committed at
compiled/navi-release.apk (versionName 0.3.30-beta,
versionCode 33; see Install a prebuilt APK). To rebuild locally:
- Native library for every ABI you ship (store AABs usually need both):
export ANDROID_HOME=…
export ANDROID_NDK_HOME="$ANDROID_HOME/ndk/<version>"
./scripts/build-android-native.sh aarch64-linux-android release
./scripts/build-android-native.sh x86_64-linux-android release- Local upload keystore (optional but recommended for installable release
APKs / AAB smoke). Creates gitignored
app/keystore/navi-upload.jks— for local testing only, not Play production signing:
./scripts/make-upload-keystore.shIf that file exists, the release build type signs with it. Override
passwords/alias with Gradle properties navi.upload.storePassword,
navi.upload.keyAlias, and navi.upload.keyPassword if needed. Without a
keystore, Gradle still produces release outputs, but they may be unsigned.
- Assemble:
# Signed/unsigned release APK
./gradlew :app:assembleRelease
# → app/build/outputs/apk/release/app-release.apk
# Play-style app bundle
./gradlew :app:bundleRelease
# → app/build/outputs/bundle/release/app-release.aab- Install a release APK (signatures differ from debug — uninstall the debug
build first if
adbrefuses the upgrade):
adb uninstall no.navi.app # only if a debug/other-signed build is present
adb install -r app/build/outputs/apk/release/app-release.apk
adb shell am start -n no.navi.app/.MainActivity- AAB smoke (optional): validate / split / install with
bundletool as in
docs/android-api36-plan.md.
Current versionName / versionCode live in app/build.gradle.kts
(0.3.30-beta / 33 at time of writing). Bump those before a tagged or
F-Droid release. F-Droid-style Podman reproducibility:
tools/fdroid-check/README.md. Full shared
recipe: docs/android-build.md.
| Host | Guide |
|---|---|
Linux (navi-desktop, gpsd, core tests) |
docs/build-linux.md |
| macOS (tools + optional desktop shell) | docs/build-macos.md |
| Windows (MSVC, tools + optional desktop shell) | docs/build-windows.md |
core/— routing, places, rest rules, icons (Rust). Icon SVGs:core/src/icons/navi-ffi/— bridge to Android and other hostsapp/— Android UI (Kotlin). On-device icon pack:app/src/main/assets/icons/plugin-host//plugin-sdk//plugins/— future pluginsdocs/architecture.md— how it fits together
cargo test -p driver-break-core --test planner_options_routes
cargo test -p navi-plugin-host --test isolation -- --nocaptureLarge map-file integration tests are usually marked #[ignore] and need
fixtures under core/target/integration-fixtures. See
docs/test-results.md.
Navi is offline-first. The network is used only when you choose to download or update.
| Data | Source | Used for |
|---|---|---|
| Roads & places | OpenStreetMap via Geofabrik .osm.pbf |
Routing and search |
| Map updates | Geofabrik diffs / fresh extract | Opt-in refresh only |
| Elevation | Public DEM tiles | Eco / hills; Mapterhorn DEM also drives hillshade and contours |
| Map picture | OpenFreeMap Liberty (online) or Protomaps PMTiles (offline) | What you see on screen |
| Position | Device GPS (or gpsd on Linux) | Where you are |
| Icons | Mostly Navit-derived SVG; custom leaf / speed_camera |
Markers and turns |
Country/region visual extracts can also be prepared with PMT-splitter.
-
Place-index wall-time outlier (known, unreproduced). On SM-P613 (2026-09-17), one Østlandet place-index build took ~27.9 min (
place_index.total1672.7 s, same 1 486 764 rows as faster runs). A same-day build finished in ~4.8 min, and four back-to-back rebuilds after a named-routes scan fix (2026-09-18) all clustered at ~5.8–6.2 min. The ~28 min run was slower across unchanged phases too (admin ~241 s vs ~52 s; SQLite insert ~681 s vs ~145 s) — not explained by named-routes alone. Thermal Status and flash free-space were healthy on the fast repro runs (~74–82% Data-Free); no iostat/thermal HOST snapshot exists from the slow timestamp. A further run under deliberate memory / flash / background-app pressure (Chrome/Maps/YouTube started, ~1–2 GB/data/local/tmpwrite churn immediately before index) still finished in ~5.6 min (place_index.total334.2 s) — did not re-enter the ~28 min mode. Treat ~6 min as the current Østlandet place-index baseline on this tablet, and treat ~28 min as an open field risk, not as resolved. Pipeline phases logPHASE_TIMINGHOST (RAM / thermal /avail_bytes/ processproc_*_bytes) and IO_PROXY (per-phase/proc/self/iodeltas + MB/s, withsuspected_disk_contention=1when throughput falls far below the SM-P613 healthy floor). GrepHOST phase=/IO_PROXY phase=/suspected_disk_contention=1in logcat (PHASE_TIMING/NaviNative) or a diagnostic session log. Permanent platform limit: system-widedisk_*_sectorsstaydisk_stats=unavailableon the app UID (SM-P613 denies/proc/diskstatsand/sys/block). AndroidStatFs/StorageStatsManageronly expose capacity / per-app usage — not other apps' flash traffic — so there is no rootless system iostat. The IO_PROXY flag is the available contention signal; it cannot name the contending writer. -
Background indexing is still slow on region-scale extracts, but improved. On the reference SM-P613, full Østlandet convert dropped from about 14.8 min to about 10.6 min after wetland single-pass tile assignment and a shared car+foot PBF parse (host ~143 s → ~110 s), then to about 7.4 min after folding POI and barrier/danger-geometry extraction into one shared blob-parallel two-pass walk (
poi_ms≈38 s, same 10870 POIs / 1073435 barrier segs as before; peak RSS 1569 MB, vs 1563 MB). Of the reduced ~7.4 min total: graph ~58%, wetland ~32%, POI+barrier walk ~9% (shares of the new total; the old ~41/~24/~34 split was of 10.6 min — POI+barrier dropped in absolute time, not relative to a slower extract). You can still plan while indexing runs; plans are much faster once packs are ready. Longer-term relief (precomputed packs from a mirror such as navi.app, plus optional town-to-town caches — Navi does not ship a commercial vendor routing DB today):docs/precomputed-index-and-route-cache.md. -
Indexed-map progress bar is phase-based, not continuous. Tools shows
Indexed maps (background): …with a percentage that jumps once when each convert phase starts (graph tiling, POI + barriers at ~90%, wetlands at ~95%), not as work proceeds inside the phase. A new percentage means that phase has begun, not that it is actively advancing; a wedged phase leaves the bar frozen with no visual distinction from “almost done”. On the reference SM-P613 Østlandet convert, typical phase walls are roughly POI + barriers ~38 s and wetlands a couple of minutes (see the background-indexing bullet above); much longer at the same label usually means memory pressure or a competing PBF walk — force-stop and relaunch, or wait for pack-hit before planning. -
Long-distance route planning is slow. It takes some time for the app to compute these routes. With Long trip on (or cold / missing packs), graph build and related phases can run for many minutes; the UI progress may sit still and look hung even while the process is working. Patience is a virtue. Cold / missing-pack planning uses PBF graph build; pack-hit planning is much faster: parallel tile mmap/deserialize cut host warm
graph_build_msby roughly 35–47% on short/medium/long Ostlandet routes; on SM-P613 pack-hit short/medium/long warm walls were about 4.1 / 8.4 / 5.4 s (not the multi-minute PBF fallback). Details and older pack-hit vs pack-miss baselines are in the planning-latency bullet below. Sweden-style single-country PBF (known cost, not a hang): server packs for Swedish län (Halland, Västra Götaland, Skåne, …) ship.rkyvgraphs only. Geofabrik has no leaf extracts for those regions — onlysweden-latest.osm.pbf(~840 MB). Place-index and ferry overlay for every län stem share that one country file. When densify needs ferry overlay for a län stem, it walks the full country PBF (typically a few minutes per stem); TripAabb / pad retries can repeat the scan for each stem. The same class of slowdown applies to any country that has subregion packs but only a single country PBF. A respectful request to the team at Geofabrik for a split of Sweden by län (and the same for Finland) should resolve this ferry-overlay / place-index cost; ideally all countries would be published as their respective subregions so leaf packs have matching leaf PBFs. Evidence:docs/bevensen-mobilehome-campaign.md(post-corridor_readywall dominated by repeatedsweden-latestferry_overlayscans, not A*). -
Plugins: content add-ons are intentionally not shipped yet, as they have not been made.
-
UI polish: the screens work but still need visual tidy-up on car displays.
-
Moving icons: drawn with a Compose overlay today; native map symbol layers are not the primary path yet.
-
Map / GPU quirks: some emulator and phone GPU setups have historically crashed or washed out hillshade; the project defaulted to MapLibre GLES after SM-P613 and Pixel 9a checks. Details in
docs/map-styles.mdanddocs/debugging.md. -
Screenshot-only lake fringe: a soft blue rim around water can appear in captures but not while using the app live — see
docs/map-styles.md. -
Region-scale pack conversion has thin memory margin on lower-end 4GB-class hardware. Measured on a Samsung Galaxy Tab S6 Lite (SM-P613, ~3.5GB total RAM — below this project's nominal 4GB floor): a full Østlandet-scale background conversion completed successfully with no crash and no process kill, but system-level available memory dropped to ~329 MiB at its lowest point, ~250 MiB of swap was used, and Android issued
TRIM_MEMORY_RUNNING_CRITICALto other running processes during the conversion's POI phase. This indicates real, if survived, system memory pressure — not a comfortable margin. Devices with less RAM than this reference device, or under heavier concurrent load (more background apps, less free memory at the time conversion starts), remain an open risk. Region download and immediate use are unaffected (bbox/PBF fallback works immediately regardless); this risk is specific to the background pack-conversion step. On ~4GB-class devices the tiled graph builder now spills filtered ways to the app data dir and keeps only routing-relevant tags in RAM (instead of holding every highway + full OSM tag map until the first tile), which previously caused LMK with zero.rkyvwritten. Further margin work (e.g. smaller tile cells) may still help on the tightest hardware. Cross-ref:docs/indexed-map-format-plan.mdand Minimum hardware and storage. -
Cold / missing-pack planning is still data-loading-bound; pack-hit is not. A* itself is typically sub-second. With indexed packs ready (Phase 4 + 4b; see
docs/indexed-map-format-plan.md): motor pack-hit ~1.5–1.8 s vs cold missing-pack ~31 s on Hedmark 162 km; wetland load 18.6 s → 93 ms (~199×) on SM-P613; long Hiking OD that previously aborted ~6 min completes (~61 s) withwetland_pack_hit. Historical pre-pack Car Espa→Atnbrufossen (SM-P613):plan_duration_ms=26835withgraph_build_ms=17571,poi_barrier_ms=8045,astar_ms=378— that ~15–27 s class remains the fallback when packs are missing, stale, or still converting in the background..navigphdeprecated (ignored on every plan — do not expect.navigphfiles to speed anything up). Host re-check (release, Ostlandet, 2026-08-24): without packs, Car Espa→Atnbrufossen ~54 s (graph_build_ms≈29 s+poi_barrier_ms≈25 s,astar_ms≈0.3 s,pack_hit=falseboth back-to-back runs); with packs ~2.7 s (pack_hit=true,graph_build_ms≈1.5 s,poi_barrier_ms≈0.3 s). Host pack-hit after parallel tile load (2026-08-26): warmgraph_build_ms~758 / ~1484 / ~983 ms on short / medium / long Ostlandet car routes (was ~1398 / ~2222 / ~1862 ms sequential). Hiking Skolla→Rondvassbu ~104 s without packs vs ~25 s with packs (pack_hit/wetland_pack_hit/poi_pack_hittrue; remaining time is mostlynetwork_pref_ms+wetland_ms+multiday_ms, not A*). Cabin prefs (use_networked_cabins) do not invalidate the graph cache. Region-scale packs now include tiled wetland + overnight buildings (POI/barrier v2): short Atnbrufossen hike on SM-P613 159 s → ~3.1 s withwetland_pack_hitandovernight_buildings_pack_hit. If planning feels extremely slow across modes, check Diagnostic logging forpack_hit=falseand use Tools → Rebuild indexed maps (or wait for background convert after download). Plan-button session logs now includepack_hit/poi_pack_hitandROUTE_PLAN_STAGES(same as off-route recalculation). Graph packs are format v7 (OSM practical/advisory/minspeed and related fields). Stale packs from an older format fall back to PBF until you rebuild. Pixel UI multi-minute Espa→Atnbrufossen stalls (36 min / 193 s / 294 s / 314555 ms) were a fixture-PBF pack-dir miss, not a planner bug — seedocs/status.md(2026-08-28). The UI status also warns when a completed plan used the PBF fallback. Concurrent convert / place-index / GPS cone PBF readers are coordinated during a foreground plan (pause / skip — see Indexing); without that, pack-miss plans on a large extract can stretch into many minutes. Reproduce stages with Diagnostic logging →ROUTE_PLAN/ROUTE_PLAN_STAGES(docs/debugging.md). See alsodocs/status.md. -
Rerouting after a detour is not instant. Off-route (cross-track beyond ~75 m motor / ~100 m hiking) reuses the same planner: pack-hit when packs are ready (~seconds class matching Plan), otherwise the slower PBF fallback. While off-route, the approach box shows Off route. A Recalculating route… banner is shown during the wait (with Cancel). This is an expected wait, not a hang. Motor profiles auto-reroute after a short sustained debounce (~5 s); Hiking prompts first. See
docs/route-simulation.md. -
Hiking plan speed on huge areas (addressed for packs): overnight buildings use a 1.5 km corridor pre-filter over pack-stored centroids when POI/barrier v2 packs are ready (exact 150 m allemannsretten check unchanged). Historical DNT Åkersætra→Rondvassbu (~139.9 km corridor;
overnight_scan_bench, debug): bbox-all 102 556 buildings / ~180.7 s load → corridor 487 buildings / ~83.1 s load. Graph/wetland/overnight pack-hit removes that PBF path when packs are ready (fallback remains if packs are missing or still converting). -
Break timer ≠ trip ETA: by design — see Break timer vs trip ETA.
-
Overnight glacier safety vs basemap can disagree. Hiking overnight exclusion (
SAFETY_MIN_GLACIER_DISTANCE_M, 1 km to glacier polygon edge) reads Geofabrik.osm.pbf/ the.navi-poi-barrierpack. Offline map ice fill and glacier name labels come from a separately downloaded Protomaps PMTiles extract. Those pipelines update independently (different Tools actions and build dates). Confirmed on SM-P613 Ostlandet: PBF mtime vs PMTiles content date differed, and at Gjende (OSM way380644665) pack geometry and basemaplanduse.kind=glaciertiles did not cover the same footprint. A tent site may therefore be excluded near ice the map does not show (or vice versa). The plan UI surfaces the reason explicitly (e.g.Excluded: within 1 km of a glacier) so the decision stays legible when map and pack disagree. Future consideration (not built): optional “refresh basemap after OSM update” prompt. Seedocs/poi.mdanddocs/map-styles.md. -
Finest contour interval on flat terrain is not fully verified. At close zoom the 5 m / 25 m ladder can look sparse or miss rings on genuinely flat sites (DEM sample spacing vs isoline threshold). Mountainous areas (for example Gjendebu) are the regression site. Detail:
docs/map-styles.md. -
Online Liberty has no named glacier labels. OpenFreeMap Liberty / OpenMapTiles expose ice as fill only (
landcover_ice); there is no glacier POI name path to style. Navi adds a dashed ice outline for visibility. Offline Protomaps labelspois.kind=glacierfrom ~z12. Not a Navi Liberty regression — seedocs/map-styles.md. -
Pilgrim stamp / credential offices have no stable OSM tag. Official pilgrim centers (pilegrimspass / credencial stamp points) are tagged inconsistently:
tourism=information+information=office, barebuilding=office, guideposts, or (Camino)office=company. Navi therefore has no dedicated POI category for them — a name matcher would mostly hit guideposts, andinformation=officewould pull generic tourist offices. Pilgrim lodgings (tourism=hostel/guest_house) already match Lodging / Cabin. Named centers remain searchable via the place index when present. Upstream proposal under discussion: proposal: pilgrimage=stamp_office and network=pilgrim. Relatedtourism=checkpoint/checkpoint:type=stamptagging does not close the gap (no reliable route-relation link, tourism-key collision, no pilgrimage semantics). Revisit aPilgrimCentercategory if OSM settles on a consistent, machine-readable scheme. Seedocs/poi.mdanddocs/how-to-use.md. -
Not implemented yet: checking whether the code can be optimised for rendering.
(Future work only — shipped features are listed in the Features table above.)
UI language packs — chrome is English-only today. A future i18n /
ui_translation plugin will add selectable languages with fallback to
English when a translation or pack is missing. Spec:
docs/plugins/i18n-translation-spec.md.
Do not infer UI language from GPS or SIM country. Do not add a language
toggle until that plugin exists.
Display units (metric / US / UK) are shipped (Drive settings), including
peak-height labels on the basemap. Norwegian speed-limit pictograms stay
official km/h plates; mph plate artwork is still future (new-signs/).
Historical Norwegian/Norse distance units as a selectable display option
(e.g. rast, dagsvei, fjerdingvei), alongside the existing Metric / US / UK
profiles. Display-only historical/cultural mode, not a default or a serious
alternative to metric/imperial for navigation — a novelty or
regional-flavor toggle. Needs a design pass before implementation (which
distance and speed fields it applies to, how it interacts with
DisplayUnits, whether it is era-specific or one canonical conversion set).
Speed: Old Norse mil per hour (using the younger Norse mile / rast ≈ 9,100.8 m) could replace kilometre per hour in HUD / limit chrome for this profile. Smaller distances (approach box, remaining distance under a mil, etc.) should use the finer traditional units — stone's throw, arrow's flight, fjerdingvei — not only mil / rast / dagsvei.
Context for whoever picks this up:
- A rast was the distance traveled on foot before needing a rest ("rast," "pause"). It corresponded to a mil and was tied to the length of the ell, and varied by region and era. In the 900s, a rast was about 192 stone throws, divided into four fjerdingvei (quarter-ways), roughly 9,100.8 m. By the 12th century it was expressed as 16,000 ells (four quarters of 8,000 feet), the same order of magnitude.
- A dagsvei (day's journey) was the traditional distance walkable in a day, commonly reckoned at about 40 km.
- A stone's throw was 120 ells (also called a "great hundred") — about 56.88 m (200 feet).
- An arrow's flight was 4 stone's throws, ~480 ells — about 227.52 m (800 feet) around the year 900. Later in the Middle Ages, 10 arrow shots made up a fjerding of a mile — 2,275.2 m (8,000 feet), a quarter of the younger Norse mile.
- The younger Norse mile (rast / vei) was 9,100.8 m (32,000 feet) — the same order of magnitude as the 12th-century 16,000-ell figure above. Speed display in this mode: mil/h derived from that mile length (≈ 9.1008 km/h per mil/h), with sub-mil distances shown as stone's throw, arrow's flight, and so on.











