# Fitbit Companion App — Android Constraints

## What the Companion Can Do

### Communication with the watch
- Messaging API: `peerSocket.onmessage` / `peerSocket.send()` — reliable enough with `fitbit-asap`
- File Transfer API: `outbox.enqueue()` — more reliable than messaging
- Companion wakes when watch sends a message (if sleeping)

### Network access
- `fetch()` to HTTPS endpoints — **only HTTPS**, no plain HTTP
- Can reach public internet servers (Pipo backend on VPS with Tailscale)
- Can reach local network servers by IP (fitbit-homeassistant project confirms this)
- Self-signed certificates are problematic — needs real CA-signed cert
- WebSocket API works (confirmed by fitbit-heart-rate-mqtt project)

### Storage
- Local settings via `me.storage` / settings API
- Can persist small amounts of config data

### Permissions
- `access_internet` — required in `package.json` for network
- `run_background` — helps keep companion alive
- Companion can be killed by Android OS at any time (battery optimization)

### Lifecycle
- Started when watch app launches and connects
- Can request wake interval to poll periodically
- Can be killed by Android — watch app should handle reconnection
- Companion is "headless" — no direct UI on phone

## What the Companion CANNOT Do

### Cannot communicate with other Android apps
- **No IPC to Hevy app**: The companion runs inside the Fitbit app process. It cannot send intents, bind to services, or access other apps' data.
- **No ContentProvider access**: Cannot query other apps' databases.
- **No Android SDK**: Companion JS runs in Fitbit's JS engine, not Android runtime.
- **No Accessibility or Notification access**: No Android permissions model; companion only has Fitbit SDK APIs.

**This is the fundamental constraint that necessitates Path C.** The Fitbit companion can only talk to:
1. The watch (via messaging)
2. The internet (via HTTPS fetch)
3. Its own storage (via settings API)

It cannot directly observe or control the Hevy app on the same phone.

### Cannot run native Android code
- Companion is pure JavaScript executed by Fitbit's JS runtime
- No way to load .so libraries or call Android Java/Kotlin APIs
- No WebView or DOM access

### Cannot use localhost services reliably
- Companion `fetch()` to `https://localhost` or `https://127.0.0.1` is not guaranteed
- Local network IP addresses may work but are inconsistent across platforms (iOS vs Android)
- Some users report `fetch()` to localhost failing on device but working in simulator
- Best practice: always use a public or Tailscale-reachable HTTPS endpoint

## Architecture Implication

The Fitbit companion is **not the bridge itself** — it's a client of the bridge. The actual bridge must be:

**Option A**: A separate Android APK running on the Pixel 9a alongside the Fitbit app
- Has NotificationListenerService + AccessibilityService
- Runs a local HTTP server that the companion can `fetch()` to
- **Problem**: Companion may not reach localhost consistently

**Option B**: A separate Android APK that talks to Pipo backend, which the companion also talks to
- Bridge writes Hevy state to Pipo backend via HTTPS
- Fitbit companion reads state from Pipo backend via HTTPS
- **This is the recommended architecture** — both clients talk to a shared server

**Option C**: Bridge as a background service on the VPS that communicates with Pixel via ADB
- Not practical for live use — ADB over USB/WiFi is high-latency and unreliable for continuous streaming

## Recommended Flow (Option B)

```
Watch ──msg──► Fitbit Companion ──HTTPS POST──► Pipo Backend
                                                    ▲
                                                    │ HTTPS POST (state)
                                                    │
                         Hevy App ◄──bridge APK─────┘
                            │            │
                            │    (NotificationListener
                            │     + AccessibilityService)
                            │
                    Posts notification
                    when workout state changes
```

The bridge APK:
1. Registers as `NotificationListenerService` to read Hevy notifications
2. Registers as `AccessibilityService` (targeting `com.hevy`) as fallback
3. Polls/computes workout state from notification content
4. POSTs state to `https://pipo-backend/api/live-workout/state`
5. Polls `https://pipo-backend/api/live-workout/command` for commands
6. Executes commands via notification actions or accessibility taps

The Fitbit companion:
1. GETs `https://pipo-backend/api/live-workout/state` (or receives via WebSocket)
2. Relays to watch via `peerSocket.send()`
3. Sends watch-set events to `https://pipo-backend/api/live-workout/event`

## Developer Bridge Note

The Fitbit Developer Bridge runs on the development machine (Linux), not on the phone. It connects to the Fitbit app on the phone to install apps and capture screenshots. It is **not** a runtime bridge — it's a development tool. It cannot be used for live Hevy ↔ Fitbit communication.
