9cb6bfb71423192cc98e312977953c0e33e0f7ee
Add 'fs5 ui' subcommand with 4 operations: - ui dump [path] — dump UI hierarchy XML via uiautomator - ui elements [--json] — list all interactive elements with coords - ui find <text> — find element by text/content-desc, return x y - ui tap <text> — find element and tap it (ui find + tap) lib/input.sh: - adb_ui_dump() — uiautomator dump → pull XML → cleanup - adb_ui_find() — Python XML parse, case-insensitive search - adb_ui_elements() — full element inventory as JSON tests/test_ui.bats: 22 new tests (fixture-based, no live device needed) Total: 85/85 BATS tests passing (was 64/64) Research findings (AppAgent pattern, ADB+vision): - UIAutomator dump: best no-root UI inspection on Android 9 SDK 28 - AppAgent (6.6k★): screenshot + GPT-4V + ADB tap/swipe pipeline - RustDesk InputService already enabled → accessibility layer available - scrcpy 3.3.4 + tesseract OCR pipeline already working
android-fs5
CLI toolset for managing the exone GmbH FS5 Android 9 device via ADB.
Device
| Property | Value |
|---|---|
| Model | exone GmbH FS5 |
| Serial | RD51QE202392 |
| Android | 9 |
| Storage | ~52 GB |
Requirements
| Tool | Version | Install |
|---|---|---|
| adb | 1.0.41+ | sudo pacman -S android-tools |
| bash | 5.x | pre-installed |
| python3 | 3.x | pre-installed |
Setup
cp .env.example .env
# Edit .env if your device serial differs
chmod +x fs5
Usage
Usage: fs5 <command> [options]
Commands:
status Show device health and info
push <src> <dst> Push file/dir to device
pull <src> <dst> Pull file/dir from device
app list List installed apps
app install <apk> Install APK on device
app uninstall <pkg> Uninstall package (requires --force)
shell [cmd] Execute shell command on device
logs Stream or capture logcat output
Global Options:
--json Output as JSON
--force Allow destructive/overwrite operations
--help Show help
Examples
# Device health check
./fs5 status
./fs5 status --json | python3 -m json.tool
# File transfer
./fs5 push ./report.pdf /sdcard/Documents/report.pdf
./fs5 pull /sdcard/DCIM/photo.jpg ./photo.jpg
./fs5 push ./file.txt /sdcard/file.txt --force # overwrite
# App management
./fs5 app list
./fs5 app list --all --json
./fs5 app install ./myapp.apk
./fs5 app uninstall com.example.app --force
# Shell access
./fs5 shell "df -h"
./fs5 shell "pm list packages | grep google"
# Log capture
./fs5 logs --lines 50
./fs5 logs --filter ActivityManager
./fs5 logs --lines 100 --output /tmp/device.log
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | General error |
| 2 | Device not found |
Configuration (.env)
DEVICE_SERIAL=RD51QE202392 # ADB device serial
LOG_FILE=./fs5.log # Operation log path
DEFAULT_PUSH_PATH=/sdcard/ # Default push destination
ADB_TIMEOUT=10 # ADB timeout in seconds
Testing
# Install test dependencies (once)
sudo pacman -S bats bats-assert bats-support shellcheck
# Run all tests
bats tests/
# Run specific test file
bats tests/test_status.bats
# Lint
shellcheck fs5 lib/adb.sh lib/output.sh
Operation Log
All mutating operations (push, pull, install, uninstall) are logged to fs5.log:
2026-03-02T15:43:00+01:00 PUSH /home/ja/file.txt -> /sdcard/file.txt [OK]
2026-03-02T15:44:00+01:00 INSTALL /tmp/app.apk [OK]
Project Structure
android-fs5/
├── fs5 # Main CLI entrypoint
├── lib/
│ ├── adb.sh # ADB wrapper functions
│ └── output.sh # Output formatting (human + JSON)
├── tests/
│ ├── test_status.bats
│ ├── test_transfer.bats
│ ├── test_app.bats
│ ├── test_shell.bats
│ └── test_logs.bats
├── specs/ # Spec-Driven Development artifacts
├── .env.example # Config template
└── README.md
Languages
Shell
100%