Manage onboard regions
The onboard region store holds the NDS map data the SDK falls back to when the online cache cannot cover the current location. This guide covers what you can do with it from your app: monitor its state, discover which regions the driver needs, install and remove regions, and choose between deploying a pre-populated map or a small empty map that fills itself up over time.
For a conceptual introduction read Map data overview. For directory placement see Configure map data storage. For corruption recovery see Map corruption recovery.
The region-management types on this page are provided by the com.tomtom.sdk.datamanagement:data-store dependency added in the Map data quickstart.
Obtaining a RegionStore
RegionStore is the runtime handle to the onboard region store. Obtain it after TomTomSdk.initialize(…) completes, and enable update processing — it starts disabled every time the SDK initializes, and no downloads, deletions, or updates run until it is enabled:
val regionStore = TomTomSdk.getOfflineRegionStore()// Update processing is disabled when the SDK starts. Enable it so that// downloads and deletions can run.regionStore.setUpdatesEnabled(true)getOfflineRegionStore() throws IllegalStateException if the SDK was initialized without a regionStorePath (no onboard region store was configured).
The RegionStore methods you use directly are:
setUpdatesEnabled(Boolean)— the master switch for update processing. CallsetUpdatesEnabled(false)to stop all downloads, deletions, and updates again, for example when the user turns off background data in your app settings.replaceMap(…)andreplaceKeystore(…)— used only for corruption recovery. See Map corruption recovery.
Everything else you do with the onboard store — install and delete regions, monitor state, look up which regions cover a position or route — goes through RegionUpdater, described in the next sections.
Obtaining a RegionUpdater
RegionUpdater is the manual-management interface. Obtain it from the RegionStore:
val regionUpdater = regionStore.obtainRegionUpdater()obtainRegionUpdater()returns the same instance until it is closed; a new call afterclose()creates a fresh instance.- Call
regionUpdater.close()when you no longer need it (for example when the map-management screen is dismissed) to release resources. - Throws
IllegalStateExceptionif theRegionStorewas configured without update capability.
Region model
Three concepts are worth introducing before the operations.
Region
A Region is a single downloadable/removable unit of map data. Each region has a stable Region.Id, a localized name, an isUpdatable flag, and a set of children — regions form a tree, from continental roots down to leaf regions.
RegionState
RegionState is the on-device status of an updatable region, combining three properties:
installState— one ofRegionInstallState.NotInstalled,PartiallyInstalled,CompletelyInstalled, orInconsistent(the installed data needs a repair, that is, a re-download).updateState— whether downloading would change the region data on the device (downloadAvailable) and the estimateddownloadSize.nullwhile update information is not yet available.dataInfo— details about the installed data, such as its size on disk.nullwhen the region is not installed.
State changes are reported by RegionInfoUpdateListener.onStatesChanged.
RegionOperation and RegionOperationStatus
An in-flight download or deletion, and its progress. Progress updates are reported by RegionInfoUpdateListener.onOperationStatusesChanged.
Monitoring region state
Register a RegionInfoUpdateListener on the RegionUpdater to receive callbacks whenever the onboard region set, individual region states, or in-flight operations change.
val listener = object : RegionInfoUpdateListener { override fun onStructureChanged(structureResult: Result<RegionStructure, MapUpdateError>) { // Called once when the listener is registered and again whenever the // set of available regions changes. Render the region tree from the // structure's roots and cache its region states. }
override fun onStatesChanged(stateInfo: RegionStateInfo) { // Delta update: merge stateInfo.regionStates into your cached state map. }
override fun onOperationStatusesChanged(statuses: Set<RegionOperationStatus>) { // Delta update on in-flight downloads and deletions. Show progress and // completion in your UI. }}regionUpdater.addRegionInfoUpdateListener(listener)onStructureChanged fires first, providing the full region tree and initial states. onStatesChanged and onOperationStatusesChanged then deliver delta updates — only regions and operations whose state changed since the previous call.
Remove the listener when your UI no longer needs it:
regionUpdater.removeRegionInfoUpdateListener(listener)Discovering which regions to install
Two lookup methods answer the “which regions cover this area” question without downloading anything. Both are asynchronous and return a Cancellable handle you can use to abort the query.
Around a position
val query = regionUpdater.findRegionsAroundPosition( position = currentPosition, radius = Distance.kilometers(30), callback = object : RegionQueryCallback { override fun onSuccess(result: Set<Region.Id>) { // These regions cover the requested area; pass them to download(). }
override fun onFailure(failure: MapUpdateError) { // Handle the failure. } },)Use this on first launch to figure out which region contains the driver’s current location, or before opening a map-management picker to show the user “these are the regions around you”.
Along a route
val query = regionUpdater.findRegionsAlongPolyline( polyline = routeGeometry, // Requires at least two points. radius = Distance.kilometers(3), // Corridor half-width. callback = object : RegionQueryCallback { override fun onSuccess(result: Set<Region.Id>) { // Check coverage, or pass the IDs to download(). }
override fun onFailure(failure: MapUpdateError) { // Handle the failure. } },)Use this before starting a long trip to check whether the driver has onboard coverage for the whole route.
Both queries only identify regions. To actually install them, hand the returned Region.Id values to download — note that the callbacks deliver a Set<Region.Id> while download and delete take a List<Region.Id>.
A third way to choose regions is to let the user browse the full region tree delivered by RegionInfoUpdateListener.onStructureChanged — the approach behind the region-management screen described in the first-install options below.
Installing and removing regions
Downloading
val result = regionUpdater.download(regionIds.toList())The result is Success(Set<RegionOperation>) if the operations were scheduled, or Failure(MapUpdateError) if any could not be — for example if a region is already scheduled, or if none of the passed IDs is available for download. Progress and completion are reported through your RegionInfoUpdateListener.
Deleting
val result = regionUpdater.delete(regionIds.toList())Same result type as download; likewise reports through the listener.
Cancelling
regionUpdater.cancelOperations( regionIds = regionIds, action = DownloadedRegionDataAction.Delete, // Or .Keep to allow resuming later.)Cancellation of an in-flight download can either delete the partially-downloaded data (frees disk immediately) or keep it, in which case a subsequent download on the same region resumes rather than restarts.
Deployment: pre-populated vs empty map
The regionStorePath you pass to buildSdkConfiguration points at an on-disk NDS map. There are two common ways to provision this directory.
Pre-populated map
The device ships with a full region set for a defined market (for example a continental cut). Advantages: navigation is available immediately on first boot, no connectivity required for the initial user experience. Disadvantages: larger disk footprint at ship time; content freshness lags until the first update. Use this when your product must work out-of-the-box in an unconnected first-boot scenario, or when your legal/commercial arrangement requires shipping content pre-loaded.
Preinstalling the map is not an SDK function — you define the process that places it on the device, for example factory flashing or dealer provisioning. Contact Sales for the map deliverables.
Empty map
The device ships with a minimal region store (metadata only, no downloadable region content) and the driver — or an automated flow — pulls in regions on demand. Advantages: small footprint at ship time; content downloaded is guaranteed fresh. Disadvantages: requires network connectivity for the first drive; you must decide how the initial region set is chosen.
The rest of this section describes the empty-map first-install flow.
First install from an empty map
On first launch, the onboard store contains no regions. Any of the following will populate it:
- User-driven from a picker — call
findRegionsAroundPositionaround the current location (radius wide enough to cover the driver’s home region), present the returned regions in a picker UI, and calldownloadon the user’s selection. TheRegionInfoUpdateListener.onOperationStatusesChangedcallback drives your progress UI. - Programmatic from position — call
findRegionsAroundPositionand immediatelydownloadall returned IDs, without user intervention. Reasonable for a “quiet install” during dealer setup on WiFi. - Programmatic along a planned route — if the driver plans a long route before their first offline stretch,
findRegionsAlongPolylinereturns the regions the route passes through;downloadthem ahead of departure. - Region-management screen — render the full region tree delivered by
RegionInfoUpdateListener.onStructureChangedand let the user browse and select regions by name, showing the estimated download size (RegionState.updateState.downloadSize) and, once installed, the size on disk (RegionState.dataInfo). Calldownloadon the selection. The same screen doubles as the place to delete regions and to surface available updates later.
Whichever entry point you pick, setUpdatesEnabled(true) must have been called first — update processing starts disabled every time the SDK initializes.
Connectivity settings
Whether the SDK is allowed to consume mobile data for region operations is controlled from the regionStoreConfiguration.updateConfiguration { … } block on buildSdkConfiguration. This block exposes a RegionStoreUpdateConfiguration.Builder.
The setting for manual operations is manualUpdateNetworkConfig:
val sdkConfig = buildSdkConfiguration( context = context, apiKey = apiKey, regionStorePath = File(context.filesDir, "region-store"), telemetryUserConsent = { UserConsent.TelemetryOn }, regionStoreConfiguration = { keyStorePath = File(context.filesDir, "keystore") updateConfiguration = { // Allow manual downloads on metered connections (refused by default). manualUpdateNetworkConfig = NetworkConnectivityConfiguration(isMeteredAllowed = true) } },)The default for manualUpdateNetworkConfig is NetworkConnectivityConfiguration(false) — manual downloads are refused on metered connections by default. This matters: an integrator who calls regionUpdater.download(…) on a device with only a mobile connection will see the download fail unless manualUpdateNetworkConfig was set to NetworkConnectivityConfiguration(true).
manualUpdateNetworkConfig accepts only two effective values:
NetworkConnectivityConfiguration(true)— manual downloads proceed on both metered and unmetered connections.NetworkConnectivityConfiguration(false)— manual downloads proceed only on unmetered connections.
The multi-argument constructor of NetworkConnectivityConfiguration that takes a regionAgeForMeteredConnections duration is not valid for manualUpdateNetworkConfig; passing anything other than the two forms above throws IllegalArgumentException at configuration build time.
At runtime, regionStore.setUpdatesEnabled(Boolean) is the master switch: it must have been set to true for any download to run, and setting it to false stops all update processing regardless of connectivity or of manualUpdateNetworkConfig.
Disk usage
mapDiskUsageQuota on the same updateConfiguration block caps the total on-disk size of the region store:
val sdkConfig = buildSdkConfiguration( context = context, apiKey = apiKey, regionStorePath = File(context.filesDir, "region-store"), telemetryUserConsent = { UserConsent.TelemetryOn }, regionStoreConfiguration = { keyStorePath = File(context.filesDir, "keystore") updateConfiguration = { mapDiskUsageQuota = Memory.gibibytes(50) } },)Defaults to null (unlimited — the region store may grow to fill whatever the underlying filesystem allows). Downloads that would exceed the quota do not proceed; free up space by deleting regions.
The locale field on the same block controls the language used for region names surfaced by RegionInfoUpdateListener — useful if your UI needs region names to match the SDK’s other localized strings. Defaults to the user’s preferred locale.
Next steps
Overview
Conceptual introduction to the two data sources and the behavior when connectivity changes.
Configure map data storage
Choose where the online cache and onboard region store live on the device.