# Permissions & Security

## Android Permissions Required

### NotificationListenerService

```xml
<!-- AndroidManifest.xml -->
<service
    android:name=".HevyNotificationListener"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE"
    android:exported="true">
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>
```

- User must manually enable in: **Settings → Apps → Special access → Notification access**
- No runtime permission dialog — user must navigate to settings
- Can guide user with intent: `startActivity(Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS))`
- On Android 13+, user gets a confirmation dialog on first enable
- Policy: Notification listeners read ALL notifications. Google's policy says this should be for "notification management." Our use case (reading workout state from a specific app) is reasonable.

### AccessibilityService

```xml
<!-- AndroidManifest.xml -->
<service
    android:name=".HevyAccessibilityService"
    android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
    android:exported="true">
    <intent-filter>
        <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>
    <meta-data
        android:name="android.accessibilityservice"
        android:resource="@xml/accessibility_service_config" />
</service>
```

```xml
<!-- res/xml/accessibility_service_config.xml -->
<accessibility-service
    android:description="@string/accessibility_description"
    android:accessibilityEventTypes="typeWindowStateChanged|typeWindowContentChanged"
    android:accessibilityFlags="flagDefault|flagRetrieveInteractiveWindows"
    android:canRetrieveWindowContent="true"
    android:canPerformGestures="true"
    android:packageNames="com.hevy" />
```

- User must manually enable in: **Settings → Accessibility → [App Name]**
- `packageNames="com.hevy"` — limits service to only Hevy app (good for privacy)
- Google Play policy NOTE: Apps using AccessibilityService for non-accessibility purposes MAY be rejected. See "Google Play Policy Risk" below.

### Internet

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

Standard, no user prompt.

### Foreground Service (for persistent bridge)

```xml
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- Android 13+ -->
```

- Needed if bridge needs to stay alive during workout
- Must show a persistent notification ("Bridge is running")
- On Android 14+, must declare foreground service type

### Wake Lock (optional, for keeping CPU awake)

```xml
<uses-permission android:name="android.permission.WAKE_LOCK" />
```

### Battery Optimization Exemption

- Prompt user to exempt from battery optimization
- `Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)`

## Google Play Policy Risk Assessment

### NotificationListenerService: LOW RISK
- Standard use case: "notification management"
- Many legitimate apps use this (AutoNotification, Notification Listener, etc.)
- Our use is narrow (single app: `com.hevy`) and purposeful (fitness tracking)
- **Recommendation**: Safe to include in any APK, even if published on Play

### AccessibilityService: MEDIUM-HIGH RISK (if published on Play)
- Google's official policy: "AccessibilityService should only be used to help users with disabilities"
- Google has been cracking down on non-accessibility use since 2017
- Apps have been removed for using Accessibility for automation
- **BUT**: This only matters if we publish on Google Play Store
- **Recommendation**: If we publish on Play, do NOT include AccessibilityService. If we sideload (ADB install), there is no policy risk.

### Sideloading: NO PLAY POLICY RISK
- We're targeting Chicho's personal Pixel 9a
- Install via ADB: `adb install bridge.apk`
- No Google Play review process
- No policy constraints on AccessibilityService use
- **This is the recommended distribution method**

## Data Flow Security

### Sensitive data in transit

```text
Hevy Notification → Bridge APK (on-device, no network)
Bridge APK → Pipo Backend: HTTPS (TLS 1.3, Tailscale or public HTTPS)
Pipo Backend → Fitbit Companion: HTTPS (TLS 1.3)
Fitbit Companion → Sense 2: Fitbit messaging (encrypted by Fitbit)
```

### What data crosses the network

| Data | Sensitivity | Notes |
|------|-------------|-------|
| Exercise name | Low | Public data |
| Set number | Low | |
| Weight (kg) | Low | Workout data only |
| Reps | Low | |
| RPE/RIR | Low | |
| Rest timer seconds | Low | |
| Hevy API key | **HIGH** | Only used server-side (Pipo backend) |
| Hevy login credentials | **HIGH** | Only if using internal API approach |
| Fitbit auth token | **HIGH** | Only in Fitbit companion (Fitbit-managed) |

### Credential storage

- **Hevy API key**: Stored on Pipo backend (VPS, environment variable or Bitwarden)
- **Hevy internal auth token**: If needed, stored in Bridge APK's `EncryptedSharedPreferences` (Android Keystore-backed)
- **Pipo backend auth**: API key or token in bridge APK config

## Bridge APK Authentication to Backend

```
Option A: Pre-shared API key
  - Hardcoded or configured API key in bridge APK
  - Simple, sufficient for single-user deployment

Option B: Device-bound token
  - Generate token on first launch
  - Tie to device ID
  - More secure but overkill for single user
```

**Recommendation**: Option A (pre-shared API key) is sufficient. This is a personal tool for one user.

## Security Recommendations

1. **Sideload, don't publish**: Avoid Google Play policy issues entirely
2. **Narrow Accessibility scope**: Set `packageNames="com.hevy"` to limit exposure
3. **Minimal permissions**: Request only what's needed
4. **No credential logging**: Never log Hevy tokens or API keys
5. **HTTPS only**: All backend communication over TLS
6. **Transparent notification**: Show clear notification when bridge is active
7. **Easy disable**: Quick settings tile or notification action to pause bridge
