VPS Location Source
The VPS (Visual Positioning System) Location Source provides highly accurate indoor positioning using camera input. It's especially useful in environments where GPS signals are weak or unavailable.
Wemap VPS must be configured by the Wemap team. Please contact us if you are interested in using it.
We recommend reading the VPS Understanding and Best Practices guide first (product and UX); then use this page for technical implementation.
There are two slightly different ways to configure VPS Location Source:
VPS Locaton Sourcein Wemap ecosystem (withWemapMapSDKor/andWemapGeoARSDK)VPS Locaton Sourcestandalone. For example when you want to use it with third-party Map/AR.
Below you'll find guides for both cases.
Requirements
In addition to common requirement user device has to support ARCore.
Google provides a precise list of supported devices, but you can also check at runtime if device is supported via:
fun checkAvailability() {
WemapVPSARCoreLocationSource.checkAvailabilityAsync(requireContext()) { availability ->
when (availability) {
SUPPORTED_INSTALLED -> // launch VPS Location Source
SUPPORTED_NOT_INSTALLED -> // install ARCore
else -> // explain to the user that his device is not supported
}
}
}
Or you can add a Manifest property to restrict installation on unsupported devices via:
<meta-data
android:name="com.google.ar.core"
android:value="required" />
Installation
Check common installation.
Permissions
VPS Location source requires camera permission. Declare android.permission.CAMERA in your app Manifest as follows:
<uses-permission android:name="android.permission.CAMERA" />
Please request camera permission before creating and starting WemapVPSARCoreLocationSource, because without access to the camera - system can't work.
If you don't do it, system will crash on first access to camera.
private val cameraPermissionHandler =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (!granted) {
// User denied camera access. show a message explaining how to enable it
return
}
// User granted camera access. Continue with WemapVPSARCoreLocationSource
}
fun requestCameraPermission() {
// show a model explaining that camera access is crucial for indoor localization and navigation.
// then check if it's arealy granted and request if not yet
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// User already granted camera access, Continue with WemapVPSARCoreLocationSource
} else {
requestCameraPermission.launch(Manifest.permission.CAMERA)
}
}
Known limitations
ARCore-based relative positioning may occasionally show jumps or drift. Performance can also be affected by factors such as temperature, lighting, and environmental conditions. For example, relative positioning quality may decrease over time due to device temperature or in challenging environments (such as corridors with plain white walls). While we use overlays to reduce these effects, some issues may persist. We are aware of this and are working on improvements.
1. VPS Location Source in Wemap ecosystem
Setting Up the VPS ARCore Location Source
Once you have the MapData, create a WemapVPSARCoreLocationSource instance, set vpsListener, then assign it to Map or/and GeoAR as follows:
fun setupLocationSource(mapData: MapData) {
vpsLocationSource = WemapVPSARCoreLocationSource(requireContext(), mapData)
vpsLocationSource.bind(requireContext(), surfaceView)
vpsLocationSource.vpsListeners.add(vpsListener)
// assign it to the map if you are using WemapMapSDK
mapView.locationManager.apply {
locationSource = vpsLocationSource
isEnabled = true
}
// or/and assign it to GeoARView if you are using WemapGeoARSDK
geoARView.locationManager.locationSource = vpsLocationSource
}
Handling Location Source State Changes
You must handle state changes in WemapVPSARCoreLocationSourceListener, as users may need to scan their environment.
private val vpsListener by lazy {
object: WemapVPSARCoreLocationSourceListener {
override fun onStateChanged(state: State) {
// Handle state changes
}
override fun onScanStatusChanged(status: ScanStatus) {
// Handle scan status changes
}
override fun onBackgroundScanStatusChanged(status: ScanStatus) {
// Handle background scan status changes
}
override fun onLocalizedUser(coordinate: Coordinate, attitude: Attitude, backgroundScan: Boolean) {
// here you could let user know that scan succeded or/and hide other hints
}
}
}
Scanning the Environment
To start tracking the user’s location, you need to allow the user to scan their environment:
fun startScan() {
vpsLocationSource.startScan()
}
Once the system successfully recognizes the user’s location, it will report the ACCURATE_POSITIONING state to WemapVPSARCoreLocationSourceListener. Shortly afterward, the VPS system will start updating the user’s location indicator on the map or in GeoAR. If you are using it with third-party Map or AR you will start receiving updated Coordinate and Attitude values in LocationSourceListener.
The VPS system will also report:
NOT_POSITIONING– indicates that the system hasn't yet recognized the environment and a VPS scan is required. At this point, you should present the camera view to the user to allow them to scan usingvpsLocationSource.startScan().DEGRADED_POSITIONING– indicates that user location tracking is limited. A scan is recommended, but not mandatory, to restore theACCURATE_POSITIONINGstate. We suggest a subtle UI indication when this state occurs, such as a location icon warning or a small toast message prompting the user to re-scan.