All AOSP
Basalt app icon

Basalt

A clock in brass and phosphor, with no Material anywhere in it.

Basalt is the AOSP DeskClock rebuilt in Kotlin, wearing a face made of milled brass and a dot-matrix readout. There is no androidx.compose.material in the project — no MaterialTheme, no Scaffold, no Material icons, no ripples. Every button, switch, stepper and letterform is drawn by hand, so it reads as one machine rather than a theme applied to someone else's.

Version
0.2.0
Platform
Android 10 and up
Licence
MIT
Network
Offline

Basalt never opens a connection. There is no permission for one in the manifest. The weather and location that a later version may offer alongside its widgets will be opt-in, off by default, and named here when they exist.

MIT. AOSP DeskClock is a behavioural reference only — no AOSP source is copied in.

Why MIT?

Basalt is an independent reimplementation, not a fork. Nothing in it is lifted from AOSP DeskClock; what is borrowed is the behaviour — the semantics of alarm state machines, timer overrun, lap arithmetic and world clock time zones — and behaviour is not copyrightable. So there is nothing to keep open by obligation, and MIT is the honest label.

In 0.2.0 · August 2026

Seven palettes, and a test suite under the alarm engine.

  • Seven themes, chosen in Settings → THEME: Basalt, BREM, Copper, Latte, Mocha, Quartz and Solar. The picker draws each one as a swatch in its own colours, because "BREM" is not a colour anyone can picture from the word.
  • Quartz is a genuine light theme rather than an inversion — the bezel's specular edge moves from the top of a panel to the bottom, and the system bar icons flip with it, or a raised panel would read as a recessed one.
  • Every palette is contrast-checked by test, per role: 4.0:1 for text, 3.0:1 for accents. Writing that test found four tokens under the bar, one of them in the default palette, where it had shipped in 0.1.0.
  • 137 JVM unit tests, over next-occurrence walking, the repeat mask, daylight saving in both directions, timer and stopwatch arithmetic across process gaps, the glyph fold, and the alarm lifecycle decisions. No device or emulator needed for any of them.
  • Room's destructive fallback is gone. The schema is exported and committed, and a change with no matching migration throws on open instead of quietly deleting your alarms.

Screens

What it looks like

The first seven are the six sections and the sound picker. The last seven are the same clock screen in each of the seven palettes — which is the only honest way to show a theme, since a list of seven words tells you nothing.

  • The readout

  • Alarms, and the next one

  • Timers that run past zero

  • Laps, split and total

  • The night, as an arc

  • Seven swatches, seven palettes

  • Your files, or the phone's

  • Basalt

  • BREM

  • Copper, the default

  • Latte

  • Mocha

  • Quartz, a real light theme

  • Solar

Features

What it does

The metal is the chassis, the dots are the display

One rule shapes everything. Glyphs are always dots; chrome is always metal; they never swap roles. The unlit cells behind a message are drawn rather than skipped, because the dark grid is as much the look as the message is.

Pick the part of the song that wakes you

Any system tone, or any MP3 or WAV through the document picker — and then choose the section that plays. Set a start and an end, audition the loop, and that exact stretch is what rings. The part worth waking up to is almost never the first thirty seconds.

Seven palettes, and the roles hold

The token names are roles, not hues. Quartz's ink is a warm white and its silverBright is nearly black, because ink means "the ground" and silverBright means "the strongest mark you can make on it". Nothing in the drawing code may assume a token is dark.

The icon tells the time

The launcher icon is not a picture of a clock — it is one. The hour and minute hands are separate layers, and Launcher3 and its descendants rotate them as the clock advances. The second hand deliberately does not move: waking the launcher every second for a detail nobody reads at icon size is not a feature.

Nothing counts down in a process

A running timer is a deadline plus a notification, and the system owns both. AlarmManager wakes the app at the deadline; the notification's own chronometer draws the count with no process alive. A service ticking once a second to update a number the system can draw itself is pure battery cost — and it gets killed anyway.

Time is injected, and decisions are separated from effects

Nothing below the UI calls the system clock at a call site. AlarmTransitions is pure, so "what happens to a repeating alarm once this morning is over" can be tested without a device — which is exactly the part that is tangled enough to get wrong.

Limits

What it does not do yet

Said here rather than discovered later. Everything below is known, deliberate, and on the list.

  • The Doze story is implemented and verified on one device, not proven. It has not had enough overnight soak time across enough phones and OEM skins to call it done, and that box stays unticked until it has.
  • The world clock has its city dataset but not its screen yet.
  • Widgets — the actual reason the project exists — are 0.3.0. The plan is a modular renderer where a new style is a configuration rather than a rewrite, not one big clock and a shrug.
  • The hero and micro glyph sets, per-cell digit animation and custom clock faces are all still to come.