1page.title=Creating and Monitoring Geofences 2 3trainingnavtop=true 4@jd:body 5 6 7<div id="tb-wrapper"> 8<div id="tb"> 9 10<h2>This lesson teaches you to</h2> 11<ol> 12 <li><a href="#RequestGeofences">Set up for Geofence Monitoring</a></li> 13 <li><a href="#CreateAdd">Create and Add Geofences</a></li> 14 <li><a href="#HandleGeofenceTransitions">Handle Geofence Transitions</a></li> 15 <li><a href="#StopGeofenceMonitoring">Stop Geofence Monitoring</a></li> 16 17</ol> 18 19<h2>You should also read</h2> 20<ul> 21 <li> 22 <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a> 23 </li> 24</ul> 25 26<h2>Try it out</h2> 27 28 <ul> 29 <li> 30 <a href="https://github.com/googlesamples/android-play-location/tree/master/Geofencing" 31 class="external-link">Geofencing</a> 32 </li> 33 </ul> 34 35</div> 36</div> 37<p> 38 Geofencing combines awareness of the user's current location with awareness of the user's 39 proximity to locations that may be of interest. To mark a 40 location of interest, you specify its latitude and longitude. To adjust the proximity for the 41 location, you add a radius. The latitude, longitude, and radius define a geofence, creating a 42 circular area, or fence, around the location of interest. 43</p> 44<p> 45 You can have multiple active geofences, with a limit of 100 per device user. For each geofence, 46 you can ask Location Services to send you entrance and exit events, or you can specify a 47 duration within the geofence area to wait, or <em>dwell</em>, before triggering an event. You 48 can limit the duration of any geofence by specifying an expiration duration in milliseconds. 49 After the geofence expires, Location Services automatically removes it. 50</p> 51 52<img src="{@docRoot}images/training/geofence@2x.png" 53srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geofence@2x.png 2x" alt="" 54 width="400" height="400"/> 55<p> 56 This lesson shows you how to add and remove geofences, and then listen for geofence transitions 57 using an {@link android.app.IntentService}.</p> 58 59<h2 id="RequestGeofences">Set up for Geofence Monitoring</h2> 60<p> 61 The first step in requesting geofence monitoring is to request the necessary permission. 62 To use geofencing, your app must request 63 {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this 64 permission, add the following element as a child element of the 65<code><a href="{@docRoot}guide/topics/manifest/manifest-element.html"><manifest></a></code> 66 element in your app manifest: 67</p> 68<pre> 69<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> 70</pre> 71 72<p> 73 If you want to use an {@link android.app.IntentService} to listen for geofence transitions, 74 add an element specifying the service name. This element must be 75 a child of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html"> 76 <application></a></code> element: 77</p> 78 79<pre> 80<application 81 android:allowBackup="true"> 82 ... 83 <service android:name=".GeofenceTransitionsIntentService"/> 84<application/> 85</pre> 86 87<p>To access the location APIs, you need to create an instance of the 88 Google Play services API client. To learn how to connect your client, see 89 <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect 90 to Google Play Services</a>.</p> 91 92<h2 id="CreateAdd">Create and Add Geofences</h2> 93 94<p>Your app needs to create and add geofences using the location API's builder class for 95 creating Geofence objects, and the convenience class for adding them. Also, to handle the 96 intents sent from Location Services when geofence transitions occur, you can define a 97 {@link android.app.PendingIntent} as shown in this section. 98</p> 99 100<h3>Create geofence objects</h3> 101 102<p> 103 First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder. 104 html">Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and 105 transition types for the geofence. For example, to populate a list object named 106 {@code mGeofenceList}: 107 </p> 108 109<pre> 110mGeofenceList.add(new Geofence.Builder() 111 // Set the request ID of the geofence. This is a string to identify this 112 // geofence. 113 .setRequestId(entry.getKey()) 114 115 .setCircularRegion( 116 entry.getValue().latitude, 117 entry.getValue().longitude, 118 Constants.GEOFENCE_RADIUS_IN_METERS 119 ) 120 .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS) 121 .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | 122 Geofence.GEOFENCE_TRANSITION_EXIT) 123 .build()); 124</pre> 125 126<p>This example pulls data from a constants file. In actual practice, apps might 127 dynamically create geofences based on the user's location.</p> 128 129<h3>Specify geofences and initial triggers</h3> 130 131<p> 132 The following snippet uses the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html"> 133 GeofencingRequest</a></code> class 134 and its nested <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.Builder.html"> 135 GeofencingRequestBuilder</a></code> class to 136 specify the geofences to monitor and to set how related geofence events are triggered: 137</p> 138<pre> 139private GeofencingRequest getGeofencingRequest() { 140 GeofencingRequest.Builder builder = new GeofencingRequest.Builder(); 141 builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER); 142 builder.addGeofences(mGeofenceList); 143 return builder.build(); 144} 145</pre> 146 147<p> 148 This example shows the use of two geofence triggers. The <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER"> 149 GEOFENCE_TRANSITION_ENTER</a></code> 150 transition triggers when a device enters a geofence, and the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT"> 151 GEOFENCE_TRANSITION_EXIT</a></code> 152 transition triggers when a device exits a geofence. Specifying 153 <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER"> 154 INITIAL_TRIGGER_ENTER</a></code> tells Location services that 155 <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER"> 156 GEOFENCE_TRANSITION_ENTER</a></code> 157 should be triggered if the the device is already inside the geofence.</p> 158</p> 159 160<p>In many cases, it may be preferable to use instead <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL"> 161 INITIAL_TRIGGER_DWELL</a></code>, 162 which triggers events only when the user stops for a defined duration within a geofence. 163 This approach can help reduce "alert spam" resulting from large numbers notifications when a 164 device briefly enters and exits geofences. Another strategy for getting best results from your 165 geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy 166 of typical WiFi networks, and also helps reduce device power consumption. 167</p> 168 169<h3>Define an Intent for geofence transitions</h3> 170<p> 171 The {@link android.content.Intent} sent from Location Services can trigger various actions in 172 your app, but you should <i>not</i> have it start an activity or fragment, because components 173 should only become visible in response to a user action. In many cases, an 174 {@link android.app.IntentService} is a good way to handle the intent. An 175 {@link android.app.IntentService} can post a notification, do long-running background work, 176 send intents to other services, or send a broadcast intent. The following snippet shows how 177 to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}: 178</p> 179<pre> 180public class MainActivity extends FragmentActivity { 181 ... 182 private PendingIntent getGeofencePendingIntent() { 183 // Reuse the PendingIntent if we already have it. 184 if (mGeofencePendingIntent != null) { 185 return mGeofencePendingIntent; 186 } 187 Intent intent = new Intent(this, GeofenceTransitionsIntentService.class); 188 // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when 189 // calling addGeofences() and removeGeofences(). 190 return PendingIntent.getService(this, 0, intent, PendingIntent. 191 FLAG_UPDATE_CURRENT); 192 } 193</pre> 194 195<h3>Add geofences</h3> 196 197<p> 198 To add geofences, use the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html#addGeofences(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.GeofencingRequest, android.app.PendingIntent)">{@code GeoencingApi.addGeofences()}</a></code> method. 199 Provide the Google API client, the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest"> 200 GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}. 201 The following snippet, which processes the results in <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)"> 202 onResult()</a></code>, assumes that the main activity implements <code><a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html"> 203 ResultCallback</a></code>: 204</p> 205<pre> 206public class MainActivity extends FragmentActivity { 207 ... 208 LocationServices.GeofencingApi.addGeofences( 209 mGoogleApiClient, 210 getGeofencingRequest(), 211 getGeofencePendingIntent() 212 ).setResultCallback(this); 213</pre> 214 215 216<h2 id="HandleGeofenceTransitions">Handle Geofence Transitions</h2> 217<p> 218 When Location Services detects that the user has entered or exited a geofence, it 219 sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent} 220 you included in the request to add geofences. This {@link android.content.Intent} is received 221 by a service like <code>GeofenceTransitionsIntentService</code>, 222 which obtains the geofencing event from the intent, determines the type of Geofence transition(s), 223 and determines which of the defined geofences was triggered. It then sends a notification as 224 the output. 225</p> 226<p> 227 The following snippet shows how to define an {@link android.app.IntentService} that posts a 228 notification when a geofence transition occurs. When the user clicks the notification, the 229 app's main activity appears: 230</p> 231<pre> 232public class GeofenceTransitionsIntentService extends IntentService { 233 ... 234 protected void onHandleIntent(Intent intent) { 235 GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 236 if (geofencingEvent.hasError()) { 237 String errorMessage = GeofenceErrorMessages.getErrorString(this, 238 geofencingEvent.getErrorCode()); 239 Log.e(TAG, errorMessage); 240 return; 241 } 242 243 // Get the transition type. 244 int geofenceTransition = geofencingEvent.getGeofenceTransition(); 245 246 // Test that the reported transition was of interest. 247 if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER || 248 geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) { 249 250 // Get the geofences that were triggered. A single event can trigger 251 // multiple geofences. 252 List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences(); 253 254 // Get the transition details as a String. 255 String geofenceTransitionDetails = getGeofenceTransitionDetails( 256 this, 257 geofenceTransition, 258 triggeringGeofences 259 ); 260 261 // Send notification and log the transition details. 262 sendNotification(geofenceTransitionDetails); 263 Log.i(TAG, geofenceTransitionDetails); 264 } else { 265 // Log the error. 266 Log.e(TAG, getString(R.string.geofence_transition_invalid_type, 267 geofenceTransition)); 268 } 269 } 270</pre> 271 272<p>After detecting the transition event via the {@link android.app.PendingIntent}, 273 this {@link android.app.IntentService} gets the geofence transition type and tests whether 274 it is one of the events the app uses to trigger notifications -- either 275 <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">GEOFENCE_TRANSITION_ENTER</a></code> 276 or <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">GEOFENCE_TRANSITION_EXIT</a></code> 277 in this case. The service then sends a notification and logs the transition details.</p> 278<!-- 279 Remove Geofences 280 --> 281<h2 id="StopGeofenceMonitoring">Stop Geofence Monitoring</h2> 282 283<p>Stopping geofence monitoring when it is no longer needed or desired can help save battery 284 power and CPU cycles on the device. You can stop geofence monitoring 285 in the main activity used to add and remove geofences; removing a geofence stops it 286 immediately. The API provides methods to 287 remove geofences either by request IDs, or by removing geofences associated with a given 288 {@link android.app.PendingIntent}. 289</p> 290<p> 291 The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all 292 further notification when the device enters or exits previously added geofences: 293</p> 294<pre> 295LocationServices.GeofencingApi.removeGeofences( 296 mGoogleApiClient, 297 // This is the same pending intent that was used in addGeofences(). 298 getGeofencePendingIntent() 299 ).setResultCallback(this); // Result processed in onResult(). 300} 301</pre> 302 303<p> 304 You can combine geofencing with other location-aware features, such as periodic location updates. 305 For more information, see the other lessons in this class. 306</p> 307