Route your phone's audio to the earpiece speaker — automatically when you bring the phone to your ear, or manually on demand. Useful for listening to voice messages, podcasts, or any media privately without headphones.
- Auto mode — bring the phone to your ear while audio is playing and it switches to the earpiece; pull away and it switches back. The screen turns off at your ear, just like during a phone call.
- Manual mode — force earpiece routing on/off from the notification or the app.
- Quick Settings tile — start/stop the service from the notification shade.
- Headphone-aware — automatically disengages when wired, Bluetooth, or USB audio is connected, and refuses to engage while headphones are attached.
- Survives reboots — restarts itself after boot if it was running.
Android offers no public API to route other apps' audio to the earpiece on
demand. Apps that own their player (e.g. WhatsApp voice messages) can recreate
their AudioTrack on STREAM_VOICE_CALL, but third-party audio can't be
touched that way without root. The only mechanism available to a normal app is
MODE_IN_COMMUNICATION + AudioManager.setCommunicationDevice() — which is
what this app uses, with several device-specific workarounds described below.
The core is a foreground service (AudioRouterService):
- Routing: sets
AudioManager.mode = MODE_IN_COMMUNICATIONand callssetCommunicationDevice(earpiece)(API 31+; falls back toisSpeakerphoneOn = falseon older versions). In communication mode the system routes media streams to the earpiece. - Silent comm-path track: several devices (observed on Vivo) reset
MODE_IN_COMMUNICATIONback toMODE_NORMALevery few seconds when no app is actually using the communication path, causing an audible glitch on every reset. The service plays a silentAudioTrackwithUSAGE_VOICE_COMMUNICATIONwhile routing is active, which keeps the mode legitimately held. No audio focus is requested — requesting focus would make media apps pause. - Proximity: a
SensorEventListeneron the proximity sensor with a 150 ms debounce. Some devices do not deliver proximity events at all unless aPROXIMITY_SCREEN_OFF_WAKE_LOCKis held, so the wakelock is held for the entire time auto mode is active (it also turns the screen off at your ear, which is the desired behavior anyway). - Playback detection:
AudioPlaybackCallbackwatchesAudioPlaybackConfigurations.isActive()was removed from the public SDK in API 34, so it is reached via reflection with a presence-based fallback. Configs withUSAGE_VOICE_COMMUNICATIONare ignored so the app doesn't trigger on its own silent track. - Device changes:
AudioDeviceCallback(not the deprecatedACTION_HEADSET_PLUGbroadcast) detects wired/Bluetooth/USB output changes. - Call safety: the routing watchdog backs off during
MODE_IN_CALLandMODE_RINGTONEso it never fights telephony. - State is persisted across process restarts and reboots
(
SharedPreferences+BOOT_COMPLETEDreceiver).
| Permission | Why |
|---|---|
FOREGROUND_SERVICE / FOREGROUND_SERVICE_SPECIAL_USE |
The routing service must run persistently |
POST_NOTIFICATIONS |
Status + controls notification (Android 13+) |
MODIFY_AUDIO_SETTINGS |
Required to change audio mode and routing |
WAKE_LOCK |
Proximity screen-off wakelock (ear detection + sensor delivery) |
RECEIVE_BOOT_COMPLETED |
Restart the service after reboot |
No internet permission. No analytics, no ads, no data collection.
- Android 8.0 (API 26) or newer; best experience on Android 12+ (API 31),
where
setCommunicationDeviceis available. - A device with a proximity sensor (for auto mode) and an earpiece speaker.
Standard Gradle build, no extra setup:
./gradlew assembleDebug # debug APK in app/build/outputs/apk/debug/
./gradlew assembleRelease # release (minified) — add your signing configRequirements: JDK 17, Android SDK 34. Gradle wrapper included (Gradle 8.5, AGP 8.2.2, Kotlin 1.9.22).
adb install -r app/build/outputs/apk/debug/app-debug.apkThen launch the app, tap Start Service, and (Android 13+) grant the notification permission. Add the Earpiece Quick Settings tile for quick access.
- The earpiece is a small speaker — expect phone-call quality, not media quality. That is the point (privacy), not a bug.
- Auto mode reacts in ~150–300 ms on the app side, but the proximity sensor hardware itself adds ~1–2 s of latency on most devices. This is a hardware floor; the stock Phone app has the same delay.
- Some OEMs (e.g. Vivo) aggressively manage audio modes; the silent comm-path track exists specifically to keep routing stable on those devices.
- On API 34+, true play/pause state of other apps is hidden by the platform, so playback detection falls back to a presence heuristic in rare cases.
app/src/main/java/com/earpiece/router/
├── AudioRouterService.kt # Core: routing, proximity, wakelock, silent track
├── EarpieceTileService.kt # Quick Settings tile
├── MainActivity.kt # Start/stop UI + notification permission
└── BootReceiver.kt # Restart after reboot
Issues and PRs are welcome — see CONTRIBUTING.md.
Device-specific routing behavior reports (with adb logcat -s EarpieceRouter)
are especially valuable.