Skip to main content

Areas alarms

|

Another powerful use case is triggering operations the moment a user enters or exits a defined geographic area.

The Magic Lane Android SDK includes a built-in AlarmService class, making it effortless to configure and manage all your geofence events.

Add areas to be monitored

Define your geographic areas-RectangleGeographicArea, CircleGeographicArea, and PolygonGeographicArea-then invoke the monitorArea method on your AlarmService instance:

// Create a rectangular area using minLat, maxLat, minLon, maxLon
val rect = RectangleGeographicArea(
minLat = 0.5, // minimum latitude
maxLat = 1.0, // maximum latitude
minLon = 0.5, // minimum longitude
maxLon = 1.0 // maximum longitude
)

// Create a circular area with center coordinates and radius in meters
val circle = CircleGeographicArea(
center = Coordinates(latitude = 1.0, longitude = 0.5),
radius = 100 // radius in meters
)

// Create a polygon area with a list of coordinates (first and last should be identical to close the polygon)
val polygonCoordinates = arrayListOf(
Coordinates(latitude = 1.0, longitude = 0.5),
Coordinates(latitude = 0.5, longitude = 1.0),
Coordinates(latitude = 1.0, longitude = 1.0),
Coordinates(latitude = 1.0, longitude = 0.5) // Close the polygon
)
val polygon = PolygonGeographicArea(polygonCoordinates)

// Monitor the areas
SdkCall.execute {
alarmService?.monitorArea(rect)
alarmService?.monitorArea(circle)
alarmService?.monitorArea(polygon)
}

The SDK automatically manages area identification internally for boundary crossing detection.

Get a list of monitored areas

Access your active geofences via the monitoredAreas property, which returns a list of AlarmMonitoredArea objects, each one reflecting the parameters you provided to monitorArea.

val monitoredAreas = alarmService?.monitoredAreas ?: emptyList()

for (monitoredArea in monitoredAreas) {
val area = monitoredArea.area
val id = monitoredArea.id
Log.d("AreaMonitoring", "Monitoring area: $id")
}
Tip

When defining a PolygonGeographicArea, always "close" the shape by making the first and last coordinates identical. Otherwise, the SDK may return polygons that don't match the one you provided.

Unmonitor an area

To remove a monitored area, call the unmonitorArea method and pass in the same GeographicArea instance you originally supplied to monitorArea. This will unregister that zone and stop all related geofence events.

val rect = RectangleGeographicArea(
minLat = 0.5,
maxLat = 1.0,
minLon = 0.5,
maxLon = 1.0
)

alarmService?.monitorArea(rect)
// Later, unmonitor the same area
alarmService?.unmonitorArea(rect)

To unmonitor multiple areas, call unmonitorArea for each area individually.

Get notified when the user enters an area:

Attach your AlarmListener-including the onBoundaryCrossed callback - to your AlarmService. This callback is triggered when the user crosses area boundaries.

val alarmListener = AlarmListener.create {
onBoundaryCrossed {
Log.d("BoundaryCrossed", "Boundary crossed detected")

// Handle area entry/exit events
// Update UI based on area changes
// Use alarmService?.crossedBoundaries to get detailed boundary information
}
}

val alarmService = AlarmService.produce(alarmListener)

Get the list of areas where the user is located

Retrieve the zones the user is currently inside by calling the insideAreas property on your AlarmService instance:

val insideAreas = alarmService?.insideAreas ?: emptyList()
Log.d("AreaMonitoring", "User is inside ${insideAreas.size} areas")
info

For the insideAreas property to return a non-empty list, the user must be inside at least one monitored area and must move or change position within that area.

To retrieve the zones the user has exited, call the outsideAreas property on your AlarmService instance.

Here's a complete Android Activity example that demonstrates area alarm functionality:

import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.magiclane.sdk.core.*
import com.magiclane.sdk.places.Coordinates

class AreaAlarmsActivity : AppCompatActivity() {

private var alarmService: AlarmService? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setupAreaAlarms()
createAndMonitorAreas()
}

private fun setupAreaAlarms() {
// Create alarm listener with boundary crossing callback
val alarmListener = AlarmListener.create {
onBoundaryCrossed {
Log.d("AreaAlarm", "Boundary crossed detected")

// Update UI to show area status changes
// Check crossedBoundaries for detailed information
SdkCall.execute {
val crossedBoundaries = alarmService?.crossedBoundaries
Log.i("AreaAlarm", "Crossed boundaries: $crossedBoundaries")
}
}
}

// Create alarm service
alarmService = AlarmService.produce(alarmListener)
}

private fun createAndMonitorAreas() {
// Create different types of geographic areas
val rectangularArea = RectangleGeographicArea(
minLat = 37.7649,
maxLat = 37.7849,
minLon = -122.4294,
maxLon = -122.4094
)

val circularArea = CircleGeographicArea(
center = Coordinates(latitude = 37.7749, longitude = -122.4194),
radius = 500 // 500 meters radius
)

val polygonCoordinates = arrayListOf(
Coordinates(latitude = 37.7749, longitude = -122.4194),
Coordinates(latitude = 37.7799, longitude = -122.4144),
Coordinates(latitude = 37.7849, longitude = -122.4194),
Coordinates(latitude = 37.7799, longitude = -122.4244),
Coordinates(latitude = 37.7749, longitude = -122.4194) // Close the polygon
)
val polygonArea = PolygonGeographicArea(polygonCoordinates)

// Monitor all areas

alarmService?.monitorArea(rectangularArea)
alarmService?.monitorArea(circularArea)
alarmService?.monitorArea(polygonArea)

Log.d("AreaAlarm", "Started monitoring 3 geographic areas")
checkMonitoredAreas()
}
}

private fun checkMonitoredAreas() {
SdkCall.execute {
val monitoredAreas = alarmService?.monitoredAreas ?: emptyList()
Log.d("AreaAlarm", "Currently monitoring ${monitoredAreas.size} areas")

for (area in monitoredAreas) {
Log.d("AreaAlarm", "Area ID: ${area.id}")
}

// Check which areas user is currently inside
val insideAreas = alarmService?.insideAreas ?: emptyList()
Log.d("AreaAlarm", "User is inside ${insideAreas.size} areas")
}
}

override fun onDestroy() {
super.onDestroy()

// Clean up - unmonitor all areas
SdkCall.execute {
// Unmonitor areas individually using the original area instances
alarmService?.unmonitorArea(rectangularArea)
alarmService?.unmonitorArea(circularArea)
alarmService?.unmonitorArea(polygonArea)
Log.d("AreaAlarm", "Unmonitored all areas")
}
}
}

This example demonstrates:

  • Creating different types of geographic areas (rectangle, circle, polygon)
  • Monitoring areas with the AlarmService
  • Handling boundary crossing events with proper Android logging
  • Checking currently monitored and inside areas
  • Proper cleanup when the activity is destroyed