Files
android-fs5/specs/003-autonomous-agent-control/plan.md
T
Jane Alesi ad8c738160 feat(spec): add 003-autonomous-agent-control specification
Spec for full AI agent mobile control capability:
- Voice call control (dial/answer/hangup/status/list)
- App lifecycle management (install --url, update, permissions, grant, info)
- Device backup & restore (create/list/restore/app/verify, AES-256 encrypt)
- SMS send/delete + wait-reply via KDE Connect
- Audio control (volume/mute/route)
- Contacts management (list/add/export VCF)

56 tasks across 7 phases. TDD: fixtures → RED tests → GREEN impl.
Target: ≥130 BATS tests on completion.

Closes: specs/003-autonomous-agent-control/{spec,plan,tasks}.md
2026-03-02 18:38:35 +01:00

203 lines
7.1 KiB
Markdown

# 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 <pkg>` | Full permission dump |
| App grant | `adb shell pm grant <pkg> <perm>` | 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:<number>` 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 "<msg>" --destination <number> -d <device-id>`
**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 |