Developers
Pathline Data API
Integration Guide · API Revision 1
Archived revision
This is the guide for API revision 1 (Pathline 1.5.x). The current revision is 2, available in Pathline 1.6.x and later — see the current integration guide. This page is kept so integrations built against revision 1 can still reference the exact contract they target.
The Pathline Data API lets another app on the same device read the user's
timeline (visits and trips) and raw recorded location samples from
Pathline, through an exported, read-only Android
ContentProvider.
Reaching the provider requires a single install-time permission your app declares
(auto-granted, no prompt); access to the data is then gated by custom runtime
permissions the user approves in the system permission dialog.
- On-device only. Nothing is sent off the device by this API; you read another local app's data via IPC.
- User-gated. A consumer only ever sees data for scopes the user has explicitly granted.
- Read-only. There is no way to write, modify, or delete Pathline data through this API.
- Audited. Every read — and any denied (unauthorized) attempt — is logged by Pathline and shown to the user, who can revoke access at any time. A denied attempt also notifies the user, so guard your queries (see §8).
Note
This guide targets API revision 1, first available in Pathline 1.5.0 (version code 12). The authority, permission names, URI paths, and column names documented here are part of Pathline's stable contract — see Stability & versioning.
Contents
- How it works
- Requirements & compatibility
- Quick start
- Permissions
- Querying
- Data reference
- Complete example
- Best practices
- Privacy & transparency
- Stability & versioning
- Troubleshooting
- Appendix A — Contract constants
1. How it works
Pathline publishes a ContentProvider at the authority
net.extrawdw.apps.locationhistory.provider. You query one of three
collections by passing a time window as URI query parameters and read the results from the returned
Cursor.
The data model
Pathline organizes location data into three layers, from raw to derived:
- Samples — the raw, individual location fixes (a fused/GPS point with a timestamp, plus accuracy, speed, bearing, device state, …). The lowest level.
- Visits — stays: a continuous period spent at one place, derived by clustering samples. Carries a centroid, radius, and (when known) the matched place.
- Trips — the movements between stays, each with an inferred transport mode, a distance, and — for authorized callers — the route travelled.
Together, visits and trips form the user's timeline; samples are the raw
layer beneath it. A trip references the visits it connects via
from_visit_id / to_visit_id, so you can stitch a continuous
stay → move → stay timeline. Pick the layer your feature needs: the timeline for a
human-readable history, samples for raw analysis.
Collections
| Collection | Content URI | Required permission | Match semantics |
|---|---|---|---|
| Visits | content://net.extrawdw.apps.locationhistory.provider/visits | READ_TIMELINE | overlap |
| Trips | content://net.extrawdw.apps.locationhistory.provider/trips | READ_TIMELINE | overlap |
| Samples | content://net.extrawdw.apps.locationhistory.provider/samples | READ_LOCATION_HISTORY | point-in-window |
Before any of this, your app must hold the install-time API gate permission
net.extrawdw.apps.locationhistory.permission.API — declare it with
<uses-permission> and the system auto-grants it (no prompt). An app that doesn't
declare it can't even resolve the provider, let alone query it. It's necessary but not sufficient:
every read still needs the relevant runtime permission(s) below.
Two refinements layer on top of the base permission (see §4):
- Older than 30 days additionally requires
READ_EXTENDED_HISTORY. - A trip's
encoded_polyline(its precise route) is gated separately from the rest of the trip row: it is populated only when the caller also holdsREAD_TIMELINE_ROUTEorREAD_LOCATION_HISTORY, and isnullotherwise. AREAD_TIMELINE-only caller still gets every trip, just without its route geometry.
2. Requirements & compatibility
| Requirement | Detail |
|---|---|
| Pathline installed | The provider, permissions, and authority only resolve while Pathline is installed. |
| Pathline version | The Data API (revision 1) is available in Pathline 1.5.0 (version code 12) and later. |
| Android version | Android 14 (API 34) or newer — Pathline's minimum. |
| Package visibility | On Android 11+ (targetSdk 30+) you must declare Pathline in your <queries> to see the provider (see below). |
| Threading | ContentResolver.query is blocking — never call it on the main thread. |
Package visibility (Android 11+)
Add this to your consumer app's AndroidManifest.xml, as a direct child of
<manifest>, so your app can resolve Pathline's provider and permissions:
<queries>
<package android:name="net.extrawdw.apps.locationhistory" />
</queries>
Important
Without a <queries> entry (or QUERY_ALL_PACKAGES, which Google Play restricts), ContentResolver calls resolve to null and permission requests are silently denied on Android 11+. Prefer the targeted <queries> declaration above — do not request QUERY_ALL_PACKAGES just for this.
Detecting whether Pathline is installed
fun isPathlineInstalled(context: Context): Boolean =
runCatching {
context.packageManager.getPackageInfo("net.extrawdw.apps.locationhistory", 0)
true
}.getOrDefault(false)
3. Quick start
- Declare the scopes you need and the
<queries>entry in your manifest (§4). - Request the matching runtime permission(s) before reading (§4).
- Query the collection for a time window and read the
Cursoroff the main thread (§5).
Tip
Request only the scope you actually use. If your feature only shows the timeline, request READ_TIMELINE alone — don't ask for location-history or extended-history access you won't use. Users are far more likely to grant a narrow, obviously-justified request.
4. Permissions
The API gate (install-time)
One permission stands apart from the rest:
| Permission (constant) | Protection level | Grants |
|---|---|---|
net.extrawdw.apps.locationhistory.permission.API | normal (install-time, auto-granted) | Permission to reach the provider at all. |
Just declare it with <uses-permission>; the system grants it at
install with no runtime prompt and nothing to request in code. It is a coarse
"this app uses the Pathline API" marker — necessary but not sufficient: every read
still requires the relevant runtime permission(s) below. An app that doesn't declare it can't resolve
or query the provider, and a query without it throws SecurityException.
The data permissions (runtime)
These four are all protectionLevel="dangerous" (runtime, user-approved):
| Permission (constant) | Grants |
|---|---|
…permission.READ_TIMELINE | Read visits and trips (trip routes excluded — see below). |
…permission.READ_TIMELINE_ROUTE | Unlock the trips.encoded_polyline route column. Requested in addition to READ_TIMELINE. |
…permission.READ_LOCATION_HISTORY | Read raw location samples. Also unlocks trips.encoded_polyline. |
…permission.READ_EXTENDED_HISTORY | Read data older than 30 days — required in addition to the relevant base permission. |
A consumer must both declare a permission (manifest) and request it (runtime). Declaring without requesting, or requesting without declaring, will not grant access.
Choosing your scopes
These permissions form an escalating ladder — request the lowest tier your feature needs:
| Your feature needs… | Declare & request |
|---|---|
| Trip types, durations, distances, visits | READ_TIMELINE |
| …plus drawing the route of each trip | READ_TIMELINE + READ_TIMELINE_ROUTE |
| Raw, per-point location fixes (timestamps, accuracy, speed…) | READ_LOCATION_HISTORY |
Note
READ_TIMELINE_ROUTE and READ_LOCATION_HISTORY belong to one permission group (both expose the precise path). On Android, once the user grants one permission in a group, your app's other declared permissions in that group are granted without a second prompt, and they are revoked together as one unit. So a reader that declares both gets them in a single consent; a routes-only reader that declares just READ_TIMELINE_ROUTE (not READ_LOCATION_HISTORY) still never gains sample access. READ_TIMELINE and READ_EXTENDED_HISTORY are standalone — each is its own independent consent.
Declare (consumer AndroidManifest.xml)
<!-- Required by every consumer: the install-time gate to reach the provider (auto-granted). -->
<uses-permission android:name="net.extrawdw.apps.locationhistory.permission.API" />
<uses-permission android:name="net.extrawdw.apps.locationhistory.permission.READ_TIMELINE" />
<!-- Only if you draw trip routes (or skip it and rely on READ_LOCATION_HISTORY): -->
<uses-permission android:name="net.extrawdw.apps.locationhistory.permission.READ_TIMELINE_ROUTE" />
<!-- Only if you need raw location samples: -->
<uses-permission android:name="net.extrawdw.apps.locationhistory.permission.READ_LOCATION_HISTORY" />
<!-- Only if you need data older than 30 days: -->
<uses-permission android:name="net.extrawdw.apps.locationhistory.permission.READ_EXTENDED_HISTORY" />
Request at runtime
val launcher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { result ->
val granted = result.values.all { it }
// Reload your data if granted; otherwise guide the user (see the OEM note below).
}
// Request only what the current feature needs:
launcher.launch(arrayOf(
"net.extrawdw.apps.locationhistory.permission.READ_TIMELINE",
))
The user can revoke any of these at any time in Settings → Apps → (your app) → Permissions.
Permission requests may not work on every device
Warning
Some Android skins (notably Xiaomi MIUI / HyperOS builds) do not support the third-party custom permissions — the request can be silently denied without any prompt.
Make your flow resilient: if the permission is still not granted after a request, fall back to deep-linking the user to your app's settings page so they can grant it manually. Be aware that some OEM permission managers also hide third-party custom permissions in their own UI; if so, the user may need to reach the stock Android permission controller (e.g. Settings → Apps → (your app) → Permissions) to find and grant them.
fun openAppSettings(context: Context) {
context.startActivity(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", context.packageName, null),
).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
)
}
Tip
Re-check permissions in onResume (e.g. with ContextCompat.checkSelfPermission) so your screen reloads automatically when the user returns from the Settings page after granting access.
Errors
| Condition | Thrown by query |
|---|---|
| Caller lacks the collection's base permission | SecurityException |
Window's start is older than 30 days and caller lacks READ_EXTENDED_HISTORY | SecurityException |
start query parameter missing, or end <= start | IllegalArgumentException |
| Unknown collection path | IllegalArgumentException |
Note
Lacking the route permission is not an error: a READ_TIMELINE-only caller's trips query succeeds, with encoded_polyline returned as null on every row. Always null-check that column (§6).
Caution
An over-30-day window without READ_EXTENDED_HISTORY is rejected, never silently narrowed. Either keep start within the last 30 days, or hold the extended-history permission — don't assume a clamped result.
5. Querying
Every collection is queried by a time window passed as URI query parameters:
content://net.extrawdw.apps.locationhistory.provider/<collection>?start=<epochMs>&end=<epochMs>
| Parameter | Required | Meaning |
|---|---|---|
start | Yes | Inclusive start of the window, epoch milliseconds (UTC). |
end | No | Exclusive end of the window, epoch milliseconds (UTC). Defaults to now. |
group | No | Batch-correlation key (see Grouping batched reads). Affects display only, never the data returned. |
Grouping batched reads
A single user-facing refresh often reads several collections at once (e.g. visits + trips + samples). By default those log as separate entries in Pathline's access manager. Pass an optional group key — the same value on every request in the batch — to have Pathline display them as one expandable access group.
- Value: a wall-clock epoch-ms number at/near "now" — use
System.currentTimeMillis()captured once at the start of the batch and reused. (NotelapsedRealtime.) - Validity: honored only when it lands essentially at "now" — between ~120 s before and a few seconds after the moment Pathline receives the request; stale, far-future, or non-numeric values are ignored (the read is still logged, just ungrouped). An invalid
groupnever causes an error. - Scope: grouping is per calling package — you can only group your own reads, never merge with another app's.
- Display only:
grouphas zero effect on what data a query returns. It also can't hide reads — Pathline still logs every individual request; grouped entries are expandable to the originals, and every request (with its group key) appears in the user's exportable log.
val batch = System.currentTimeMillis() // one value for the whole refresh
val visits = query("visits", start, now, group = batch)
val trips = query("trips", start, now, group = batch)
val samples = query("samples", start, now, group = batch)
Note
The 120 s validity is deliberate: a batch must complete within ~2 minutes to group. A long-running sync that spans more than that is several accesses over time and is shown as such — you can't make all-day activity look like a single access.
Match semantics
- Timeline (
visits,trips) — overlap. Any item whose[start_ms, end_ms]span intersects the requested[start, end)window is returned in full, including items that began beforestartor end afterend. A request that lands in the middle of a stay or a journey returns that whole item — you never get truncated fragments. - Samples — point-in-window. A sample is returned when
start <= timestamp_ms < end.
Ordering
Results are ordered ascending by start_ms (timeline) / timestamp_ms (samples).
Ignored arguments
Note
projection, selection, selectionArgs, and sortOrder are ignored. Scope every query through the start / end URI parameters; the column set and ordering are fixed (see §6). Always resolve columns by name with Cursor.getColumnIndexOrThrow(...) rather than by fixed index.
Paging
Important
There is no paging — a query returns the entire matching set in one Cursor. A wide samples window can return tens of thousands of rows. Query in bounded windows (e.g. a day or a week at a time) and always read the cursor off the main thread. When you must cover a long span, split it into several bounded windows queried in sequence (optionally sharing one group key so they log as a single access). A future Pathline version may also cap the maximum window size.
6. Data reference
All times are epoch milliseconds, UTC. Nullable columns are marked ?. Each collection also advertises a directory MIME type via getType() — vnd.android.cursor.dir/vnd.net.extrawdw.apps.locationhistory.<visit|trip|sample> — though ContentResolver.query never requires you to read it.
visits
| Column | Type | Notes |
|---|---|---|
_id | long | Stable visit id. |
start_ms | long | Stay start. |
end_ms | long | Stay end (equals "now" while the visit is ongoing). |
place_id | long? | Matched place id, or null when unconfirmed / candidate-only. |
place_name | string? | Matched place name, else candidate name, else null. |
latitude | double | Visit centroid latitude. |
longitude | double | Visit centroid longitude. |
radius_meters | double | Approximate radius of the stay. |
confidence | float | Place-attribution confidence, [0,1]. |
confirmed | int | 1 if the user confirmed the place, else 0. |
is_ongoing | int | 1 if this is the current open visit, else 0. |
trips
| Column | Type | Notes |
|---|---|---|
_id | long | Stable trip id. |
start_ms | long | Movement start. |
end_ms | long | Movement end. |
mode | string | One of the transport modes below. |
mode_confidence | float | Confidence of mode, [0,1]. |
distance_meters | double | Total distance traveled. |
encoded_polyline | string? | Route as a Google encoded polyline (precision 5). null unless the caller holds READ_TIMELINE_ROUTE or READ_LOCATION_HISTORY (§4). |
confirmed | int | 1 if the user confirmed the mode, else 0. |
from_visit_id | long? | Departure visit id, or null. |
to_visit_id | long? | Arrival visit id, or null. |
samples
| Column | Type | Notes |
|---|---|---|
_id | long | Stable sample id. |
timestamp_ms | long | Time of the fix. |
latitude | double | |
longitude | double | |
altitude | double? | Meters, or null. |
accuracy | float? | Horizontal accuracy radius in meters, or null. |
bearing | float? | Degrees, or null. |
speed | float? | Meters/second, or null. |
provider | string? | Source provider (e.g. fused, gps), or null. |
is_mock | int | 1 if reported as a mock location, else 0. |
device_state | string | One of the device states below. |
ar_activity | string? | Raw Activity-Recognition activity string, or null. |
network_transport | string? | One of the network transports below, or null. |
included_in_computation | int | 1 if used in timeline computation, 0 if excluded (e.g. mock / GPS drift). |
Enumerations
String columns use fixed, stable token sets. Treat any unrecognized value as the UNKNOWN/null case.
| Column | Values |
|---|---|
trips.mode | WALKING, RUNNING, CYCLING, CAR, BUS, RAIL, FERRY, FLIGHT, UNKNOWN |
samples.device_state | STATIONARY, WALKING, RUNNING, CYCLING, IN_VEHICLE, UNKNOWN |
samples.network_transport | WIFI, CELLULAR, ETHERNET, VPN, OTHER, NONE |
7. Complete example
A minimal, production-shaped read: declare → request (with OEM fallback) → query off the main thread.
object Pathline {
const val AUTHORITY = "net.extrawdw.apps.locationhistory.provider"
const val READ_TIMELINE = "net.extrawdw.apps.locationhistory.permission.READ_TIMELINE"
fun windowUri(collection: String, startMs: Long, endMs: Long): Uri =
Uri.parse("content://$AUTHORITY/$collection").buildUpon()
.appendQueryParameter("start", startMs.toString())
.appendQueryParameter("end", endMs.toString())
.build()
}
data class Visit(val id: Long, val name: String?, val startMs: Long, val endMs: Long)
/** Reads visits overlapping [startMs, endMs). Call from a background dispatcher. */
fun readVisits(resolver: ContentResolver, startMs: Long, endMs: Long): List<Visit> {
val out = ArrayList<Visit>()
resolver.query(Pathline.windowUri("visits", startMs, endMs), null, null, null, null)?.use { c ->
val id = c.getColumnIndexOrThrow("_id")
val name = c.getColumnIndexOrThrow("place_name")
val start = c.getColumnIndexOrThrow("start_ms")
val end = c.getColumnIndexOrThrow("end_ms")
while (c.moveToNext()) {
out += Visit(
id = c.getLong(id),
name = if (c.isNull(name)) null else c.getString(name),
startMs = c.getLong(start),
endMs = c.getLong(end),
)
}
}
return out
}
Driving it from a screen, with the permission flow and the OEM fallback:
private val needed = arrayOf(Pathline.READ_TIMELINE)
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { if (it.values.all { granted -> granted }) loadTimeline() else /* show "Open settings" hint */ }
private fun ensureAccessThenLoad() {
val missing = needed.filter {
ContextCompat.checkSelfPermission(this, it) != PackageManager.PERMISSION_GRANTED
}
if (missing.isEmpty()) loadTimeline() else permissionLauncher.launch(missing.toTypedArray())
}
private fun loadTimeline() {
lifecycleScope.launch(Dispatchers.IO) {
val now = System.currentTimeMillis()
val visits = try {
readVisits(contentResolver, now - 24 * 60 * 60 * 1000L, now)
} catch (e: SecurityException) {
emptyList() // permission missing/revoked — prompt or deep-link to settings
}
withContext(Dispatchers.Main) { render(visits) }
}
}
Tip
To read further back than 30 days, widen start and hold READ_EXTENDED_HISTORY — otherwise the query throws SecurityException.
8. Best practices
Important
Always guard the query with a permission check. Call ContextCompat.checkSelfPermission(...) for each required scope and only query when it's granted; otherwise request the permission (or send the user to Settings). A query you aren't authorized for throws SecurityException, is recorded in the user-visible access log as a denied attempt, and immediately notifies the user that your app tried to reach a scope it isn't permitted — so never call the provider speculatively to "see if it works."
fun canRead(context: Context, vararg permissions: String): Boolean =
permissions.all {
ContextCompat.checkSelfPermission(context, it) == PackageManager.PERMISSION_GRANTED
}
// Guard, don't probe:
if (canRead(context, Pathline.READ_TIMELINE)) {
readVisits(contentResolver, start, now) // safe — permission held
} else {
requestPermissions(arrayOf(Pathline.READ_TIMELINE)) // ask first
}
- Query in bounded windows. Prefer a day or a week per query, especially for
samples. There is no paging. - Always go off-thread.
queryis blocking IPC; use a background dispatcher /WorkManager. - Resolve columns by name. Use
getColumnIndexOrThrowand handle nullables withCursor.isNull. - Request the narrowest scope. Only ask for
READ_EXTENDED_HISTORYwhen the user actually navigates past 30 days. - Handle absence and revocation gracefully. Pathline may be uninstalled, or a permission revoked, between launches — catch
SecurityExceptionand re-check on resume. - Don't hardcode column indices or assume ordering beyond the documented ascending sort.
9. Privacy & transparency
Pathline treats third-party access as a first-class privacy surface: every interaction is recorded on-device and shown to the user, who can revoke any app at any time. Design your integration assuming the user sees exactly what you do.
Important
Pathline logs both of these to the audit trail under Settings → Access to Pathline data, and the user can revoke any app's access from there:
- Every successful read — which app, which collection, the requested window, and the number of rows returned.
- Every denied attempt — a well-formed request rejected because your app lacks the permission. It reads nothing, is shown as "Denied", and — unlike a read — notifies the user immediately that your app tried to reach a scope it isn't permitted.
A speculative or unguarded query is therefore both visible and actively surfaced to the user. Always guard your query with a permission check and request the scope first — never probe to "see if it works."
- Read the minimum, on demand. Request the narrowest scope, over the smallest window, in clear response to a user action — bursty or unexplained access is visible to the user.
- On-device only. The audit metadata never leaves the device and is not included in Pathline's encrypted backups.
- Your data handling is your responsibility. This API never exposes another user's data and never leaves the device by itself; what your app does with what it reads is on you (and subject to Google Play's policies).
Notification behavior
Pathline proactively alerts the user about third-party access. Assume both of the following will surface as user notifications:
- On a successful read — a separate, per-app notification (your app's icon on the right, Pathline's on the left) naming your app and summarizing what was read (e.g. "Acme accessed 6 visits, 2,636 location samples."). Reads are coalesced (a burst becomes one alert) and rate-limited per app with an escalating back-off (next alert waits ~1h, then 2h, 4h … up to 24h), so a frequently-reading app won't spam the user. The back-off resets after ~48h quiet.
- On a denied attempt — a separate, immediate notification ("Acme tried to access Location history without permission."). It fires without the coalescing delay because a blocked access is a security-relevant event the user should hear about right away. It rides its own per-app back-off lane (so it never displaces, or is muffled by, the read alert) with the same escalating limit for repeats.
- Standing-access reminder — periodically (about weekly), Pathline reminds the user which apps still hold access, so a granted-and-forgotten app is surfaced for review.
All of these use a dedicated, default-importance "Data access alerts" notification channel the user can tune or mute in system settings, and deep-link into Settings → Access to Pathline data. The user can reset all back-off timers from there, so the next access (read or denied) alerts again at once.
Note
Permissions themselves are standard Android runtime permissions — granting/revoking happens in the OS permission UI, and Pathline sends no notification for a grant or revoke. The alerts above are about reads, denied attempts, and standing access, not permission changes.
Tip
Because access is user-visible and notified, do your reads in clear response to a user action (opening your timeline screen, a widget refresh) rather than silent, high-frequency background polling — and never query a scope you haven't been granted.
10. Stability & versioning
The following are part of the stable contract for API revision 1 and will not change without a new API revision:
- The authority
net.extrawdw.apps.locationhistory.provider. - The collection paths
visits,trips,samples. - The permission names — including the install-time gate
…permission.API— the query-parameter names (start,end), and the column names in §6.
Note
New columns or collections may be added in place; treat unknown columns/values defensively and don't assume a fixed column count. The 30-day boundary for READ_EXTENDED_HISTORY is a fixed product rule.
Warning
Change notifications are not delivered. A Cursor from this provider sets a notification URI, but Pathline does not currently call notifyChange, so a ContentObserver will not fire when data updates. Poll on your own cadence (e.g. on screen open or via WorkManager); do not rely on observers.
11. Troubleshooting
| Symptom | Likely cause / fix |
|---|---|
query returns null | Pathline not installed, or missing <queries> visibility (§2). |
SecurityException on every call | Missing the install-time …permission.API gate — declare it with <uses-permission> (§4). |
SecurityException | Missing base permission, or an over-30-day window without READ_EXTENDED_HISTORY (§4). |
IllegalArgumentException | Missing start, end <= start, or an unknown path (§4). |
| No permission dialog appears | OEM skin suppressing third-party custom-permission prompts — deep-link to app settings (§4). |
| Empty results for a valid window | Permission granted but the user simply has no data in that window, or all samples were excluded. |
encoded_polyline is always null | Caller holds READ_TIMELINE but neither READ_TIMELINE_ROUTE nor READ_LOCATION_HISTORY (§4). |
| Observer never fires | Expected — no change notifications; poll instead (§10). |
Appendix A — Contract constants
Pathline ships the canonical, dependency-free contract at net.extrawdw.apps.locationhistory.api.PathlineContract — prefer copying that file verbatim to avoid string literals. The excerpt below is the string-constant subset for quick reference; the shipped file additionally provides a typed CONTENT_URI and CONTENT_TYPE per collection and a COLUMNS array for each.
Download PathlineContract.kt (revision 1)
object PathlineContract {
const val AUTHORITY = "net.extrawdw.apps.locationhistory.provider"
/** Windows reaching further back than this need READ_EXTENDED_HISTORY. */
const val EXTENDED_HISTORY_WINDOW_MS = 30L * 24 * 60 * 60 * 1000
object Permissions {
/** Install-time gate (normal); declare to reach the provider. Necessary, not sufficient. */
const val API = "net.extrawdw.apps.locationhistory.permission.API"
const val READ_TIMELINE = "net.extrawdw.apps.locationhistory.permission.READ_TIMELINE"
const val READ_TIMELINE_ROUTE = "net.extrawdw.apps.locationhistory.permission.READ_TIMELINE_ROUTE"
const val READ_LOCATION_HISTORY = "net.extrawdw.apps.locationhistory.permission.READ_LOCATION_HISTORY"
const val READ_EXTENDED_HISTORY = "net.extrawdw.apps.locationhistory.permission.READ_EXTENDED_HISTORY"
}
object QueryParams {
const val START = "start" // inclusive, epoch ms (required)
const val END = "end" // exclusive, epoch ms (optional, defaults to now)
const val GROUP = "group" // optional batch key: epoch ms ~now, within 120s of receipt
}
object Visits {
const val PATH = "visits"
const val ID = "_id"
const val START_MS = "start_ms"
const val END_MS = "end_ms"
const val PLACE_ID = "place_id"
const val PLACE_NAME = "place_name"
const val LATITUDE = "latitude"
const val LONGITUDE = "longitude"
const val RADIUS_METERS = "radius_meters"
const val CONFIDENCE = "confidence"
const val CONFIRMED = "confirmed"
const val IS_ONGOING = "is_ongoing"
}
object Trips {
const val PATH = "trips"
const val ID = "_id"
const val START_MS = "start_ms"
const val END_MS = "end_ms"
const val MODE = "mode"
const val MODE_CONFIDENCE = "mode_confidence"
const val DISTANCE_METERS = "distance_meters"
const val ENCODED_POLYLINE = "encoded_polyline"
const val CONFIRMED = "confirmed"
const val FROM_VISIT_ID = "from_visit_id"
const val TO_VISIT_ID = "to_visit_id"
}
object Samples {
const val PATH = "samples"
const val ID = "_id"
const val TIMESTAMP_MS = "timestamp_ms"
const val LATITUDE = "latitude"
const val LONGITUDE = "longitude"
const val ALTITUDE = "altitude"
const val ACCURACY = "accuracy"
const val BEARING = "bearing"
const val SPEED = "speed"
const val PROVIDER = "provider"
const val IS_MOCK = "is_mock"
const val DEVICE_STATE = "device_state"
const val AR_ACTIVITY = "ar_activity"
const val NETWORK_TRANSPORT = "network_transport"
const val INCLUDED_IN_COMPUTATION = "included_in_computation"
}
}