# Implementation Plan: Autonomous AI Agent Mobile Control **Feature**: 003-autonomous-agent-control **Created**: 2026-03-02 **Status**: Draft **Spec**: `specs/003-autonomous-agent-control/spec.md` --- ## Technical Context | Component | Technology | Rationale | |-----------|-----------|-----------| | Call control | `adb shell am start -a android.intent.action.CALL` + UIAutomator | ADB intent for dial; UIAutomator for answer/hangup (no root needed) | | Call state | `adb shell dumpsys telephony.registry` | Exposes call state without root | | App install (URL) | `curl` download → `adb install` | Reuses existing `adb install` path | | App update | `adb install -r` (replace) | Standard ADB replace-install | | App permissions | `adb shell dumpsys package ` | Full permission dump | | App grant | `adb shell pm grant ` | Runtime permission grant | | Backup | `adb backup -apk -shared -all` + `adb pull` for SMS/contacts | Android 9 supports `adb backup` | | SMS send | `kdeconnect-cli --send-sms` | Already paired, used in existing sms commands | | SMS wait-reply | Poll `kdeconnect-cli --list-notifications` with timeout | KDE Connect exposes incoming SMS as notifications | | Audio control | `adb shell media volume` + `adb shell service call audio` | Media volume API | | Contacts | `adb shell content query --uri content://contacts/phones` | Content provider query | --- ## Constitution Check - [x] **Library-First**: New commands added to `lib/call.sh`, `lib/backup.sh`, `lib/contacts.sh` - [x] **CLI Interface**: All new commands exposed via `fs5` entrypoint with `--help` - [x] **Test-First**: BATS tests written before implementation (RED → GREEN) - [x] **Simplicity**: Extends existing `fs5` CLI — no new entrypoints - [x] **Anti-Abstraction**: Direct ADB/KDE Connect calls, no wrapper frameworks - [x] **Integration-First**: Tests run against real device where possible; fixtures for offline --- ## Architecture ### New Library Modules ```text lib/ ├── adb.sh (existing — adb_check_device, adb_cmd, etc.) ├── output.sh (existing — out_human, out_json, out_error) ├── input.sh (existing — tap, swipe, key, type) ├── call.sh (NEW — call_dial, call_answer, call_hangup, call_status, call_list) ├── backup.sh (NEW — backup_create, backup_list, backup_restore, backup_app, backup_verify) └── contacts.sh (NEW — contacts_list, contacts_add, contacts_export) ``` ### fs5 Entrypoint Extensions New subcommands added to `fs5`: | Subcommand | Library | P1/P2/P3 | |------------|---------|----------| | `call dial/answer/hangup/status/list` | `lib/call.sh` | P1 | | `app install --url` | `lib/adb.sh` (extend) | P1 | | `app update [--all]` | `lib/adb.sh` (extend) | P1 | | `app permissions/grant/info` | `lib/adb.sh` (extend) | P1 | | `backup create/list/restore/app/verify` | `lib/backup.sh` | P1 | | `sms send [--wait-reply]` | `lib/adb.sh` (extend) | P2 | | `sms delete` | `lib/adb.sh` (extend) | P2 | | `audio volume/mute/route` | `lib/call.sh` (extend) | P2 | | `contacts list/add/export` | `lib/contacts.sh` | P3 | --- ## Data Model ### Call State JSON ```json { "state": "active", "number": "+49123456789", "direction": "outgoing", "duration_seconds": 42, "timestamp": "2026-03-02T18:30:00Z" } ``` ### Backup Manifest JSON ```json { "id": "backup-20260302-183000", "timestamp": "2026-03-02T18:30:00Z", "path": "/backups/backup-20260302-183000.tar.gz", "size_bytes": 524288000, "checksum": "sha256:abc123...", "contents": ["apks", "appdata", "sms", "contacts", "calllog"], "device_serial": "RD51QE202392", "android_version": "9" } ``` ### AppInfo JSON ```json { "package": "com.example.app", "version_name": "1.2.3", "version_code": 123, "install_date": "2026-01-15T10:00:00Z", "size_bytes": 10485760, "is_system": false, "permissions": { "granted": ["android.permission.CAMERA"], "denied": ["android.permission.READ_CONTACTS"] } } ``` --- ## Key Technical Decisions ### ADR-001: Call Control via ADB Intent + UIAutomator **Decision**: Use `adb shell am start -a android.intent.action.CALL tel:` for dialing. Use UIAutomator to tap answer/hangup buttons (no root required on Android 9). **Alternative rejected**: `adb shell service call phone` — requires root on Android 9. **Consequence**: `call answer` requires UIAutomator XML dump to find button coordinates. Add fixture for offline testing. ### ADR-002: Backup via `adb backup` + Content Providers **Decision**: Use `adb backup -apk -shared -all -f backup.ab` for app data. Use content provider queries for SMS (`content://sms`) and contacts (`content://contacts`). **Alternative rejected**: Third-party backup apps — requires installation and UI automation. **Consequence**: `adb backup` is deprecated in Android 12+ but fully functional on Android 9 (FS5 target). Document this limitation. ### ADR-003: SMS Send via KDE Connect **Decision**: Use `kdeconnect-cli --send-sms "" --destination -d ` **Alternative rejected**: `adb shell service call isms` — requires root. **Consequence**: KDE Connect must remain paired. Add pairing check to `sms send`. --- ## Test Strategy ### Offline Tests (no device required) - `backup verify` — checksum validation against fixture - `backup list` — parse fixture backup directory - `app info` — parse fixture `dumpsys package` output - `call status` — parse fixture `dumpsys telephony.registry` output - `contacts list` — parse fixture content provider output ### Online Tests (device required, marked `@requires_device`) - `call dial` — initiates call (verify via `call status`) - `backup create` — creates archive (verify size > 0) - `app install --url` — downloads and installs test APK - `sms send` — sends SMS (verify via `sms list`) ### Fixture Files ```text tests/fixtures/ ├── ui_dump.xml (existing) ├── dumpsys_telephony.txt (NEW — call state output) ├── dumpsys_package.txt (NEW — app info output) ├── content_sms.txt (NEW — SMS content provider output) └── content_contacts.txt (NEW — contacts content provider output) ``` --- ## Dependencies | Dependency | Status | Notes | |------------|--------|-------| | `adb` | ✅ Available | Used throughout existing commands | | `kdeconnect-cli` | ✅ Paired | Used in existing `sms` commands | | `curl` | ✅ Available | For APK URL download | | `sha256sum` | ✅ Available | For backup verification | | `openssl` | ✅ Available | For AES-256 backup encryption | | `bats` 1.13.0 | ✅ Available | Test runner | | UIAutomator | ✅ Available | Used in existing `ui` commands | --- ## Risks | Risk | Likelihood | Mitigation | |------|-----------|------------| | `adb backup` blocked by device policy | Low | Android 9 allows it; document if blocked | | Call answer via UIAutomator fails (button layout changes) | Medium | Use multiple selector strategies (text + content-desc) | | KDE Connect pairing lost | Low | Add `sms send` pairing check with re-pair instructions | | APK URL download fails (network) | Medium | Retry logic + clear error message |