174 lines
5.3 KiB
Markdown
174 lines
5.3 KiB
Markdown
# ClawdNode Android
|
|
|
|
AI-powered phone assistant that connects to Clawdbot Gateway. Enables Claude to answer calls, screen notifications, and act on your behalf.
|
|
|
|
## Features (v0.1)
|
|
|
|
### Notification Interception
|
|
- Captures all notifications from all apps
|
|
- Forwards to Gateway: app name, title, text, available actions
|
|
- Can trigger actions (Reply, Mark read, etc.) via Gateway commands
|
|
- Can dismiss notifications remotely
|
|
|
|
### Call Screening & Voice
|
|
- Intercepts incoming calls before ring
|
|
- Sends caller info to Gateway for Claude to decide
|
|
- **Answer calls programmatically**
|
|
- **Speak into calls via TTS** (Text-to-Speech)
|
|
- **Listen to caller via STT** (Speech-to-Text)
|
|
- Full voice conversation loop with Claude as the brain
|
|
|
|
### Security
|
|
- **Tailscale-only** — no public internet exposure
|
|
- Encrypted credential storage (EncryptedSharedPreferences)
|
|
- Local audit log of all actions
|
|
- All permissions clearly explained
|
|
|
|
## Protocol
|
|
|
|
### Events (Phone → Gateway)
|
|
|
|
```json
|
|
// Notification received
|
|
{"type": "notification", "id": "com.whatsapp:123:1706400000", "app": "WhatsApp", "package": "com.whatsapp", "title": "Mom", "text": "Call me when you can", "actions": ["Reply", "Mark read"]}
|
|
|
|
// Incoming call
|
|
{"type": "call_incoming", "call_id": "tel:+1234567890", "number": "+1234567890", "contact": "Mom"}
|
|
|
|
// Caller speech (transcribed)
|
|
{"type": "call_audio", "call_id": "tel:+1234567890", "transcript": "Hi, I'm calling about the appointment", "is_final": true}
|
|
|
|
// Call ended
|
|
{"type": "call_ended", "call_id": "tel:+1234567890", "duration": 45, "outcome": "completed"}
|
|
```
|
|
|
|
### Commands (Gateway → Phone)
|
|
|
|
```json
|
|
// Take screenshot
|
|
{"cmd": "screenshot"}
|
|
|
|
// Trigger notification action
|
|
{"cmd": "notification_action", "id": "com.whatsapp:123:...", "action": "Reply", "text": "I'll call you back in 30 min"}
|
|
|
|
// Dismiss notification
|
|
{"cmd": "notification_dismiss", "id": "com.whatsapp:123:..."}
|
|
|
|
// Answer incoming call with greeting
|
|
{"cmd": "call_answer", "call_id": "tel:+1234567890", "greeting": "Hello, this is Johan's phone. Who's calling?"}
|
|
|
|
// Reject call
|
|
{"cmd": "call_reject", "call_id": "tel:+1234567890"}
|
|
|
|
// Speak into active call
|
|
{"cmd": "call_speak", "call_id": "tel:+1234567890", "text": "Thank you for calling. I'll let Johan know about the appointment."}
|
|
|
|
// Hang up
|
|
{"cmd": "call_hangup", "call_id": "tel:+1234567890"}
|
|
```
|
|
|
|
## Setup
|
|
|
|
### 1. Build the APK
|
|
|
|
```bash
|
|
# Clone and build
|
|
cd clawdnode-android
|
|
./gradlew assembleDebug
|
|
|
|
# APK will be at:
|
|
# app/build/outputs/apk/debug/app-debug.apk
|
|
```
|
|
|
|
Or open in Android Studio and build.
|
|
|
|
### 2. Install on Phone
|
|
|
|
```bash
|
|
adb install app/build/outputs/apk/debug/app-debug.apk
|
|
```
|
|
|
|
Or transfer APK and install manually (enable "Unknown sources").
|
|
|
|
### 3. Configure Gateway
|
|
|
|
1. Open ClawdNode app
|
|
2. Enter Gateway URL: `http://<tailscale-ip>:18789`
|
|
3. Enter Gateway Token: (from your Clawdbot config)
|
|
4. Save Configuration
|
|
|
|
### 4. Grant Permissions
|
|
|
|
The app needs several permissions:
|
|
|
|
1. **Notification Access** — System settings, enable ClawdNode
|
|
2. **Call Screening Role** — Become the call screener
|
|
3. **Runtime Permissions**:
|
|
- Phone state
|
|
- Call log
|
|
- Answer calls
|
|
- Record audio (for STT)
|
|
- Contacts (for caller ID)
|
|
|
|
### 5. Test Connection
|
|
|
|
- Status should show "✓ Connected to Gateway"
|
|
- Send a test notification to your phone
|
|
- Check Gateway logs for the notification event
|
|
|
|
## Voice Flow Example
|
|
|
|
```
|
|
1. Call comes in from unknown number
|
|
2. ClawdNode sends: {"type": "call_incoming", "number": "+1234567890", "contact": null}
|
|
3. Claude decides to answer and screen
|
|
4. Gateway sends: {"cmd": "call_answer", "greeting": "Hi, this is Johan's assistant. Who's calling?"}
|
|
5. ClawdNode answers, plays TTS greeting
|
|
6. Caller speaks: "Hi, I'm calling from Dr. Smith's office about tomorrow's appointment"
|
|
7. ClawdNode sends: {"type": "call_audio", "transcript": "Hi, I'm calling from Dr. Smith's office..."}
|
|
8. Claude processes, decides to confirm details
|
|
9. Gateway sends: {"cmd": "call_speak", "text": "Thank you for calling. Can you confirm the time?"}
|
|
10. ... conversation continues ...
|
|
11. Gateway sends: {"cmd": "call_hangup"}
|
|
12. Claude sends summary to Johan via Signal
|
|
```
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
app/src/main/java/com/inou/clawdnode/
|
|
├── ClawdNodeApp.kt # Application class, initialization
|
|
├── service/
|
|
│ ├── NodeService.kt # Foreground service, command routing
|
|
│ └── GatewayClient.kt # WebSocket connection
|
|
├── notifications/
|
|
│ └── NotificationListener.kt # Notification capture & actions
|
|
├── calls/
|
|
│ ├── CallScreener.kt # Call screening service
|
|
│ └── VoiceCallService.kt # InCallService for voice interaction
|
|
├── security/
|
|
│ ├── TokenStore.kt # Encrypted credential storage
|
|
│ └── AuditLog.kt # Local audit trail
|
|
├── protocol/
|
|
│ └── Messages.kt # Event/Command data classes
|
|
└── ui/
|
|
└── MainActivity.kt # Setup UI
|
|
```
|
|
|
|
## Requirements
|
|
|
|
- Android 10+ (API 29) — required for CallScreeningService
|
|
- Tailscale installed and connected
|
|
- Clawdbot Gateway running and accessible
|
|
|
|
## Security Notes
|
|
|
|
- Gateway connection is via Tailscale mesh network only
|
|
- Credentials are stored using Android's EncryptedSharedPreferences
|
|
- All actions are logged locally with timestamps
|
|
- No data leaves your network (except to Gateway)
|
|
|
|
## License
|
|
|
|
MIT — Use freely, contribute back.
|