Skip to content

the-mrinal/Dock

Repository files navigation

Dock

The always-on ambient screen your desk was missing.

Latest release License GitHub stars Platform

Website · Download APK · Contributing · How it works

The ambient dashboard: clock, today's calendar, now playing

Plug any Android TV device into a spare monitor and turn that dusty second screen into the calmest, most useful surface in your setup.

You already have a laptop for the thing you're focused on. You already have a phone for the world reaching in. You're missing the third screen — the one that just sits there and tells you the time, what meeting is next, and what's playing, without ever asking for a click.

This is that screen.


Contents


Features

A clock you actually want to look at

A huge, thin, beautifully kerned time display — with seconds that quietly fade away after 90 seconds of stillness so the resting face is just 7:00 PM. When idle, the whole dashboard melts into a true-black screensaver and the clock drifts a few pixels every minute so your panel never burns in.

Your calendar, at the exact moment you need it

The dashboard shows what's happening now and what's next. Walk past the screen and you instantly know: "keep coding" or "stand up, meeting in five." Tap into the Calendar page for the full timeline — personal + work feeds merged from your Google / Outlook iCal URLs, colour-tagged.

A remote control for Spotify, on your wall

The Music page is a full-blown Spotify Connect remote: album art, transport buttons, your live queue, your recently played tracks — driven by the actual MediaSession on your TV plus the Spotify Web API. Skip from across the room with the Android TV remote. Switch playback to your headphones, kitchen speaker, or living-room TV from one focus ring.

Phone mirroring — AirPlay, Cast, Miracast

Flip the switch in Settings and the dock starts advertising itself on your network as a wireless display target for AirPlay (iPhone, iPad, Mac), Google Cast (Chrome, Android), and Miracast (Windows, Android). The dashboard stays calm at rest; the moment a sender connects, it crossfades out and your phone or laptop takes the screen edge-to-edge. A small "Casting from {device} via AirPlay" pill rests in the corner, drifting a few pixels every minute (same burn-in protection as the clock). Each protocol is independently toggleable.

WireGuard VPN, baked in

The dock ships with a native WireGuard tunnel. Drop a .conf from your laptop over the LAN, tap Connect on the new Connect page, and every byte the TV sends goes through the tunnel — Netflix, Plex, the launcher, everything. A discreet country pill confirms the tunnel is up. The system "Always-on / kill-switch" hook is one tap away so non-VPN traffic gets blocked at the kernel.

A background that breathes

Every screen carries a softly blurred wash of the current track's album art — Gaussian-quality (pyramid downsample + 3-pass box blur, plus GPU RenderEffect on API 31+). When you stop touching the remote, the wash fades to black so the clock owns the room.

Quietly good behaviour

  • Stay awake while visible — no screen-off mid-meeting
  • Sleep timer so the dock gracefully exits when you go to bed
  • Burn-in protection for OLED panels — clock drifts in ambient mode
  • Android TV native — uses the remote, D-pad, and media keys exactly as you'd expect
  • No cloud, no telemetry, no account required — Spotify is optional and PKCE-based

Screenshots

Home dashboard
Home — clock, today's events, now-playing, pager dots
Connect: AirPlay + VPN
Connect — AirPlay receiver and WireGuard VPN, side by side
Calendar day view
Calendar — the day on one screen, with personal/work tags
Music page with transport and queue
Music — transport, up next, recently played
Settings — VPN section
Settings · VPN — config import over LAN, kill-switch shortcut, indicator overlay

Quick start

Option 1 — install the pre-built APK (5 minutes)

  1. Grab the latest APK for your platform from the Releases page (app-firetv-release-*.apk or app-googletv-release-*.apk).
  2. Enable ADB on your TV (Fire OS: Settings → My Fire TV → Developer Options. Google TV: Settings → System → About → tap Android TV OS build 7×, then Developer options → USB debugging).
  3. From your laptop:
    adb connect <tv-ip>:5555
    adb install -r app-firetv-release-vX.Y.Z.apk      # or app-googletv-release-vX.Y.Z.apk
  4. Launch Dock from the Apps row.

APK builds are produced manually per release (see Releasing for the why) — not every release has APKs attached. If yours doesn't, build from source below or run gh workflow run package.yml -f tag=<latest> on your fork.

Option 2 — build from source

source scripts/dev-env.sh
cp local.properties.example local.properties   # set sdk.dir, spotify.clientId, unsplash.accessKey
./gradlew assembleFiretvDebug
adb install -r app/build/outputs/apk/firetv/debug/app-firetv-debug.apk

The firetv build flavor is the default and targets minSdk 25 (older Amazon Fire OS hardware still ships there). For newer Google TV / Android TV / Chromecast devices, use ./gradlew assembleGoogletvDebug — same code, minSdk 29, separate applicationId so both can coexist on one device.

spotify.clientId comes from the Spotify Developer Dashboard. Redirect URI: com.ambient.tvclock://spotify-callback. Add your Spotify account under User Management (Development Mode).

unsplash.accessKey comes from Unsplash Developers — create an app, copy the Access Key (not Secret Key). Drives the configurable background image feature. Free Demo tier is 50 req/hr, which the dock stays well under because one search returns a page of 30 URLs that get cycled locally.


Configuration

Calendar

Google Calendar → your calendar → Integrate calendarSecret address in iCal format. On the TV: Settings → Personal calendar URL — paste the link. Or, from your Mac:

./scripts/set-calendar-urls.sh 192.168.1.4:5555 "https://calendar.google.com/calendar/ical/.../basic.ics"

Work Outlook ICS goes under Work calendar URL.

Spotify

Grant the notification listener so the dock can read MediaSession metadata from the Spotify TV app:

LISTENER=com.ambient.tvclock.firetv/com.ambient.tvclock.MediaNotificationListener
adb shell settings put secure enabled_notification_listeners $LISTENER
adb shell cmd notification allow_listener $LISTENER

Or just run ./scripts/install-firetv.sh — it does all three steps in one shot.

For Premium users who want queue + remote transport:

  1. Add spotify.clientId to local.properties and rebuild
  2. Settings → Connect Spotify — sign in on the TV (WebView)
  3. Play Spotify on the same account; this TV must be the active Connect device for queue data
  4. Focus a transport button or track row and press OK
  5. Focus Playing on … · OK to switch to move playback to another device

Phone mirroring

Settings → Phone mirroring (beta) → Enable mirroring receiver. Set a device name if you want a custom one in the AirPlay picker. Each protocol (AirPlay / Cast / Miracast) is independently toggleable. The dock starts a small foreground service that advertises on the LAN; flip it off and everything goes back to sleep.

WireGuard VPN

The dock spins up a short-lived LAN endpoint that accepts a .conf upload from your laptop's browser:

Settings → VPN → Receive config from laptop (LAN)

To activate, head to the Connect page and press OK on the VPN card. The kill-switch lives one tap away under Settings → VPN → Always-on / kill-switch (system).

Inputs

Input Where What it does
D-pad Left / Right Anywhere Switch between Connect, Home, Calendar, Music
D-pad Up / Down Calendar Scroll the day
D-pad / OK Music, Connect Focus + activate transport, tracks, devices, AirPlay, VPN
Media keys Music Play/pause, skip, previous (works with the Android TV remote media buttons)
Menu Anywhere Settings

After your configured idle window (default 90s) the dashboard fades into ambient mode — clock plus a single horizontal music × calendar strip below it. Any keypress brings it back.


How it works

flowchart TD
    MA[MainActivity<br/>pager + drift + ambient watchdog] --> DP[DashboardPagerAdapter]
    DP --> C[Connect<br/>StatusScreenBinder]
    DP --> H[Home<br/>HomeScreenBinder]
    DP --> CA[Calendar<br/>CalendarScreenBinder]
    DP --> M[Music<br/>MusicScreenBinder]
    DP --> BG[BlurredBackgroundBinder<br/>AlbumArtBlur]

    H --> CP[CalendarPoller<br/>IcalParser]
    CA --> CP

    H --> NP[NowPlayingPoller<br/>MediaSession]
    M --> NP
    M --> SC[SpotifyApiClient<br/>OAuth PKCE]

    C --> RS[ReceiverService<br/>AirPlay / Cast / Miracast]
    C --> WG[WireGuardTunnel<br/>VPN service]

    RS --> SO[StreamingOverlay<br/>SurfaceView crossfade]
Loading
  • MainActivity.kt — dashboard pager, drift, ambient watchdog, input routing, streaming-overlay crossfade
  • Home/Calendar/Music/StatusScreenBinder.kt — per-page view binders
  • BlurredBackgroundBinder.kt + AlbumArtBlur.kt — full-bleed artwork wash (pyramid downsample + 3-pass box blur ≈ Gaussian, GPU RenderEffect pass on API 31+)
  • CalendarPoller.kt / IcalParser.kt — iCal feed polling, every 15 min
  • SpotifyApiClient.kt / SpotifyAuthActivity.kt — OAuth PKCE + queue / recently-played
  • NowPlayingPoller.kt — MediaSession bridge
  • receiver/ReceiverService.kt — foreground service hosting AirPlay / Google Cast / Miracast, plus the RTSP + MediaCodec pipeline for the AirPlay video stream
  • receiver/ui/StreamingOverlay.kt — full-bleed SurfaceView the dashboard crossfades into when a sender connects
  • vpn/ — WireGuard tunnel manager + the LAN config-import endpoint

Built on plain Android views (no Compose, no React Native) so it stays buttery on older Android TV hardware.


Releasing

This project uses semantic-release driven by Conventional Commits.

  • Every PR title is a Conventional Commit (feat:, fix:, perf:, …)
  • Releases are cut locally with the /release Claude Code skill or npx semantic-release --no-ci — no CI cost
  • Building and attaching APKs is a separate workflow_dispatch step: gh workflow run package.yml -f tag=vX.Y.Z

See CONTRIBUTING.md for the full release flow and commit conventions.


Contributing

Pull requests welcome. Read CONTRIBUTING.md before opening one — there's a small but firm set of conventions around commit messages, scope, and "what won't be merged" (cloud deps, telemetry, interruptive features). For bugs and feature ideas, use the issue templates.


License

Apache License 2.0. The patent grant matters for the WireGuard, AirPlay, and codec code paths — please don't strip the LICENSE if you fork.


Acknowledgements


If you've got a spare monitor and an Android TV stick in a drawer somewhere, give this five minutes.
It's the kind of small infrastructure you don't realise was missing from your desk until it's there.

About

An ambient TV dashboard for Android TV — clock, calendar, Spotify, AirPlay, WireGuard VPN. No cloud, no telemetry.

Resources

License

Contributing

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors