{
	"id": "d4911244-bd76-4ea8-a403-add7bbdd3ba1",
	"created_at": "2026-04-06T00:22:29.067338Z",
	"updated_at": "2026-04-10T13:11:52.185307Z",
	"deleted_at": null,
	"sha1_hash": "87c557d222b4b4468e5f883169e78ad2231ca244",
	"title": "Create and monitor geofences",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 232597,
	"plain_text": "Create and monitor geofences\r\nArchived: 2026-04-05 22:40:56 UTC\r\nGeofencing combines awareness of the user's current location with awareness of the user's proximity to locations\r\nthat may be of interest. To mark a location of interest, you specify its latitude and longitude. To adjust the\r\nproximity for the location, you add a radius. The latitude, longitude, and radius define a geofence, creating a\r\ncircular area, or fence, around the location of interest.\r\nYou can have multiple active geofences, with a limit of 100 per app, per device user. For each geofence, you can\r\nask Location Services to send you entrance and exit events, or you can specify a duration within the geofence area\r\nto wait, or dwell, before triggering an event. You can limit the duration of any geofence by specifying an\r\nexpiration duration in milliseconds. After the geofence expires, Location Services automatically removes it.\r\nThis lesson shows you how to add and remove geofences, and then listen for geofence transitions using a\r\nBroadcastReceiver .\r\nNote: On Wear devices, the Geofencing APIs don't make efficient use of power. We don't recommend these APIs\r\non Wear. Read Conserve power and battery for more information.\r\nSet up for geofence monitoring\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 1 of 11\n\nThe first step in requesting geofence monitoring is to request the necessary permissions. To use geofencing, your\napp must request the following:\nACCESS_FINE_LOCATION\nACCESS_BACKGROUND_LOCATION if your app targets Android 10 (API level 29) or higher\nTo learn more, see the guide on how to request location permissions.\nIf you want to use a BroadcastReceiver to listen for geofence transitions, add an element specifying the service\nname. This element must be a child of the element:\n... To access the location APIs, you need to create an instance of the Geofencing client. To learn how to connect your\nclient:\nlateinit var geofencingClient: GeofencingClient\noverride fun onCreate(savedInstanceState: Bundle?) {\n // ...\n geofencingClient = LocationServices.getGeofencingClient(this)\n}\nprivate GeofencingClient geofencingClient;\n@Override\npublic void onCreate(Bundle savedInstanceState) {\n // ...\n geofencingClient = LocationServices.getGeofencingClient(this);\n}\nYour app needs to create and add geofences using the location API's builder class for creating Geofence objects,\nand the convenience class for adding them. Also, to handle the intents sent from Location Services when geofence\ntransitions occur, you can define a PendingIntent as shown in this section.\nNote: On single-user devices, there is a limit of 100 geofences per app. For multi-user devices, the limit is 100\ngeofences per app per device user.\nCreate geofence objects\nhttps://developer.android.com/training/location/geofencing\nPage 2 of 11\n\nFirst, use Geofence.Builder to create a geofence, setting the desired radius, duration, and transition types for the\r\ngeofence. For example, to populate a list object:\r\ngeofenceList.add(Geofence.Builder()\r\n // Set the request ID of the geofence. This is a string to identify this\r\n // geofence.\r\n .setRequestId(entry.key)\r\n // Set the circular region of this geofence.\r\n .setCircularRegion(\r\n entry.value.latitude,\r\n entry.value.longitude,\r\n Constants.GEOFENCE_RADIUS_IN_METERS\r\n )\r\n // Set the expiration duration of the geofence. This geofence gets automatically\r\n // removed after this period of time.\r\n .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)\r\n // Set the transition types of interest. Alerts are only generated for these\r\n // transition. We track entry and exit transitions in this sample.\r\n .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)\r\n // Create the geofence.\r\n .build())\r\ngeofenceList.add(new Geofence.Builder()\r\n // Set the request ID of the geofence. This is a string to identify this\r\n // geofence.\r\n .setRequestId(entry.getKey())\r\n .setCircularRegion(\r\n entry.getValue().latitude,\r\n entry.getValue().longitude,\r\n Constants.GEOFENCE_RADIUS_IN_METERS\r\n )\r\n .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)\r\n .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |\r\n Geofence.GEOFENCE_TRANSITION_EXIT)\r\n .build());\r\nThis example pulls data from a constants file. In actual practice, apps might dynamically create geofences based\r\non the user's location.\r\nSpecify geofences and initial triggers\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 3 of 11\n\nThe following snippet uses the GeofencingRequest class and its nested GeofencingRequestBuilder class to\r\nspecify the geofences to monitor and to set how related geofence events are triggered:\r\nprivate fun getGeofencingRequest(): GeofencingRequest {\r\n return GeofencingRequest.Builder().apply {\r\n setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)\r\n addGeofences(geofenceList)\r\n }.build()\r\n}\r\nprivate GeofencingRequest getGeofencingRequest() {\r\n GeofencingRequest.Builder builder = new GeofencingRequest.Builder();\r\n builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);\r\n builder.addGeofences(geofenceList);\r\n return builder.build();\r\n}\r\nThis example shows the use of two geofence triggers. The GEOFENCE_TRANSITION_ENTER transition triggers when\r\na device enters a geofence, and the GEOFENCE_TRANSITION_EXIT transition triggers when a device exits a\r\ngeofence. Specifying INITIAL_TRIGGER_ENTER tells Location services that GEOFENCE_TRANSITION_ENTER should\r\nbe triggered if the device is already inside the geofence.\r\nIn many cases, it may be preferable to use instead INITIAL_TRIGGER_DWELL , which triggers events only when the\r\nuser stops for a defined duration within a geofence. This approach can help reduce \"alert spam\" resulting from\r\nlarge numbers notifications when a device briefly enters and exits geofences. Another strategy for getting best\r\nresults from your geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy\r\nof typical Wi-Fi networks, and also helps reduce device power consumption.\r\nDefine a broadcast receiver for geofence transitions\r\nAn Intent sent from Location Services can trigger various actions in your app, but you should not have it start\r\nan activity or fragment, because components should only become visible in response to a user action. In many\r\ncases, a BroadcastReceiver is a good way to handle a geofence transition. A BroadcastReceiver gets updates\r\nwhen an event occurs, such as a transition into or out of a geofence, and can start long-running background work.\r\nThe following snippet shows how to define a PendingIntent that starts a BroadcastReceiver :\r\nclass MainActivity : AppCompatActivity() {\r\n // ...\r\n private val geofencePendingIntent: PendingIntent by lazy {\r\n // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling\r\n // addGeofences() and removeGeofences().\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 4 of 11\n\nval flags = PendingIntent.FLAG_UPDATE_CURRENT\r\n if (android.os.Build.VERSION.SDK_INT \u003e= android.os.Build.VERSION_CODES.S) {\r\n // Starting on Android S+ the pending intent has to be mutable.\r\n flags or PendingIntent.FLAG_MUTABLE\r\n }\r\n val intent = Intent(this, GeofenceBroadcastReceiver::class.java)\r\n PendingIntent.getBroadcast(this, 0, intent, flags)\r\n }\r\n}\r\npublic class MainActivity extends AppCompatActivity {\r\n // ...\r\n private PendingIntent getGeofencePendingIntent() {\r\n // Reuse the PendingIntent if we already have it.\r\n if (geofencePendingIntent != null) {\r\n return geofencePendingIntent;\r\n }\r\n // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling\r\n // addGeofences() and removeGeofences().\r\n int flags = PendingIntent.FLAG_UPDATE_CURRENT;\r\n if (android.os.Build.VERSION.SDK_INT \u003e= android.os.Build.VERSION_CODES.S) {\r\n // Starting on Android S+ the pending intent has to be mutable.\r\n flags |= PendingIntent.FLAG_MUTABLE;\r\n }\r\n Intent intent = new Intent(this, GeofenceBroadcastReceiver.class);\r\n geofencePendingIntent = PendingIntent.getBroadcast(this, 0, intent, flags);\r\n return geofencePendingIntent;\r\n }\r\n}\r\nAdd geofences\r\nTo add geofences, use the GeofencingClient.addGeofences() method. Provide the GeofencingRequest object,\r\nand the PendingIntent . The following snippet demonstrates processing the results:\r\ngeofencingClient?.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {\r\n addOnSuccessListener {\r\n // Geofences added\r\n // ...\r\n }\r\n addOnFailureListener {\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 5 of 11\n\n// Failed to add geofences\r\n // ...\r\n }\r\n}\r\ngeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())\r\n .addOnSuccessListener(this, new OnSuccessListener\u003cVoid\u003e() {\r\n @Override\r\n public void onSuccess(Void aVoid) {\r\n // Geofences added\r\n // ...\r\n }\r\n })\r\n .addOnFailureListener(this, new OnFailureListener() {\r\n @Override\r\n public void onFailure(@NonNull Exception e) {\r\n // Failed to add geofences\r\n // ...\r\n }\r\n });\r\nHandle geofence transitions\r\nWhen Location Services detects that the user has entered or exited a geofence, it sends out the Intent contained\r\nin the PendingIntent you included in the request to add geofences. A broadcast receiver like\r\nGeofenceBroadcastReceiver notices that the Intent was invoked and can then obtain the geofencing event\r\nfrom the intent, determine the type of Geofence transition(s), and determine which of the defined geofences was\r\ntriggered. The broadcast receiver can direct an app to start performing background work or, if desired, send a\r\nnotification as output.\r\nNote: On Android 8.0 (API level 26) and higher, if an app is running in the background while monitoring a\r\ngeofence, then the device responds to geofencing events every couple of minutes. To learn how to adapt your app\r\nto these response limits, see Background Location Limits.\r\nThe following snippet shows how to define a BroadcastReceiver that posts a notification when a geofence\r\ntransition occurs. When the user clicks the notification, the app's main activity appears:\r\nclass GeofenceBroadcastReceiver : BroadcastReceiver() {\r\n // ...\r\n override fun onReceive(context: Context?, intent: Intent?) {\r\n val geofencingEvent = GeofencingEvent.fromIntent(intent)\r\n if (geofencingEvent.hasError()) {\r\n val errorMessage = GeofenceStatusCodes\r\n .getStatusCodeString(geofencingEvent.errorCode)\r\n Log.e(TAG, errorMessage)\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 6 of 11\n\nreturn\r\n }\r\n // Get the transition type.\r\n val geofenceTransition = geofencingEvent.geofenceTransition\r\n // Test that the reported transition was of interest.\r\n if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||\r\n geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {\r\n // Get the geofences that were triggered. A single event can trigger\r\n // multiple geofences.\r\n val triggeringGeofences = geofencingEvent.triggeringGeofences\r\n // Get the transition details as a String.\r\n val geofenceTransitionDetails = getGeofenceTransitionDetails(\r\n this,\r\n geofenceTransition,\r\n triggeringGeofences\r\n )\r\n // Send notification and log the transition details.\r\n sendNotification(geofenceTransitionDetails)\r\n Log.i(TAG, geofenceTransitionDetails)\r\n } else {\r\n // Log the error.\r\n Log.e(TAG, getString(R.string.geofence_transition_invalid_type,\r\n geofenceTransition))\r\n }\r\n }\r\n}\r\npublic class GeofenceBroadcastReceiver extends BroadcastReceiver {\r\n // ...\r\n protected void onReceive(Context context, Intent intent) {\r\n GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);\r\n if (geofencingEvent.hasError()) {\r\n String errorMessage = GeofenceStatusCodes\r\n .getStatusCodeString(geofencingEvent.getErrorCode());\r\n Log.e(TAG, errorMessage);\r\n return;\r\n }\r\n // Get the transition type.\r\n int geofenceTransition = geofencingEvent.getGeofenceTransition();\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 7 of 11\n\n// Test that the reported transition was of interest.\r\n if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||\r\n geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {\r\n // Get the geofences that were triggered. A single event can trigger\r\n // multiple geofences.\r\n List\u003cGeofence\u003e triggeringGeofences = geofencingEvent.getTriggeringGeofences();\r\n // Get the transition details as a String.\r\n String geofenceTransitionDetails = getGeofenceTransitionDetails(\r\n this,\r\n geofenceTransition,\r\n triggeringGeofences\r\n );\r\n // Send notification and log the transition details.\r\n sendNotification(geofenceTransitionDetails);\r\n Log.i(TAG, geofenceTransitionDetails);\r\n } else {\r\n // Log the error.\r\n Log.e(TAG, getString(R.string.geofence_transition_invalid_type,\r\n geofenceTransition));\r\n }\r\n }\r\n}\r\nAfter detecting the transition event via the PendingIntent , the BroadcastReceiver gets the geofence transition\r\ntype and tests whether it is one of the events the app uses to trigger notifications -- either\r\nGEOFENCE_TRANSITION_ENTER or GEOFENCE_TRANSITION_EXIT in this case. The service then sends a notification\r\nand logs the transition details.\r\nStop geofence monitoring\r\nStopping geofence monitoring when it is no longer needed or desired can help save battery power and CPU cycles\r\non the device. You can stop geofence monitoring in the main activity used to add and remove geofences; removing\r\na geofence stops it immediately. The API provides methods to remove geofences either by request IDs, or by\r\nremoving geofences associated with a given PendingIntent .\r\nThe following snippet removes geofences by PendingIntent , stopping all further notification when the device\r\nenters or exits previously added geofences:\r\ngeofencingClient?.removeGeofences(geofencePendingIntent)?.run {\r\n addOnSuccessListener {\r\n // Geofences removed\r\n // ...\r\n }\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 8 of 11\n\naddOnFailureListener {\r\n // Failed to remove geofences\r\n // ...\r\n }\r\n}\r\ngeofencingClient.removeGeofences(getGeofencePendingIntent())\r\n .addOnSuccessListener(this, new OnSuccessListener\u003cVoid\u003e() {\r\n @Override\r\n public void onSuccess(Void aVoid) {\r\n // Geofences removed\r\n // ...\r\n }\r\n })\r\n .addOnFailureListener(this, new OnFailureListener() {\r\n @Override\r\n public void onFailure(@NonNull Exception e) {\r\n // Failed to remove geofences\r\n // ...\r\n }\r\n });\r\nYou can combine geofencing with other location-aware features, such as periodic location updates. For more\r\ninformation, see the other lessons in this class.\r\nUse best practices for geofencing\r\nThis section outlines recommendations for using geofencing with the location APIs for Android.\r\nReduce power consumption\r\nYou can use the following techniques to optimize power consumption in your apps that use geofencing:\r\nSet the notification responsiveness to a higher value. Doing so improves power consumption by increasing\r\nthe latency of geofence alerts. For example, if you set a responsiveness value of five minutes your app only\r\nchecks for an entrance or exit alert once every five minutes. Setting lower values doesn't necessarily mean\r\nthat users are notified within that time period (for example, if you set a value of 5 seconds it may take a bit\r\nlonger than that to receive the alert).\r\nUse a larger geofence radius for locations where a user spends a significant amount of time, such as home\r\nor work. While a larger radius doesn't directly reduce power consumption, it reduces the frequency at\r\nwhich the app checks for entrance or exit, effectively lowering overall power consumption.\r\nChoose the optimal radius for your geofence\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 9 of 11\n\nFor best results, the minimum radius of the geofence should be set between 100 - 150 meters. When Wi-Fi is\r\navailable location accuracy is usually between 20 - 50 meters. When indoor location is available, the accuracy\r\nrange can be as small as 5 meters. Unless you know indoor location is available inside the geofence, assume that\r\nWi-Fi location accuracy is about 50 meters.\r\nWhen Wi-Fi location isn't available (for example, when you are driving in rural areas) the location accuracy\r\ndegrades. The accuracy range can be as large as several hundred meters to several kilometers. In cases like this,\r\nyou should create geofences using a larger radius.\r\nExplain to users why your app uses geofencing\r\nBecause your app accesses location in the background when you use geofencing, consider how your app delivers\r\nbenefits to users. Explain to them clearly why your app needs this access to increase user understanding and\r\ntransparency.\r\nFor more information about best practices related to location access, including geofencing, see the privacy best\r\npractices page.\r\nUse the dwell transition type to reduce alert spam\r\nIf you receive a large number of alerts when driving briefly past a geofence, the best way to reduce the alerts is to\r\nuse a transition type of GEOFENCE_TRANSITION_DWELL instead of GEOFENCE_TRANSITION_ENTER . This way, the\r\ndwelling alert is sent only when the user stops inside a geofence for a given period of time. You can choose the\r\nduration by setting a loitering delay.\r\nRe-register geofences only when required\r\nRegistered geofences are kept in the com.google.process.location process owned by the\r\ncom.google.android.gms package. The app doesn’t need to do anything to handle the following events, because\r\nthe system restores geofences after these events:\r\nGoogle Play services is upgraded.\r\nGoogle Play services is killed and restarted by the system due resource restriction.\r\nThe location process crashes.\r\nThe app must re-register geofences if they're still needed after the following events, since the system cannot\r\nrecover the geofences in the following cases:\r\nThe device is rebooted. The app should listen for the device's boot complete action, and then re- register\r\nthe geofences required.\r\nThe app is uninstalled and re-installed.\r\nThe app's data is cleared.\r\nGoogle Play services data is cleared.\r\nThe app has received a GEOFENCE_NOT_AVAILABLE alert. This typically happens after NLP (Android's\r\nNetwork Location Provider) is disabled.\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 10 of 11\n\nTroubleshoot the geofence entrance event\r\nIf geofences aren't being triggered when the device enters a geofence (the GEOFENCE_TRANSITION_ENTER alert isn’t\r\ntriggered), first ensure that your geofences are registered properly as described in this guide.\r\nHere are some possible reasons for alerts not working as expected:\r\nAccurate location isn't available inside your geofence or your geofence is too small. On most devices,\r\nthe geofence service uses only network location for geofence triggering. The service uses this approach\r\nbecause network location consumes much less power, it takes less time to get discrete locations, and most\r\nimportantly it’s available indoors.\r\nWi-Fi is turned off on the device. Having Wi-Fi on can significantly improve the location accuracy, so if\r\nWi-Fi is turned off, your application might never get geofence alerts depending on several settings\r\nincluding the radius of the geofence, the device model, or the Android version. Starting from Android 4.3\r\n(API level 18), we added the capability of “Wi-Fi scan only mode” which allows users to disable Wi-Fi but\r\nstill get good network location. It’s good practice to prompt the user and provide a shortcut for the user to\r\nenable Wi-Fi or Wi-Fi scan only mode if both of them are disabled. Use SettingsClient to ensure that the\r\ndevice's system settings are properly configured for optimal location detection.\r\nNote: If your app targets Android 10 (API level 29) or higher, you cannot call WifiManager.setEnabled()\r\ndirectly unless your app is a system app or a device policy controller (DPC). Instead, use a settings panel.\r\nThere is no reliable network connectivity inside your geofence. If there is no reliable data connection,\r\nalerts might not be generated. This is because the geofence service depends on the network location\r\nprovider which in turn requires a data connection.\r\nAlerts can be late. The geofence service doesn't continuously query for location, so expect some latency\r\nwhen receiving alerts. Usually the latency is less than 2 minutes, even less when the device has been\r\nmoving. If Background Location Limits are in effect, the latency is about 2-3 minutes on average. If the\r\ndevice has been stationary for a significant period of time, the latency may increase (up to 6 minutes).\r\nAdditional resources\r\nTo learn more about Geofencing, view the following materials:\r\nSamples\r\nSample app for creating and monitoring geofences.\r\nSource: https://developer.android.com/training/location/geofencing\r\nhttps://developer.android.com/training/location/geofencing\r\nPage 11 of 11",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MITRE"
	],
	"origins": [
		"web"
	],
	"references": [
		"https://developer.android.com/training/location/geofencing"
	],
	"report_names": [
		"geofencing"
	],
	"threat_actors": [],
	"ts_created_at": 1775434949,
	"ts_updated_at": 1775826712,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/87c557d222b4b4468e5f883169e78ad2231ca244.pdf",
		"text": "https://archive.orkl.eu/87c557d222b4b4468e5f883169e78ad2231ca244.txt",
		"img": "https://archive.orkl.eu/87c557d222b4b4468e5f883169e78ad2231ca244.jpg"
	}
}