Jane Alesi 9cb6bfb714 feat(ui): add UIAutomator-based ui subcommand for AI remote control
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
2026-03-02 18:13:44 +01:00
2026-03-02 15:55:09 +01:00
2026-03-02 15:55:09 +01:00
2026-03-02 15:55:09 +01:00

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
S
Description
Android FS5 management scripts
Readme
89 KiB
Languages
Shell 100%