Turn-by-turn navigation on the back of your Nothing Phone (4a) Pro.
GlyphMaps mirrors Google Maps' next turn — the maneuver arrow and the distance to it — onto the rear Glyph Matrix while you navigate. Glance at the back of your phone instead of the screen.
- 🧭 Shows the next maneuver — turn left/right, sharp turns, keep left/right, forks, roundabouts, U-turns and "arrived" — as a clean dot-matrix arrow.
- 📏 Scrolls the distance to the turn ("300m", "1.5k") beneath the arrow.
- 🔌 Reads directions straight from Google Maps' Live Updates notification — no Google API key, no account, no extra setup.
- 🤝 Only claims the Matrix while you're actually navigating. Start a route and it takes over; end the route and it hands the Matrix straight back to whatever Glyph toy you normally run.
- 🔒 100% on-device. No network code, no analytics, no account — it reads one notification and draws dots. Nothing leaves your phone.
Left: the app's main screen (live preview · display mode · brightness). Right: the next-turn readout.
The money shot — the lit Matrix on the back of the phone during a route — needs an external camera (see Recording a demo).
- Nothing Phone (4a) Pro — the model with the circular Glyph Matrix (137 LEDs).
- Nothing OS / Android 14+ with Google Maps Live Updates (default on recent Maps versions).
- Google Maps running an active route — GlyphMaps mirrors Maps; it is not a standalone navigation app and does no routing of its own.
- Install — download GlyphMaps‑1.0.0.apk
onto your phone and tap to install (allow Install from unknown sources if
prompted), or
adb install GlyphMaps-1.0.0.apk. You can also build from source (below). - Grant Notification Access — on first launch the app links you to the
system setting. This is required: it's how GlyphMaps reads Maps' live
directions. (It's filtered to the Google Maps package + the
navigationcategory — everything else is ignored.) - Navigate — open Google Maps, start any route, flip your phone over. The Matrix lights up with your next turn. The app doesn't even need to stay open.
Note
If you also run a custom Glyph Toy, grant Notification Access to only one Glyph-Matrix app at a time — two listeners will fight over the Matrix during navigation.
- LED brightness — independent head (the bright arrowhead) and tail (the dim trail) sliders, persisted across sessions.
- Display mode — Static Glow (steady) or Sweeping Flow (a comet animates along the arrow toward the turn). The sweep is generated from the static pattern, so the two always match.
- Speed-aware preview — a far-off turn shows a "continue, then turn" arrow and flips to the direct icon as you approach, matching Google's own preview window scaled to your current speed.
- The app reads only Google Maps' navigation notification (filtered by
package + the
navigationcategory). It ignores everything else — even other Maps notifications. - Nothing leaves your phone. There is no networking code, no analytics, no account, no ads.
- The only thing stored is your display preferences (brightness, mode) in private app storage.
- Notification access is a powerful permission — the source is right here, so you
can verify exactly what it does in
MapsNotificationListener.kt.
Full policy: PRIVACY_POLICY.md.
The 4a Pro restricts Glyph Toys to always-on-display only, with a ~1-minute
update cadence — far too slow for live navigation. GlyphMaps sidesteps that:
it's a normal app that drives the Matrix directly with setAppMatrixFrame, only
while a route is active.
Google Maps (Live Updates notification, ~every 2-5s)
│
▼
MapsNotificationListener reads title + distance, maps Google's maneuver
│ vocabulary → our 12-maneuver set, derives speed
▼
GlyphRenderService foreground service, alive ONLY during nav;
│ releases the Matrix on route end
▼
MatrixComposer → GlyphRenderer → setAppMatrixFrame()
│
▼
Glyph Matrix (137 LEDs, circular 13×13)
Project layout
app/src/main/kotlin/com/glyphnavtoy/
MainActivity.kt Compose UI (clean user build · full dev build)
glyph/
Maneuver.kt 12-maneuver set + Google-vocabulary mapping
ArrowBitmaps.kt dot-matrix arrow patterns (head/tail chars)
ArrowSweep.kt procedural sweep animation, derived from static
MatrixFrame.kt 13×13 grid + circular LED mask
MatrixComposer.kt NavState -> frame (arrow + distance marquee)
GlyphRenderer.kt owns GlyphMatrixManager, pushes frames
GlyphSettings.kt head/tail brightness + display mode, persisted
DigitFont.kt 3×5 pixel font for the distance marquee
nav/ NavState, NavStateRepo, Speedometer, PresetRoute
service/
GlyphRenderService.kt foreground render loop (nav-only lifecycle)
MapsNotificationListener.kt reads Maps, parses, forwards
capture/CaptureWriter.kt dev-only on-device capture log
Two flavors install side by side:
| Flavor | App ID | What's in it |
|---|---|---|
| user | com.glyphnavtoy |
The clean product — live preview, display mode, brightness. |
| dev | com.glyphnavtoy.dev |
Everything + manual maneuver override, route simulator, capture log. |
# Dev build → install + relaunch on a connected device
push.cmd
# Signed USER release App Bundle (.aab) for Google Play
build-release.cmdThe dev APK lands in app/build/outputs/apk/dev/debug/; the release bundle in
app/build/outputs/bundle/userRelease/app-user-release.aab. On a standard
machine, plain ./gradlew :app:assembleUserDebug works too.
Tip
Release signing reads from a gitignored keystore.properties at the repo root
(it falls back to the debug key when absent, so clones still build). See
PUBLISHING.md to set up your own upload key.
PUBLISHING.md is the full Google Play checklist — signing,
Data Safety answers, the Notification Access + special-use foreground-service
declarations, store-listing copy, and the asset list.
- Procedural sweep animation that always matches the static arrows
- Head/tail LED brightness
- Clean user build vs. full dev build (manual override + capture log)
- Release-ready: signed + minified AAB, privacy policy, Play declarations
- Play Store listing (closed testing → production) — see PUBLISHING.md
- Auto-dim (ambient light / time of day)
- ETA / speed display modes
Kotlin · Jetpack Compose · Coroutines · Android NotificationListenerService +
foreground service · the Nothing Glyph Matrix SDK.
Built for the Nothing community on top of the Glyph Matrix Developer Kit.
GNU Affero General Public License v3.0 (AGPL-3.0).
Use, modify, and redistribute freely — but any modified or derived version you ship to anyone (including as a hosted service) must publish its full source code under the same license, with credit preserved. You cannot fold this code into a closed-source product, paid or otherwise.
If AGPL doesn't work for you — e.g. you want to integrate GlyphMaps into a closed-source product, ship it as a built-in feature of a device or OS, or embed it without the share-alike obligation — a separate commercial license is available. Inquiries from Nothing Technology Ltd. about integrating GlyphMaps as a built-in Glyph Matrix feature are explicitly welcome.
Contact: capad.xyz@gmail.com
The AGPL above covers the source code. It does not grant any rights to the project's brand assets, which are © 2026 capad.io, all rights reserved:
- the names "GlyphMaps" and "GlyphNav";
- the app launcher icon and the dot-matrix chevron mark;
- promotional artwork (
promo/) and product screenshots (docs/screenshots/).
If you fork the project, rename it and replace the icon and artwork so your
build isn't presented as an official or affiliated release — the AGPL still
applies to the code you fork. This carve-out does not cover third-party
material (e.g. the Glyph Matrix layout references under reference/, or bundled
fonts), which keep their own licenses. Full statement: NOTICE.
By submitting a pull request, you agree that your contribution may be relicensed by the project owner for the purpose of granting a separate proprietary/commercial license alongside the AGPL.
GlyphMaps is an independent app and is not affiliated with, endorsed by, or sponsored by Google or Nothing Technology. "Google Maps" and "Nothing" are trademarks of their respective owners.
