# HevyBridge Android APK

Phone-local bridge for the Fitbit Sense 2 companion. This removes the gym dependency on Tailscale/ADB.

## Real architecture

```text
Fitbit Sense 2 app
  ↕ peerSocket
Fitbit companion running inside the Fitbit Android app
  ↕ fetch('http://127.0.0.1:18090')
HevyBridge APK on the same Pixel
  ↕ AccessibilityService
Hevy Android app
```

## Why this exists

The old cloud backend used:

```text
Fitbit companion → Tailscale/Funnel → server → ADB over Tailscale → Pixel → Hevy
```

That is not acceptable for the gym because the phone would need Tailscale/ADB alive. The bridge APK runs locally on the Pixel and exposes a localhost API to the Fitbit companion.

Fitbit companion `fetch()` can access local IP HTTP endpoints on Android. Existing Fitbit projects use the same pattern with `http://127.0.0.1` to avoid HTTPS certs.

## API

Base URL: `http://127.0.0.1:18090`

### GET `/health`

Returns bridge status.

### GET `/api/hevy/live`

Returns the current Hevy UI state parsed from Accessibility:

```json
{
  "phase": "exercise",
  "exercise": "Bench Press",
  "setCurrent": 2,
  "setTotal": 4,
  "weight": "80 kg",
  "reps": "8",
  "restSeconds": 0,
  "rawTexts": ["Log Workout", "Bench Press", "SET", "KG", "REPS"]
}
```

### POST `/api/hevy/action`

```json
{ "action": "set_done" }
{ "action": "skip_rest" }
{ "action": "timer_adjust", "delta": 15 }
{ "action": "timer_adjust", "delta": -15 }
```

The bridge clicks the corresponding Hevy UI element using AccessibilityNodeInfo / dispatchGesture.

### GET `/api/hevy/window`

Debug endpoint. Dumps the raw accessibility tree so selectors can be improved against real Hevy layouts.

## Build

```bash
cd phone-bridge
ANDROID_HOME=/opt/android-sdk gradle assembleDebug --no-daemon
```

APK output:

```text
phone-bridge/app/build/outputs/apk/debug/app-debug.apk
```

## Install

```bash
adb install -r phone-bridge/app/build/outputs/apk/debug/app-debug.apk
```

Then on the phone:

1. Open **Hevy Bridge**
2. Tap **Open Accessibility Settings**
3. Enable **Hevy Bridge** accessibility service
4. Open Hevy and start/continue workout
5. Open the Fitbit app on Sense 2

## Current limitations

This is an MVP bridge. The state parser is heuristic and returns `rawTexts` to improve selectors quickly. The action side uses three tiers:

1. click node by text/content-desc (`Skip`, `+15`, `-15`)
2. click likely set-done checkbox/content-desc
3. fallback gesture tap on likely clickable node

If a button doesn't work, inspect:

```bash
adb forward tcp:18090 tcp:18090  # not needed on-phone, useful from dev machine if bridge listens beyond loopback later
curl http://127.0.0.1:18090/api/hevy/window
```

For device-side testing from ADB, use:

```bash
adb shell am start -n dev.nachlakes.hevybridge/.MainActivity
adb shell settings get secure enabled_accessibility_services
```
