Work

Headless Android SDKEarly

A hidden second display on your phone. Launch an app onto it, tap and type, take screenshots, while the real screen stays yours.

C Sarath Babu's experiment Headless Android SDK. Two phones on one drive shaft, one held in a hand and one ghosted, typed on by a mechanical arm

I built a Kotlin SDK that creates a hidden second display on an Android phone.

You launch an app onto it, tap, type, take a screenshot. The physical screen you are holding stays untouched and usable the whole time.

val runtime = HeadlessAutomation.start(context)
if (!runtime.isAuthorized()) runtime.requestAuthorization()
 
val session = runtime.createSession()
session.launch("com.android.chrome")
session.tap(540f, 270f)
session.type("RRR movie")
session.pressEnter()
val screenshot = session.screenshot()
session.close()

The problem with automating a phone

Every existing way of driving an Android app takes the phone away from you.

Accessibility services drive the real screen, so you watch the taps happen and cannot use the device meanwhile. Instrumentation tests need a build and a harness. ADB needs a cable and a computer.

All of them assume the phone is doing this instead of being used, not as well as being used.

A display nobody looks at

Android can already create virtual displays. It is how screen casting works.

So the SDK makes one, keeps it off the physical screen, and launches the target app onto it. Input goes to that display. Frames come off it. The user's display never knows.

input and captureYour codelaunch, tap, typeSDKsessionVirtual displaythe app runs herePhysical displaystill the user's
Two displays, one of them nobody can see

What the SDK hides from you

Doing this by hand means Binder, ImageReader, InputManager and Shizuku, four things with almost nothing in common except that getting any of them slightly wrong fails in a way that is hard to read.

So the public surface is three types. HeadlessAutomation to start, HeadlessRuntime for authorization, HeadlessSession for the work. Nothing below that is something you should have to hold.

Where it actually is

The runtime works and is verified on a device. Display creation, launching an app onto it, touch and text and key input, frame capture. All of it end to end through the public API, on a Xiaomi running Android 14.

The perception layer is an interface and nothing else. No OCR, no vision, no Accessibility implementation. Right now you get raw screenshots and work out what is in them yourself.

Privilege comes through Shizuku, but behind an interface, so another backend can go in later without the rest moving.

tl;dr

Run an app on a display nobody can see, drive it, screenshot it, and keep using your phone while it happens.

Source on GitHub