Touch App is the Android runtime of Touch Matrix. It turns a real Android phone into an addressable execution node that can be operated through Android Accessibility APIs, an on-device LLM agent loop, and the companion cloud control server.
The current codebase is centered around the mobile runtime itself:
- An Accessibility-based execution layer for gestures, key events, node lookup, screenshots, and text input
- A LangChain4j-based agent loop that can run on-device tasks when an LLM is configured
- A cloud control channel built on
WebSocketfor pairing, live screen streaming, remote commands, and dashboard feedback - A local LAN configuration server on port
9527for browser-based configuration and debug tooling
- Controls a real Android device through
ClawAccessibilityService - Streams the live screen to the dashboard through
CloudHubandScreenStreamer - Executes remote commands such as tap, swipe, key press, text input, and AI task dispatch
- Keeps the runtime alive through a foreground service, battery optimization handling, and a scheduled keep-alive job
- Shows execution status through a floating overlay
- Applies privacy-aware screen tree reduction for finance-sensitive apps
The actual code currently boots with ToolRegistry.DeviceType.MOBILE and registers only the Cloud channel in ChannelManager.
That means the real, implemented control paths today are:
- Cloud control: Pair the phone with the Go server in
../server, then control it from the web dashboard - Local browser config: Open the built-in LAN config page from a PC browser on the same network
- On-device AI task execution: Available after LLM configuration, and currently triggered through the cloud command path
Dashboard / Browser
|
| /api/pairing-code, /api/device/validate-token, /ws/dash
v
Go server in ../server
|
| /ws/device
v
CloudHub -----------------------> ScreenStreamer
| |
| remote commands | JPEG frames
v v
RemoteExecutor Live preview in dashboard
|
| cmd_tap / cmd_swipe / cmd_input / cmd_key / cmd_task
v
ClawAccessibilityService
|
+--> gesture injection
+--> node tree inspection
+--> screenshots
+--> system key operations
|
v
TaskOrchestrator -> AgentService -> ToolRegistry -> mobile tools
ClawApplication: app bootstrap, tool registration, foreground service startup, async initializationAppViewModel: central coordinator for permissions, agent init, floating UI, config server, and task orchestrationTaskOrchestrator: single-task lock, agent lifecycle, task callbacks, cancellation, and result delivery
service/ClawAccessibilityService.java: core Accessibility service for gestures, node lookup, clicks, screenshots, and key operationsdevice/RemoteExecutor.kt: translates dashboard commands into device actions and starts AI tasksdevice/DeviceInfo.kt: collects device metadata used for auth and status reportingfloating/FloatingCircleManager.kt: floating indicator for runtime state
device/CloudHub.kt:WebSocketclient for auth, reconnect, heartbeat, RTT ping, status sync, and command handlingdevice/ScreenStreamer.kt: live screen streaming with adaptive width tiersdevice/RemoteExecutor.kt: remote command bridge between the dashboard and Accessibility execution
server/ConfigServer.kt: embedded HTTP server on port9527server/ConfigServerManager.kt: lifecycle manager for the local config serverapp/src/main/assets/web/index.html: browser configuration pageapp/src/main/assets/web/debug.html: debug-only tool execution page
ui/splash/SplashActivity.kt: launcher entryui/home/HomeActivity.kt: permission dashboard, LLM entry, cloud bind entry, runtime statusui/guide/GuideActivity.kt: first-run permission guideui/settings/LlmConfigActivity.kt: LLM configurationui/settings/SettingsActivity.kt: LAN config, cloud bind, and model entry
- Tap, long press, swipe, and center-point fallback click
- Find nodes by text or view ID
- Inspect the full accessibility tree
- Take screenshots and send files back through the active task channel
- Trigger system keys such as home, back, recent apps, and lock screen
- LLM config stored locally through
KVUtils - OpenAI-compatible and Anthropic-compatible clients through LangChain4j
- Agent execution loop with tool calls, round callbacks, token statistics, and cancellation
- Task execution gated by a single-task lock in
TaskOrchestrator
- Device auth through
/ws/device - Pairing and token validation through HTTP calls to the companion server
- Dashboard-to-device commands:
cmd_tapcmd_swipecmd_inputcmd_taskcmd_keycmd_cancel_task
- Immediate and heartbeat-based device status reporting
- Adaptive screen streaming based on RTT and frame-send congestion
GET /orGET /index.html: configuration pageGET/POST /api/llm: read and update LLM configGET/POST /api/channels: placeholder channel config endpointGET /debug.html: debug page, debug builds onlyGET /api/debug/tools: list runtime tools, debug builds onlyPOST /api/debug/execute: execute a tool from browser, debug builds only
The app initializes in mobile mode, so the current runtime tool set is:
get_screen_infofind_node_infoinput_textsystem_keyopen_appget_installed_appstake_screenshotwaitrepeat_actionsclipboardsend_filefinish
taplong_pressswipescroll_to_find
The Accessibility layer contains explicit privacy handling for sensitive apps.
- A blacklist includes apps such as WeChat, Alipay, Bank of China, ICBC, QQ, Google Play, Amap, WeCom, Pinduoduo, and JD
- In those contexts, the screen tree can switch to a reduced mode to avoid exposing full text content
- First launch shows a privacy notice explaining that UI element metadata may be sent to the AI service, while password, verification code, and banking text content are not sent as normal text payloads
- Android
9.0+(minSdk = 28) - Target / compile SDK
36 - Java
17 - Android Gradle Plugin
9.1.0 - Gradle wrapper included in the repository
cd touch_app
export ANDROID_HOME=~/Library/Android/sdk
./gradlew assembleDebugcd touch_app
./gradlew assembleReleaseGenerated APK files are renamed during the build to:
Touch App_v<versionName>_<timestamp>.apk
The version is currently maintained in app/build.gradle.kts, and buildConfigField("VERSION_INFO", ...) also embeds the current Git branch and commit SHA.
The repository includes build_and_install.sh, which:
- Reads and bumps the version in
VERSION - Updates
versionCodeandversionNameinapp/build.gradle.kts - Builds the debug APK
- Installs it to the connected device through
adb
Usage:
cd touch_app
./build_and_install.sh
./build_and_install.sh <device_serial>After installing the APK, the real setup flow in the app is:
- Open the app and complete the permission guide
- Enable Accessibility Service
- Enable persistent notification
- Enable overlay permission
- Exempt the app from battery optimization
- Grant storage access
- Configure an LLM if you want to run
cmd_taskor other AI-driven flows - Bind to the cloud server if you want dashboard-based remote control
The LLM settings page stores:
API KeyBase URLModel Name- Provider selection metadata
If Base URL is empty, the runtime falls back to:
https://api.openai.com/v1
The current agent config in AppViewModel uses:
temperature = 0.1maxIterations = 100
Touch App is designed to work with the Go companion server in ../server.
The in-app cloud bind flow is:
- Enter the server address such as
ws://<host>:8443orwss://<host>:8443 - Enter a device ID
- Request a pairing code from
POST /api/pairing-code - Complete pairing in the dashboard
- Paste the issued token back into the app
- Validate the token
- Let
CloudHubconnect toGET /ws/device
Once connected, the app will:
- Authenticate with device metadata
- Stream the screen
- Report battery, screen state, and permission state
- Accept remote dashboard commands
Touch App also exposes a local configuration server built on NanoHTTPD.
- Port:
9527 - Entry page:
http://<phone-ip>:9527/ - LLM config API:
/api/llm - Debug UI:
/debug.htmlin debug builds only
This is mainly intended for quick browser-side configuration and tool debugging on the same network.
touch_app/
├── app/
│ ├── src/main/java/com/nextflow/nftouch/
│ │ ├── agent/ # Agent loop and LLM clients
│ │ ├── base/ # Base app / activity classes
│ │ ├── channel/ # Current channel abstraction, currently Cloud
│ │ ├── device/ # Cloud hub, remote executor, screen streaming, device info
│ │ ├── floating/ # Floating runtime indicator
│ │ ├── server/ # Embedded LAN config server
│ │ ├── service/ # Accessibility, foreground, boot, keep-alive services
│ │ ├── tool/ # Tool abstraction and implementations
│ │ ├── ui/ # Splash, home, guide, settings, web UI
│ │ ├── utils/ # KV, logging, helpers
│ │ ├── widget/ # Reusable custom views
│ │ ├── AppViewModel.kt
│ │ ├── ClawApplication.kt
│ │ └── TaskOrchestrator.kt
│ ├── src/main/assets/web/
│ │ ├── index.html # LAN config page
│ │ └── debug.html # Debug tool page
│ └── src/main/AndroidManifest.xml
├── gradle/
├── build_and_install.sh
├── VERSION
└── README.md
dev.langchain4j:langchain4j-coredev.langchain4j:langchain4j-open-aidev.langchain4j:langchain4j-anthropiccom.squareup.okhttp3:okhttpcom.squareup.retrofit2:retrofitcom.tencent:mmkv-staticorg.nanohttpd:nanohttpdcom.github.princekin-f:EasyFloatcom.github.bumptech.glide:glidecom.google.zxing:core
- Accessibility permission is mandatory for any real device control
cmd_taskrequires a valid LLM configuration- Text input has multiple fallbacks, but the shell-based fallback only supports ASCII text
- The current repository contains channel-related UI wording, but the implemented runtime message channel is currently
Cloud - Sensitive apps may expose a reduced accessibility tree instead of full text content
Touch App depends on the Go backend in ../server for:
- pairing code generation
- token validation
- device unbind
- dashboard sessions
- cloud device sessions
- browser-based remote control
If you are deploying the full system, read ../server/README.md together with this file.
See LICENSE.