#20077: fix(android): expose node invoke commands consistently + add sms.read
app: android
size: M
Cluster:
Cross-Platform Fixes
## Summary
- Make Android node advertise invoke commands consistently (camera/screen/sms/app-update)
- Add new `sms.read` command to Android node runtime
- Add `READ_SMS` permission to Android manifest
- Wire `sms.read` through protocol constants, dispatcher, and SMS handler
- Implement SMS inbox read in `SmsManager` with optional `{ limit, sinceMs }` params
## Why
On-device testing showed camera capability was present but `camera.snap`/`camera.clip` were missing from registered node commands, causing `node command not allowed` from gateway tools.
## Validation
- Built Android debug app successfully
- Verified node now registers:
- `camera.snap`, `camera.clip`, `screen.record`, `sms.send`, `sms.read`, `app.update`
- Verified `camera_snap` works end-to-end from gateway tool
- Verified `sms.read` returns recent messages payload
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR makes the Android node consistently advertise all supported invoke commands (`camera.snap`, `camera.clip`, `screen.record`, `sms.send`, `sms.read`, `app.update`) regardless of current permission/setting state, and adds a new `sms.read` command for reading SMS inbox messages.
- **Command registration change**: `ConnectionManager.buildInvokeCommands()` now always advertises camera and SMS commands instead of gating them behind `cameraEnabled()` and `smsAvailable()` checks. Runtime enforcement is handled by `InvokeDispatcher` and the individual handlers. Capabilities (`buildCapabilities()`) remain gated.
- **New `sms.read` command**: Wired through `OpenClawSmsCommand.Read` protocol constant, `InvokeDispatcher`, `SmsHandler.handleSmsRead`, and `SmsManager.read()` with `READ_SMS` permission and content resolver query against `Telephony.Sms.CONTENT_URI`.
- **Permission**: `READ_SMS` added to manifest and handled via `ensureSmsReadPermission()` with runtime permission request flow.
- **Tests**: Existing `buildPayloadJson` test renamed to `buildSendPayloadJson` to match the renamed method. No new tests for the read functionality.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with low risk — changes follow established patterns and runtime permission checks are in place.
- The implementation is clean and follows existing patterns for command dispatch, permission handling, and error reporting. The main deduction is for the LIMIT-in-sortOrder fragility (already discussed) and the absence of unit tests for the new read functionality. All other changes are mechanical and well-structured.
- `SmsManager.kt` — the LIMIT-in-sortOrder approach (already flagged) and the new `read()` method lacks unit test coverage.
<sub>Last reviewed commit: ed119af</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#8311: feat(gateway): add SYSTEM_COMMANDS to Android node allowlist
by ipv1337 · 2026-02-03
73.6%
#22484: Android: add flashlight on/off control support
by ztechenbo · 2026-02-21
68.7%
#22329: Android : Add Notification Intelligence -- cross-app AI triage
by VikrantSingh01 · 2026-02-21
64.6%
#15951: fix: Android production build permits cleartext traffic globally
by coygeek · 2026-02-14
64.3%
#11205: Android: fix gateway connection and canvas URL for Tailscale serve
by emonty · 2026-02-07
63.6%
#23636: iOS: normalize watch quick actions and fix test signing
by mbelinky · 2026-02-22
63.4%
#23326: fix(daemon): graceful degradation on unsupported platforms
by indistinctchatter604 · 2026-02-22
62.9%
#22403: docs: add SMS Gateway to community plugins
by zacharypodbela · 2026-02-21
62.3%
#23288: feat(whatsapp): group command gating via commands.allowFrom + sende...
by rodrigoscoelho · 2026-02-22
62.2%
#11132: fix(telegram): guard command menu overflow and doctor warnings
by kiminbean · 2026-02-07
61.8%