Skip to content

Data types

Every type is a Kotlin data class decoded from the engine’s JSON. Fields that the engine may legitimately omit are nullable; fields it always sends are not. Where a field is nullable, that nullability is load-bearing — see the note on isMoving at the end.

Location

The payload of onLocation, the return of getCurrentPosition(), and the record shape in the upload queue.

FieldTypeNotes
uuidStringStable per record; the handle destroyLocation() takes.
timestampStringISO 8601, UTC.
ageDouble?Milliseconds between the fix being taken and processed.
odometerDoubleCumulative metres since the last reset.
coordsCoordsSee below.
activityMotionActivityClassification at the time of the fix.
batteryBatteryLevel and charging state.
isMovingBooleanThe motion machine’s verdict for this fix.
sampleBoolean?true for a getCurrentPosition() sample that was not persisted.
eventString?"motionchange", "heartbeat", "geofence", or absent for an ordinary fix.
extrasJSONObject?Whatever you attached via config or getCurrentPosition(extras = …).

Coords

FieldTypeNotes
latitudeDouble
longitudeDouble
accuracyDoubleHorizontal radius, metres — the number the accuracy gate filters on.
altitudeDouble?Metres above sea level.
altitudeAccuracyDouble?
speedDouble?m/s. -1 means “unknown” on some devices; treat negatives as absent.
speedAccuracyDouble?
headingDouble?Degrees; negative means unknown.
headingAccuracyDouble?
ellipsoidalAltitudeDouble?Height above the WGS84 ellipsoid, where the device reports it.

MotionActivity

FieldTypeNotes
typeActivityTypeSTILL, WALKING, IN_VEHICLE, …
confidenceInt0–100, from Play Services activity recognition.

The engine ignores a classification below minimumActivityRecognitionConfidence (75 by default) when deciding motion state, so a low-confidence IN_VEHICLE does not by itself wake tracking.

Battery

FieldTypeNotes
levelDouble0.0–1.0. -1 means unknown — guard before showing a percentage.
isChargingBoolean

State

Returned by ready(), setConfig(), start(), stop() and getState().

FieldTypeNotes
enabledBooleanWhether tracking is on. This is the persisted intent, not “is a fix arriving right now”.
rawJSONObjectEverything else the engine reported.

raw is deliberately untyped: it is a superset of health and diagnostic fields that grows with the engine, and a typed class would have to be released in lockstep to stay honest. Read it with state["key"], which returns null for both an absent key and a JSON null:

val state = BackgroundGeolocation.getState()
val trackingActive = state["trackingActive"] as? Boolean
val lastFixAge = state["lastAcceptedFixAge"] as? Double // seconds, null until a fix arrives

Fields the Android engine reports today: enabled, trackingMode, isMoving, odometer, geofenceCount, lastGeofenceError, connected, trackingActive, authorization, lastRawFixAge, lastAcceptedFixAge. The two fix ages are in seconds and are null until the first fix — the raw one is stamped before the location filter runs and the accepted one after, so the pair tells “the OS stopped delivering fixes” apart from “the filter is rejecting them”.

ProviderState

From getProviderState(), and the payload of onProviderChange.

FieldTypeNotes
statusAuthorizationStatusThe grant.
enabledBooleanLocation services on at all.
gpsBooleanGPS provider enabled.
networkBooleanNetwork provider enabled.
accuracyAuthorizationAccuracyAuthorization?REDUCED when the user granted approximate location only.

Geofence

FieldTypeNotes
identifierStringYours; unique. Re-adding the same identifier replaces the fence.
radiusDoubleMetres. Under ~100 m, expect the OS to report crossings late.
latitude / longitudeDouble
notifyOnEntryBoolean?Defaults to true engine-side.
notifyOnExitBoolean?Defaults to true engine-side.
notifyOnDwellBoolean?Requires loiteringDelay.
loiteringDelayDouble?Milliseconds inside the radius before DWELL fires.
extrasJSONObject?Echoed back on every event for this fence.

Event payloads

MotionChangeEvent

FieldTypeNotes
isMovingBoolean
locationLocation?Null on the first motionchange of a tracking session on Android — the engine has no accepted fix yet.

GeofenceEvent

FieldTypeNotes
identifierString
actionGeofenceActionENTER, EXIT, DWELL.
locationLocationThe last accepted fix when the OS delivered the transition — not the point where the boundary was crossed.
extrasJSONObject?From the geofence definition.

GeofencesChangeEvent

FieldTypeNotes
onList<Geofence>Now being monitored by the OS.
offList<Geofence>No longer monitored.

Android limits how many regions one app can monitor, so the engine keeps the nearest maxMonitoredGeofences armed and swaps as you move. This event is how you see that happen; the fences you added all still exist.

HttpEvent

FieldTypeNotes
successBoolean2xx.
statusIntHTTP status; 0 means a network-level failure, not a server response.
responseTextStringBody, truncated to 1024 chars. Logged verbatim — do not put secrets in error bodies.

ConnectivityChangeEvent

FieldType
connectedBoolean

Validated connectivity, not merely “an interface is up” — a captive portal reads as disconnected.

HeartbeatEvent

FieldType
rawJSONObject

Option classes

CurrentPositionOptions

FieldTypeNotes
persistBoolean?Whether the fix enters the upload queue.
samplesInt?How many fixes to collect before returning the best.
timeoutDouble?Seconds.
maximumAgeDouble?Milliseconds; accept a cached fix younger than this.
desiredAccuracyInt?Overrides config for this call.
extrasJSONObject?Attached to the returned record.

WatchPositionOptions

FieldType
intervalDouble?
desiredAccuracyInt?
persistBoolean?
extrasJSONObject?

AuthState

FieldType
accessTokenString?
refreshTokenString?

The engine’s current token pair after a native refresh — read it with getAuthState() when your app needs to stay in step with tokens the SDK rotated on its own. See HTTP & authorization.

LogEntry

FieldTypeNotes
tsStringISO 8601.
levelInt1=ERROR … 5=VERBOSE.
srcString"native" for engine lines.
eventStringDot-namespaced (track.start, wake.rearm) for engine diagnostics.
messageString?
dataAny?Parsed JSON, not a string.

A note on nullability

Nullable fields here are not defensive padding. MotionChangeEvent.location really is absent on the first motion change of a session, and Location.isMoving arrives as null from the engine while motion is still being probed — up to stopTimeout minutes after start(). An earlier SDK declared that field non-null on the strength of a TypeScript interface, and dropped every location for the first minutes of every session while the server received them all. If a field is nullable in this table, the engine can and does send nothing for it.