All checks were successful
Create Release / build (push) Successful in 6s
Server-side: - Add push credential auto-creation for FCM incoming call notifications - Add queue alert FCM notifications (data-only for background delivery) - Add queue alert cancellation on call accept/disconnect - Fix caller ID to show caller's number instead of Twilio number - Fix FCM token storage when refresh_token is null - Add pre_call_status tracking to revert agent status 30s after call ends - Add SSE fallback polling for mobile app connectivity Mobile app: - Add Android telecom permissions and phone account registration - Add VoiceFirebaseMessagingService for incoming call push handling - Add insistent queue alert notifications with custom sound - Fix caller number display on active call screen - Add caller ID selection dropdown on dashboard - Add phone numbers endpoint and provider support - Add unit tests for CallInfo, QueueState, and CallProvider - Remove local.properties from tracking, add .gitignore Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
177 lines
5.8 KiB
Markdown
177 lines
5.8 KiB
Markdown
# TWP Softphone — Mobile App
|
|
|
|
Flutter-based VoIP softphone client for the Twilio WordPress Plugin. Uses the Twilio Voice SDK (WebRTC) to make and receive calls via the Android Telecom framework.
|
|
|
|
## Requirements
|
|
|
|
- Flutter 3.29+ (tested with 3.41.4)
|
|
- Android device/tablet (API 26+)
|
|
- TWP WordPress plugin installed and configured on server
|
|
- Twilio account with Voice capability
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
cd mobile
|
|
flutter pub get
|
|
flutter build apk --debug
|
|
adb install build/app/outputs/flutter-apk/app-debug.apk
|
|
```
|
|
|
|
## Server Setup
|
|
|
|
The app connects to your WordPress site running the TWP plugin. The server must have:
|
|
|
|
1. **TWP Plugin** installed and activated
|
|
2. **Twilio credentials** configured (Account SID, Auth Token)
|
|
3. **At least one Twilio phone number** purchased
|
|
4. **A WordPress user** with agent permissions
|
|
|
|
### SSE (Server-Sent Events) — Apache + PHP-FPM
|
|
|
|
The app uses SSE for real-time updates (queue changes, agent status). On Apache with PHP-FPM, `mod_proxy_fcgi` buffers output by default, which breaks SSE streaming.
|
|
|
|
**Fix** — Create a config file on the web server:
|
|
|
|
```bash
|
|
echo 'ProxyPassMatch "^/wp-json/twilio-mobile/v1/stream/events$" "unix:/run/php-fpm/www.sock|fcgi://localhost/path/to/wordpress/index.php" flushpackets=on' > /etc/httpd/conf.d/twp-sse.conf
|
|
httpd -t && systemctl restart httpd
|
|
```
|
|
|
|
> **Adjust the paths:**
|
|
> - Socket path must match your PHP-FPM config (check `grep fcgi /etc/httpd/conf.d/php.conf`)
|
|
> - Document root must match your WordPress installation path
|
|
|
|
**Diagnosis** — If the green connection dot stays red:
|
|
|
|
```bash
|
|
# Check current PHP-FPM proxy config
|
|
grep -r "fcgi\|php-fpm" /etc/httpd/conf.d/
|
|
|
|
# Check if flushpackets is configured
|
|
grep -r "flushpackets" /etc/httpd/conf.d/
|
|
|
|
# Test SSE endpoint (should stream data continuously, not hang)
|
|
curl -N -H "Authorization: Bearer YOUR_TOKEN" \
|
|
https://your-site.com/wp-json/twilio-mobile/v1/stream/events
|
|
```
|
|
|
|
**Notes:**
|
|
- `flushpackets=on` is a `ProxyPassMatch` directive — it **cannot** go in `.htaccess`
|
|
- If using **nginx** instead of Apache, the `X-Accel-Buffering: no` header (already in the PHP code) handles this automatically
|
|
- The app automatically falls back to 5-second polling if SSE fails, so the app still works without this config — just with higher latency
|
|
|
|
## App Setup (Android)
|
|
|
|
### First Launch
|
|
|
|
1. Open the app and enter your server URL (e.g., `https://phone.cloud-hosting.io`)
|
|
2. Log in with your WordPress credentials
|
|
3. Grant permissions when prompted:
|
|
- Microphone (required for calls)
|
|
- Phone/Call (required for Android Telecom integration)
|
|
|
|
### Phone Account
|
|
|
|
Android requires a registered and **enabled** phone account for VoIP apps. The app registers automatically, but enabling must be done manually:
|
|
|
|
1. If prompted, tap **"Open Settings"** to go to Android's Phone Account settings
|
|
2. Find **"TWP Softphone"** in the list and toggle it **ON**
|
|
3. Return to the app
|
|
|
|
If you skipped this step, tap the orange warning card on the dashboard.
|
|
|
|
> **Path:** Settings → Apps → Default apps → Phone → Calling accounts → TWP Softphone
|
|
|
|
### Making Calls
|
|
|
|
1. Tap the phone FAB (bottom right) to open the dialer
|
|
2. Enter the phone number
|
|
3. Caller ID is auto-selected from your Twilio numbers
|
|
4. Tap **Call** — the Android system call screen (InCallUI) handles the active call
|
|
|
|
### Receiving Calls
|
|
|
|
Incoming calls appear via Android's native call UI. Answer/reject using the standard Android interface.
|
|
|
|
> **Note:** FCM push notifications are required for receiving calls when the app is in the background. This requires `google-services.json` in `android/app/`.
|
|
|
|
### Queue Management
|
|
|
|
- View assigned queues on the dashboard
|
|
- Tap a queue with waiting calls to see callers
|
|
- Tap **Accept** to take a call from the queue
|
|
|
|
### Agent Status
|
|
|
|
Toggle between **Available**, **Busy**, and **Offline** using the status bar at the top of the dashboard.
|
|
|
|
## Development
|
|
|
|
### Project Structure
|
|
|
|
```
|
|
lib/
|
|
├── config/ # App configuration
|
|
├── models/ # Data models (CallInfo, QueueState, AgentStatus, User)
|
|
├── providers/ # State management (AuthProvider, CallProvider, AgentProvider)
|
|
├── screens/ # UI screens (Login, Dashboard, Settings, ActiveCall)
|
|
├── services/ # API/SDK services (VoiceService, SseService, ApiClient, AuthService)
|
|
├── widgets/ # Reusable widgets (Dialpad, QueueCard, AgentStatusToggle)
|
|
└── main.dart # App entry point
|
|
```
|
|
|
|
### Running Tests
|
|
|
|
```bash
|
|
flutter test
|
|
```
|
|
|
|
34 tests covering CallInfo, QueueState, and CallProvider.
|
|
|
|
### Building
|
|
|
|
```bash
|
|
# Debug APK
|
|
flutter build apk --debug
|
|
|
|
# Release APK (requires signing config)
|
|
flutter build apk --release
|
|
```
|
|
|
|
### ADB Deployment (WiFi)
|
|
|
|
```bash
|
|
# Connect to device
|
|
adb connect DEVICE_IP:PORT
|
|
|
|
# Install
|
|
adb install -r build/app/outputs/flutter-apk/app-debug.apk
|
|
|
|
# Launch
|
|
adb shell am start -n io.cloudhosting.twp.twp_softphone/.MainActivity
|
|
|
|
# View logs
|
|
adb logcat -s flutter
|
|
```
|
|
|
|
### Key Dependencies
|
|
|
|
| Package | Purpose |
|
|
|---------|---------|
|
|
| `twilio_voice` | Twilio Voice SDK (WebRTC calling) |
|
|
| `provider` | State management |
|
|
| `dio` | HTTP client (REST API, SSE) |
|
|
| `firebase_messaging` | FCM push for incoming calls |
|
|
| `flutter_secure_storage` | Secure token storage |
|
|
|
|
## Troubleshooting
|
|
|
|
| Problem | Solution |
|
|
|---------|----------|
|
|
| Green dot stays red | SSE buffering — see [Server Setup](#sse-server-sent-events--apache--php-fpm) |
|
|
| "No registered phone account" | Enable phone account in Android Settings (see [Phone Account](#phone-account)) |
|
|
| Calls fail with "Invalid callerId" | Server webhook needs phone number validation — check `handle_browser_voice` in `class-twp-webhooks.php` |
|
|
| App hangs on login | Check server is reachable: `curl https://your-site.com/wp-json/twilio-mobile/v1/auth/login` |
|
|
| No incoming calls | Ensure FCM is configured (`google-services.json`) and phone account is enabled |
|