Skip to main content

Landmark and overlay alarms

|

The AlarmService can be configured to send notifications upon approaching specific landmarks or overlay items within a defined proximity. This behavior can be tailored to trigger notifications exclusively during navigation or simulation modes, or while freely exploring the map without a predefined route.

This can be used to implement different use cases such as:

  • Notify users about incoming reports such as speed cameras, police, accidents or other road hazards.
  • Notify users when approaching points of interest, such as historical landmarks, monuments, or scenic viewpoints.
  • Notify users about traffic signs such as stop and give way signs.
Tip

You can search for landmarks along the active route, whether in navigation or simulation mode, using specific categories or other criteria. Once identified, these landmarks can be added for monitoring. Be sure to account for potential route deviations.

danger

If notifications are not sent via the AlarmListener make sure that:

  • The AlarmService and AlarmListener are properly initialized and are kept alive
  • The alarmDistance and monitorWithoutRoute properties are configured as needed
  • The stores / overlays to be monitored are successfully added to the AlarmService
  • The overlay items are on the correct side of the road. If the items are on the opposite side of the road, notifications will not be triggered

Configure the alarm distance

The distance threshold measured in meters for triggering notifications when approaching a landmark or overlay item can be obtained as follows:

val alarmDistance = alarmService?.alarmDistance ?: 0.0

This threshold can also be adjusted as needed. For example, the following snippet will configure the alarm service to start sending notifications when within 200 meters of one of the monitored items:

alarmService?.alarmDistance = 200.0

Configure alarms without active navigation

The AlarmService can be configured to control whether notifications about approaching landmarks or overlay items are triggered exclusively during navigation (or navigation simulation) on a predefined route, or if they should also occur while freely exploring the map without an active navigation session.

The following snippet demonstrates how to enable notifications for monitored landmarks at all times, regardless of whether navigation is active:

alarmService?.monitorWithoutRoute = true

The value of the preference set above can be accessed as follows:

val isMonitoringWithoutRoute = alarmService?.monitorWithoutRoute ?: false

Landmark alarms

Configure alarms listeners

Users are notified through the onLandmarkAlarmsUpdated and onLandmarkAlarmsPassedOver callbacks when approaching the specified landmarks and when the landmarks have been passed respectively.

The following snippet demonstrates how to retrieve the next landmark to be intercepted and the distance to it and how to detect when a landmark has been passed:

val alarmListener = AlarmListener.create(
onLandmarkAlarmsUpdated = {
SdkCall.execute {
// The landmark alarm list containing the landmarks that are to be intercepted
val landmarkAlarms = alarmService?.landmarkAlarms

if (landmarkAlarms != null && landmarkAlarms.size > 0) {
// Get the closest landmark and its associated distance (in meters)
val closestLandmark = landmarkAlarms.getItem(0)
val distance = landmarkAlarms.getDistance(0)

closestLandmark?.let { landmark ->
Log.i("LandmarkAlarm", "The landmark ${landmark.name} is ${distance.toInt()} meters away")
}
}
}
},
onLandmarkAlarmsPassedOver = {
Log.d("LandmarkAlarm", "Landmark was passed over")

SdkCall.execute {
// The landmarks that were passed over
val landmarkAlarmsPassedOver = alarmService?.landmarkAlarmsPassedOver

// Process the landmarks that were passed over
landmarkAlarmsPassedOver?.let { passedAlarms ->
for (i in 0 until passedAlarms.size) {
val landmark = passedAlarms.getItem(i)
landmark?.let {
Log.d("LandmarkAlarm", "Passed landmark: ${it.name}")
}
}
}
}
}
)
info

The onLandmarkAlarmsUpdated callback will be continuously triggered once the threshold distance is exceeded, until the landmark is intercepted. The onLandmarkAlarmsPassedOver callback is called once when the landmark is intercepted.

danger

The items within landmarkAlarmsPassedOver do not have a predefined sort order. To identify the most recently passed landmark, you can compare the current list of items with the previous list of landmarkAlarmsPassedOver entries.

Specify the landmarks to be monitored

Landmarks can be defined and added to the AlarmService for monitoring. The user will receive notifications through the onLandmarkAlarmsUpdated callback when approaching specified landmarks.

// Create landmarks to monitor
val landmark1 = Landmark().apply {
name = "Landmark 1"
coordinates = Coordinates(49.0576, 1.9705)
}

val landmark2 = Landmark().apply {
name = "Landmark 2"
coordinates = Coordinates(43.7704, 1.2360)
}
//Create a landmark store and add the landmarks to it
LandmarkStoreService().createLandmarkStore("Landmarks to be monitored").also { result ->
result?.let { (store, err) ->
if (!GemError.isError(err))
store?.let {
it.addLandmark(landmark1)
it.addLandmark(landmark2)
//add the landmark store to the alarm service for monitoring
alarmService?.landmarkStores?.add(it)
}
}
}

Multiple landmark stores can be added to the monitoring list simultaneously. These stores can be updated later by modifying the landmarks within them or removed from the monitoring list as needed.

Overlay alarms

The workflow for overlay items is similar to that for landmarks, with comparable behavior and functionality. Notifications for overlay items are triggered in the same way as for landmarks, based on proximity or other criteria. The steps for monitoring, and handling events related to overlay items align with those for landmarks. All the notices specified above for landmarks are also applicable for overlay items.

danger

To enable overlay alarms, a map view must be created, and a style containing the overlay to be monitored should be applied. Additionally, the overlay needs to be enabled for the alarms to function properly.

Configure alarms listeners

The following snippet demonstrates how to retrieve the next overlay item to be intercepted and the distance to it and how to detect when a overlay item has been passed:

val alarmListener = AlarmListener.create(
onOverlayItemAlarmsUpdated = {
SdkCall.execute {
// The overlay item alarm list containing the overlay items that are to be intercepted
val overlayItemAlarms = alarmService?.overlayItemAlarms

if (overlayItemAlarms != null && overlayItemAlarms.size > 0) {
// Get the closest overlay item and its associated distance
val closestOverlayItem = overlayItemAlarms.getItem(0)
val distance = overlayItemAlarms.getDistance(0)

closestOverlayItem?.let { overlayItem ->
Log.i("OverlayAlarm", "The overlay item is ${distance.toInt()} meters away")
}
}
}
},
onOverlayItemAlarmsPassedOver = {
Log.d("OverlayAlarm", "Overlay item was passed over")

SdkCall.execute {
// The overlay items that were passed over
val overlayItemAlarmsPassedOver = alarmService?.overlayItemAlarmsPassedOver

// Process the overlay items that were passed over
overlayItemAlarmsPassedOver?.let { passedAlarms ->
for (i in 0 until passedAlarms.size) {
val overlayItem = passedAlarms.getItem(i)
overlayItem?.let {
Log.d("OverlayAlarm", "Passed overlay item at distance: ${passedAlarms.getDistance(i)}")
}
}
}
}
}
)

Specify the overlays to be monitored

The workflow for specifying the overlay items to be monitored is a bit different from the workflow for landmarks. Instead of specifying the landmarks one by one, the overlay items are specified as a whole, based on the overlay and on the overlay categories.

The snippet below shows how to add specific overlay types to be monitored:

// Add safety cameras overlay (speed cameras, red light cameras, etc.)
alarmService?.startAlarmForOverlay(ECommonOverlayId.Safety)

// Add multiple overlay types at once
val overlayIds = arrayListOf(
ECommonOverlayId.Safety,
ECommonOverlayId.SocialReports
)
alarmService?.startAlarmForOverlays(overlayIds)

// Alternative: Directly access overlays collection
alarmService?.overlays?.let { overlaysCollection ->
// Add specific overlay by getting it from OverlayService
val overlayService = OverlayService()
val safetyOverlays = overlayService.getOverlaysById(arrayListOf(ECommonOverlayId.Safety))
overlaysCollection.add(safetyOverlays.first)
}

You can also remove specific overlays from monitoring:

// Stop monitoring safety cameras
alarmService?.stopAlarmForOverlay(ECommonOverlayId.Safety)

// Stop monitoring multiple overlay types
val overlayIdsToRemove = arrayListOf(
ECommonOverlayId.Safety,
ECommonOverlayId.SocialReports
)
alarmService?.stopAlarmForOverlays(overlayIdsToRemove)

Here's a complete example demonstrating landmark and overlay alarm monitoring in an Android application:

class LandmarkOverlayAlarmsActivity : AppCompatActivity() {

private var alarmService: AlarmService? = null
private lateinit var alarmStatusText: TextView

private val alarmListener = AlarmListener.create(
onLandmarkAlarmsUpdated = {
handleLandmarkAlarmsUpdated()
},
onLandmarkAlarmsPassedOver = {
handleLandmarkAlarmsPassedOver()
},
onOverlayItemAlarmsUpdated = {
handleOverlayAlarmsUpdated()
},
onOverlayItemAlarmsPassedOver = {
handleOverlayAlarmsPassedOver()
},
postOnMain = true
)

private fun initializeAlarmService() {
SdkCall.execute {
alarmService = AlarmService.produce(alarmListener)
alarmService?.apply {
// Configure alarm settings
alarmDistance = 300.0 // 300 meters
monitorWithoutRoute = true

// Add landmarks to monitor
addCustomLandmarks()

// Add overlay monitoring
startAlarmForOverlay(ECommonOverlayId.Safety)
startAlarmForOverlay(ECommonOverlayId.PointsOfInterest)
}
}
}

private fun addCustomLandmarks() {
SdkCall.execute {
alarmService?.landmarkStores?.let { landmarkStores ->
val defaultStore = landmarkStores.default
defaultStore?.let { store ->
// Add custom landmarks
val monument = Landmark().apply {
name = "Historic Monument"
coordinates = Coordinates(52.3676, 4.9041) // Amsterdam
}

val viewpoint = Landmark().apply {
name = "Scenic Viewpoint"
coordinates = Coordinates(52.3702, 4.8952)
}

store.add(monument)
store.add(viewpoint)
}
}
}
}

private fun handleLandmarkAlarmsUpdated() {
SdkCall.execute {
val landmarkAlarms = alarmService?.landmarkAlarms
if (landmarkAlarms != null && landmarkAlarms.size > 0) {
val closestLandmark = landmarkAlarms.getItem(0)
val distance = landmarkAlarms.getDistance(0)

closestLandmark?.let { landmark ->
runOnUiThread {
alarmStatusText.text = "Approaching: ${landmark.name} (${distance.toInt()}m)"
alarmStatusText.setTextColor(Color.BLUE)
}
Log.i("LandmarkAlarm", "Approaching landmark: ${landmark.name} at ${distance}m")
}
}
}
}

private fun handleLandmarkAlarmsPassedOver() {
Log.d("LandmarkAlarm", "Landmark passed")
runOnUiThread {
alarmStatusText.text = "Landmark passed"
alarmStatusText.setTextColor(Color.GREEN)
}
}

private fun handleOverlayAlarmsUpdated() {
SdkCall.execute {
val overlayAlarms = alarmService?.overlayItemAlarms
if (overlayAlarms != null && overlayAlarms.size > 0) {
val closestOverlay = overlayAlarms.getItem(0)
val distance = overlayAlarms.getDistance(0)

closestOverlay?.let { overlayItem ->
runOnUiThread {
alarmStatusText.text = "Safety camera ahead: ${distance.toInt()}m"
alarmStatusText.setTextColor(Color.RED)
}
Log.w("OverlayAlarm", "Safety camera detected at ${distance}m")

// Play warning sound for safety cameras
playAlarmSound()
}
}
}
}

private fun handleOverlayAlarmsPassedOver() {
Log.d("OverlayAlarm", "Overlay item passed")
runOnUiThread {
alarmStatusText.text = "Safety camera passed"
alarmStatusText.setTextColor(Color.GRAY)
}
}

private fun playAlarmSound() {
// Implementation depends on your audio system
// Example: MediaPlayer, TTS, or notification sounds
}

override fun onDestroy() {
super.onDestroy()
SdkCall.execute {
// Clean up monitoring
alarmService?.stopAlarmForOverlay(ECommonOverlayId.Safety)
alarmService?.stopAlarmForOverlay(ECommonOverlayId.PointsOfInterest)
alarmService?.setAlarmListener(null)
}
alarmService = null
}
}

This example demonstrates:

  • Proper initialization of alarm service with both landmark and overlay monitoring
  • Custom landmark creation and monitoring setup
  • Overlay monitoring for safety cameras and points of interest
  • Real-time UI updates showing alarm status and distances
  • Proper cleanup in the activity lifecycle
  • Thread-safe operations using SdkCall.execute and runOnUiThread