Mutter for Android
Native Kotlin and Jetpack Compose client for Android 10 and newer. It connects directly to Mumble servers; a desktop computer, web bridge, or hosted backend is not required.
Build and install
Open this directory in Android Studio, or use JDK 21 and an Android SDK with platform 36.
The checked-in Gradle wrapper pins the build tool version. Set ANDROID_HOME to your SDK,
or set sdk.dir in the ignored local.properties file.
From the repository root:
node scripts/generate-themes.mjs --check
python3 scripts/deploy-android.py --build-only
python3 scripts/deploy-android.py --device YOUR_ADB_SERIAL
The helper detects the Homebrew JDK on this Mac. Elsewhere, set JAVA_HOME to JDK 21.
Enable USB debugging and authorize the Mac on the phone before installing. With exactly
one connected device, --device is optional. Installing an update preserves app data.
APKs appear in app/build/outputs/apk/debug/. Use app-arm64-v8a-debug.apk for current
Android phones, or the universal APK for other supported devices. These are development
builds signed with the local Android debug key; store distribution requires a release key.
Keep that key across releases so future builds can update existing installs.
Included
- TLS connections with explicit first-contact and changed-certificate prompts, saved pins, generated RSA identities, PKCS#12 import, per-server identity selection, and access tokens.
- Opus microphone capture and playback, encrypted OCB2 UDP, TCP fallback and UDP recovery, Mumble 1.2–1.5 wire formats, reconnect, push to talk, voice activity, open mic, and whisper.
- Android foreground call service, notification mute/deafen/disconnect actions, headset media controls, speaker/headset routing, and platform echo cancellation/noise suppression.
- Saved servers, favorites, recent ordering, occupancy/latency probes, the public directory, and local network discovery.
- Channel navigation/search, user lists, channel creation and editing, listeners, local mute/volume, permission-gated moderation, and registered-user management.
- Channel and direct chat, formatted text/links, inline attached images, photo attachments resized to server limits, unread counts, and direct-message notifications.
- WebRTC screen viewing compatible with the other Mutter clients. Screen broadcasting and share audio are not included.
- All 11 shared themes in light, dark, and system appearance, miniature theme previews,
shared typography and motion, and an adaptive/monochrome launcher icon from
docs/brand/icon.svg. - The shared phone layout: Channels, Chat, and Server tabs; an indented channel tree; circular avatars; the same call dock, grouped settings, and profiles as iPhone. Keyboard Send, large text, and short-window adaptations keep controls usable. See the phone layout guide.
Server passwords, access tokens, pins and certificate files are encrypted with a device-bound Android Keystore key. Backup and device transfer exclude this data. Signing keys and local SDK paths are ignored by Git. The app never transmits login credentials before certificate consent. Audio processing availability depends on the device; Bluetooth and physical microphone quality still need testing on real Android hardware.
Validation
Run unit tests, lint, and a debug build with JDK 21 and the Android SDK:
cd android
./gradlew testDebugUnitTest lintDebug assembleDebug
For emulator integration tests, start the shared protocol test servers from the repository root, then run the instrumentation suite in another terminal:
node android/test-server.mjs
In another terminal:
cd android
./gradlew connectedDebugAndroidTest
Run the integration suite on one emulator at a time; its fault-injection server is shared.
Tests use the emulator's 10.0.2.2 host address and ports 64740–64746. They cover actual TLS
consent, both voice formats, encrypted UDP and TCP voice, chat, channel changes, background
connections, automatic reconnect, notification controls, UDP interruption and recovery, changed
certificates, password rejection, channel edits, all theme variants, server-edit recreation,
encrypted storage tamper detection, PKCS#12 import, and platform Opus capture/encoding/decoding.
A physical test device can use
-Pandroid.testInstrumentationRunnerArguments.mumbleHost=YOUR_MAC_ADDRESS if the test
servers are explicitly configured to listen on that interface.
Unit tests use upstream OCB2 vectors and cover varints, framing, malformed input, replay and
reordered packets, and fragmented screen-share signals. Reports live under app/build/reports/.
The optional desktop-to-Android video test starts its own server and browser sharer:
CHROME=/path/to/chromium node android/test-share.mjs
It asserts that the Android viewer decodes real 640×360 video frames. Its instrumentation test is skipped in the ordinary suite unless this helper provides the sharing-server argument.
The shared palette generator writes Android's assets/themes.json and launch colors alongside
Swift and browser outputs. Fonts are read from design/fonts; Gradle
generates Android launcher resources from the master SVG on every relevant rebuild.