Alan Gaudet
AND-04 · Rev 0.10.0

crab-home

An Android home-screen launcher written in Rust, drawn with Slint into a NativeActivity.

Phone trial before 1.0.0

See it on the bench

Themed icons in the app list, coloured from the system's Material You palette.
App list with themed icons.
The hold popup on Calendar: Open, Add to Home screen, App info, Uninstall and the app's New event shortcut.
Hold popup with the app's own shortcut.

Description

crab-home is a home-screen launcher where the app is Rust from the manifest down, meant to run as the only launcher on my Pixel 6. The target was the Pixel Launcher's feature set: pages of icons with a hotseat and folders, drag and drop, an app list with search and suggestions, shortcuts, work and private profiles, and a Discover page. Features that need an Android View tree, such as app widgets, are out of scope by design.

Block diagram

  1. LauncherApps
  2. JNI bridge
  3. Loader thread
  4. Msg channel
  5. Slint UI

Decisions

The interface is Rust drawn straight into NativeActivity

I took 'written in Rust' literally and picked Slint on android-activity, which I already knew from MediaLint. The APK carries a manifest, resources and one native library with hasCode set to false, and R8 plus a Gradle flag stop AGP from adding dex. The cost is every feature that needs a View tree or a manifest-declared Java component, such as app widgets and notification dots.

Framework callbacks live in dex embedded in the library

Some framework APIs only call back into a Java class, such as the Discover overlay's service connection and the LauncherApps package callback. build.rs compiles those shims with javac and d8, embeds the dex in the .so and loads it with InMemoryDexClassLoader, the way Slint's backend already loads its keyboard helper. The APK still has no dex file, and a shim may only be a class the framework must call.

A drag never rewrites the model until the drop

Replacing a page's VecModel in Slint rebuilds every cell of that repeater, which destroys the cell holding the pointer capture and ends the drag. So a drag runs in the UI from the held cell: the source hides in place, a new page grows with an incremental push, and the saved layout changes only on the drop. The same rule later explained stalls in the folder overlay, the app list search and the news cards.

Errata

  • TalkBack reads nothing on the launcher's own screens, because Slint has no Android accessibility bridge.
  • The Android backend loads only Roboto, so an emoji or symbol in a news title draws as a box.
  • On Home settings, the switches and the grid-size chips run past the right edge of the screen.

Revision history

Version Changes
0.10.0 Story menu on screen 0, story pictures and source logos, a refresh ring that reacts to touch.
0.9.0 Screen 0: a built-in weather and news page left of the first home page.
0.8.0 Work and private profile tabs, rotation and tablet layouts, page restore, a panic hook with a crash row.
0.7.0 Icon popups with app shortcuts, pinned shortcuts, drag from the app list, and the notification shade swipe.