sessionMonitor.ts

Manages the active monitoring session lifecycle across iOS and Android

Purpose

This module manages the user-initiated “active monitoring session” — the equivalent of a workout mode. On iOS it uses a continuous GPS location watch to keep the app alive in the background, throttled to run the prediction pipeline at most once per minute. On Android it delegates to the react-native-background-actions foreground service.

Its responsibilities include:

  • Persisting session active state to AsyncStorage so it survives app restarts
  • Starting and stopping iOS GPS location watching with appropriate options
  • Starting and stopping the Android background foreground service
  • Throttling iOS pipeline runs to at most one per MIN_INTERVAL_MS
  • Notifying registered prediction listeners after each pipeline run
  • Exposing a subscription API for the PredictionScreen to react to new results

Invariants

Single Watch Guard

startSession no-ops if watchId is already set, preventing duplicate location watchers from being registered.


Throttle Gate

On iOS, each location update checks Date.now() - lastRunMs < MIN_INTERVAL_MS before running the pipeline.

Throttled updates log a debug message with the remaining cooldown in seconds but do not run inference.


AsyncStorage Session Flag

Session state is persisted to AsyncStorage under "heatsafe_session_active" so isSessionActive() can return the correct value even after a cold start.

stopSession explicitly writes "false" rather than deleting the key, ensuring the flag is always present after the first session.


iOS Location Options

OptionValueRationale
enableHighAccuracyfalseLow-power; only approximate location needed for weather
distanceFilter0Fire on every update; throttle handles rate limiting
showsBackgroundLocationIndicatortrueRequired for App Store transparency (blue status-bar pill)
pauseUpdatesAutomaticallyfalsePrevent iOS from pausing updates during inactivity

Android Permission Before Service Start

requestPersistenceNotificationPermission is called before BackgroundService.start to satisfy the Android 13+ foreground service notification requirement.

If the service is already running (BackgroundService.isRunning()), startSession does not start a second instance.


Exports

predictionListeners

let predictionListeners: PredictionListener[]

Mutable array of listener callbacks invoked after each successful pipeline run. Also used by background.ts to notify the foreground after Android background predictions.


subscribeToPredictions(...)

function subscribeToPredictions(listener: () => void): () => void

Registers a prediction listener and returns an unsubscribe function.


isSessionActive()

async function isSessionActive(): Promise<boolean>

Returns true if the session flag in AsyncStorage is "true". Returns false on storage errors.


startSession()

async function startSession(): Promise<void>

Starts the monitoring session for the current platform. On iOS, begins GPS location watching. On Android, starts the foreground service.


stopSession()

async function stopSession(): Promise<void>

Stops the monitoring session. Clears the GPS watcher (iOS), stops the background service (Android), and writes "false" to the session flag.