Home | History | Annotate | Download | only in location
      1 page.title=Creating and Monitoring Geofences
      2 
      3 trainingnavtop=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     <li><a href="#BestPractices">Use Best Practices for Geofencing</a></li>
     17     <li><a href="#Troubleshooting">Troubleshoot the Geofence Entrance Event</a></li>
     18 </ol>
     19 
     20 <h2>You should also read</h2>
     21 <ul>
     22     <li>
     23         <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
     24     </li>
     25 </ul>
     26 
     27 <h2>Try it out</h2>
     28 
     29    <ul>
     30       <li>
     31         <a href="https://github.com/googlesamples/android-play-location/tree/master/Geofencing"
     32         class="external-link">Geofencing</a>
     33       </li>
     34     </ul>
     35 
     36 </div>
     37 </div>
     38 <p>
     39     Geofencing combines awareness of the user's current location with awareness of the user's
     40     proximity to locations that may be of interest. To mark a
     41     location of interest, you specify its latitude and longitude. To adjust the proximity for the
     42     location, you add a radius. The latitude, longitude, and radius define a geofence, creating a
     43     circular area, or fence, around the location of interest.
     44 </p>
     45 <p>
     46     You can have multiple active geofences, with a limit of 100 per device user. For each geofence,
     47     you can ask Location Services to send you entrance and exit events, or you can specify a
     48     duration within the geofence area to wait, or <em>dwell</em>, before triggering an event. You
     49     can limit the duration of any geofence by specifying an expiration duration in milliseconds.
     50     After the geofence expires, Location Services automatically removes it.
     51 </p>
     52 
     53 <img src="{@docRoot}images/training/geofence@2x.png"
     54 srcset="{@docRoot}images/training/geofence.png 1x, {@docRoot}images/training/geofence@2x.png 2x" alt=""
     55   width="400" height="400"/>
     56 <p>
     57     This lesson shows you how to add and remove geofences, and then listen for geofence transitions
     58     using an {@link android.app.IntentService}.</p>
     59 
     60 <p>We recommend upgrading existing apps to use the
     61 <a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">
     62 LocationServices</a> class, which contains the
     63 <a href="{@docRoot}reference/com/google/android/gms/location/GeofencingApi.html">
     64 GeofencingApi</a> interface. The
     65 <a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">
     66 LocationServices</a> class replaces the
     67 <a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">
     68 LocationClient</a> (deprecated).</p>
     69 
     70 <h2 id="RequestGeofences">Set up for Geofence Monitoring</h2>
     71 <p>
     72     The first step in requesting geofence monitoring is to request the necessary permission.
     73     To use geofencing, your app must request
     74     {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. To request this
     75     permission, add the following element as a child element of the
     76 <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
     77     element in your app manifest:
     78 </p>
     79 <pre>
     80 &lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
     81 </pre>
     82 
     83 <p>
     84     If you want to use an {@link android.app.IntentService} to listen for geofence transitions,
     85     add an element specifying the service name. This element must be
     86     a child of the <code><a href="{@docRoot}guide/topics/manifest/application-element.html">
     87     &lt;application&gt;</a></code> element:
     88 </p>
     89 
     90 <pre>
     91 &lt;application
     92    android:allowBackup=&quot;true&quot;&gt;
     93    ...
     94    &lt;service android:name=".GeofenceTransitionsIntentService"/&gt;
     95 &lt;application/&gt;
     96 </pre>
     97 
     98 <p>To access the location APIs, you need to create an instance of the
     99   Google Play services API client. To learn how to connect your client, see
    100   <a href="{@docRoot}training/location/retrieve-current.html#play-services">Connect
    101   to Google Play Services</a>.</p>
    102 
    103 <h2 id="CreateAdd">Create and Add Geofences</h2>
    104 
    105 <p>Your app needs to create and add geofences using the location API's builder class for
    106  creating Geofence objects, and the convenience class for adding them. Also, to handle the
    107  intents sent from Location Services when geofence transitions occur, you can define a
    108  {@link android.app.PendingIntent} as shown in this section.
    109 </p>
    110 
    111 <p class="note"><strong>Note:</strong> On single-user devices, there is a limit of 100 geofences per app. For multi-user devices, the limit is 100 geofences per app per device user.</p>
    112 
    113 <h3>Create geofence objects</h3>
    114 
    115 <p>
    116     First, use <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html">
    117     Geofence.Builder</a></code> to create a geofence, setting the desired radius, duration, and
    118     transition types for the geofence. For example, to populate a list object named
    119     {@code mGeofenceList}:
    120     </p>
    121 
    122 <pre>
    123 mGeofenceList.add(new Geofence.Builder()
    124     // Set the request ID of the geofence. This is a string to identify this
    125     // geofence.
    126     .setRequestId(entry.getKey())
    127 
    128     .setCircularRegion(
    129             entry.getValue().latitude,
    130             entry.getValue().longitude,
    131             Constants.GEOFENCE_RADIUS_IN_METERS
    132     )
    133     .setExpirationDuration(Constants.GEOFENCE_EXPIRATION_IN_MILLISECONDS)
    134     .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER |
    135             Geofence.GEOFENCE_TRANSITION_EXIT)
    136     .build());
    137 </pre>
    138 
    139 <p>This example pulls data from a constants file. In actual practice, apps might
    140     dynamically create geofences based on the user's location.</p>
    141 
    142 <h3>Specify geofences and initial triggers</h3>
    143 
    144 <p>
    145     The following snippet uses the <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html">
    146     GeofencingRequest</a></code> class
    147     and its nested <code><a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.Builder.html">
    148     GeofencingRequestBuilder</a></code> class to
    149     specify the geofences to monitor and to set how related geofence events are triggered:
    150 </p>
    151 <pre>
    152 private GeofencingRequest getGeofencingRequest() {
    153     GeofencingRequest.Builder builder = new GeofencingRequest.Builder();
    154     builder.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER);
    155     builder.addGeofences(mGeofenceList);
    156     return builder.build();
    157 }
    158 </pre>
    159 
    160 <p>
    161     This example shows the use of two geofence triggers. The <code>
    162 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    163     GEOFENCE_TRANSITION_ENTER</a></code>
    164     transition triggers when a device enters a geofence, and the <code>
    165 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">
    166     GEOFENCE_TRANSITION_EXIT</a></code>
    167     transition triggers when a device exits a geofence. Specifying
    168     <code>
    169 <a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_ENTER">
    170         INITIAL_TRIGGER_ENTER</a></code> tells Location services that
    171     <code>
    172 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    173         GEOFENCE_TRANSITION_ENTER</a></code>
    174     should be triggered if the the device is already inside the geofence.</p>
    175 </p>
    176 
    177 <p>In many cases, it may be preferable to use instead <code>
    178 <a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest.html#INITIAL_TRIGGER_DWELL">
    179     INITIAL_TRIGGER_DWELL</a></code>,
    180     which triggers events only when the user stops for a defined duration within a geofence.
    181     This approach can help reduce "alert spam" resulting from large numbers notifications when a
    182     device briefly enters and exits geofences. Another strategy for getting best results from your
    183     geofences is to set a minimum radius of 100 meters. This helps account for the location accuracy
    184     of typical Wi-Fi networks, and also helps reduce device power consumption.
    185 </p>
    186 
    187 <h3>Define an Intent for geofence transitions</h3>
    188 <p>
    189     The {@link android.content.Intent} sent from Location Services can trigger various actions in
    190     your app, but you should <i>not</i> have it start an activity or fragment, because components
    191     should only become visible in response to a user action. In many cases, an
    192     {@link android.app.IntentService} is a good way to handle the intent. An
    193     {@link android.app.IntentService} can post a notification, do long-running background work,
    194     send intents to other services, or send a broadcast intent. The following snippet shows how
    195     to define a {@link android.app.PendingIntent} that starts an {@link android.app.IntentService}:
    196 </p>
    197 <pre>
    198 public class MainActivity extends FragmentActivity {
    199     ...
    200     private PendingIntent getGeofencePendingIntent() {
    201         // Reuse the PendingIntent if we already have it.
    202         if (mGeofencePendingIntent != null) {
    203             return mGeofencePendingIntent;
    204         }
    205         Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
    206         // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when
    207         // calling addGeofences() and removeGeofences().
    208         return PendingIntent.getService(this, 0, intent, PendingIntent.
    209                 FLAG_UPDATE_CURRENT);
    210     }
    211 </pre>
    212 
    213 <h3>Add geofences</h3>
    214 
    215 <p>
    216     To add geofences, use the <code>
    217 <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.
    218     Provide the Google API client, the <code>
    219 <a href="{@docRoot}reference/com/google/android/gms/location/GeofencingRequest">
    220     GeofencingRequest</a></code> object, and the {@link android.app.PendingIntent}.
    221     The following snippet, which processes the results in <code>
    222 <a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html#onResult(R)">
    223     onResult()</a></code>, assumes that the main activity implements <code>
    224 <a href="{@docRoot}reference/com/google/android/gms/common/api/ResultCallback.html">
    225     ResultCallback</a></code>:
    226 </p>
    227 <pre>
    228 public class MainActivity extends FragmentActivity {
    229     ...
    230     LocationServices.GeofencingApi.addGeofences(
    231                 mGoogleApiClient,
    232                 getGeofencingRequest(),
    233                 getGeofencePendingIntent()
    234         ).setResultCallback(this);
    235 </pre>
    236 
    237 
    238 <h2 id="HandleGeofenceTransitions">Handle Geofence Transitions</h2>
    239 <p>
    240     When Location Services detects that the user has entered or exited a geofence, it
    241     sends out the {@link android.content.Intent} contained in the {@link android.app.PendingIntent}
    242     you included in the request to add geofences. This {@link android.content.Intent} is received
    243     by a service like <code>GeofenceTransitionsIntentService</code>,
    244     which obtains the geofencing event from the intent, determines the type of Geofence transition(s),
    245     and determines which of the defined geofences was triggered. It then sends a notification as
    246     the output.
    247 </p>
    248 <p>
    249     The following snippet shows how to define an {@link android.app.IntentService} that posts a
    250     notification when a geofence transition occurs. When the user clicks the notification, the
    251     app's main activity appears:
    252 </p>
    253 <pre>
    254 public class GeofenceTransitionsIntentService extends IntentService {
    255    ...
    256     protected void onHandleIntent(Intent intent) {
    257         GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
    258         if (geofencingEvent.hasError()) {
    259             String errorMessage = GeofenceErrorMessages.getErrorString(this,
    260                     geofencingEvent.getErrorCode());
    261             Log.e(TAG, errorMessage);
    262             return;
    263         }
    264 
    265         // Get the transition type.
    266         int geofenceTransition = geofencingEvent.getGeofenceTransition();
    267 
    268         // Test that the reported transition was of interest.
    269         if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER ||
    270                 geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT) {
    271 
    272             // Get the geofences that were triggered. A single event can trigger
    273             // multiple geofences.
    274             List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
    275 
    276             // Get the transition details as a String.
    277             String geofenceTransitionDetails = getGeofenceTransitionDetails(
    278                     this,
    279                     geofenceTransition,
    280                     triggeringGeofences
    281             );
    282 
    283             // Send notification and log the transition details.
    284             sendNotification(geofenceTransitionDetails);
    285             Log.i(TAG, geofenceTransitionDetails);
    286         } else {
    287             // Log the error.
    288             Log.e(TAG, getString(R.string.geofence_transition_invalid_type,
    289                     geofenceTransition));
    290         }
    291     }
    292 </pre>
    293 
    294 <p>After detecting the transition event via the {@link android.app.PendingIntent},
    295     this {@link android.app.IntentService} gets the geofence transition type and tests whether
    296     it is one of the events the app uses to trigger notifications -- either
    297     <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">GEOFENCE_TRANSITION_ENTER</a></code>
    298      or <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_EXIT">GEOFENCE_TRANSITION_EXIT</a></code>
    299     in this case. The service then sends a notification and logs the transition details.</p>
    300 <!--
    301     Remove Geofences
    302  -->
    303 <h2 id="StopGeofenceMonitoring">Stop Geofence Monitoring</h2>
    304 
    305 <p>Stopping geofence monitoring when it is no longer needed or desired can help save battery
    306     power and CPU cycles on the device. You can stop geofence monitoring
    307     in the main activity used to add and remove geofences; removing a geofence stops it
    308     immediately. The API provides methods to
    309     remove geofences either by request IDs, or by removing geofences associated with a given
    310     {@link android.app.PendingIntent}.
    311 </p>
    312 <p>
    313     The following snippet removes geofences by {@link android.app.PendingIntent}, stopping all
    314     further notification when the device enters or exits previously added geofences:
    315 </p>
    316 <pre>
    317 LocationServices.GeofencingApi.removeGeofences(
    318             mGoogleApiClient,
    319             // This is the same pending intent that was used in addGeofences().
    320             getGeofencePendingIntent()
    321     ).setResultCallback(this); // Result processed in onResult().
    322 }
    323 </pre>
    324 
    325 <p>
    326     You can combine geofencing with other location-aware features, such as periodic location updates.
    327     For more information, see the other lessons in this class.
    328 </p>
    329 
    330 <h2 id="BestPractices">Use Best Practices for Geofencing</h2>
    331 
    332 <p>This section outlines recommendations for using geofencing with the location
    333 APIs for Android.</p>
    334 
    335 <h3>Reduce power consumption</h3>
    336 
    337 <p>You can use the following techniques to optimize power consumption in your apps that use geofencing:</p>
    338 
    339 <ul>
    340 <li><p>Set the <a href="{@docRoot}android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    341 notification responsiveness</a> to a higher value. Doing so improves power consumption by
    342 increasing the latency of geofence alerts. For example, if you set a responsiveness value of five
    343 minutes your app only checks for an entrance or exit alert once every five minutes.
    344 Setting lower values does not necessarily mean that users will be notified within that time period
    345 (for example, if you set a value of 5 seconds it may take a bit longer than that to receive the
    346 alert).</p></li>
    347 <li><p>Use a larger geofence radius for locations where a user spends a significant amount of time,
    348 such as home or work. While a larger radius doesn't directly reduce power consumption, it reduces
    349 the frequency at which the app checks for entrance or exit, effectively lowering overall power
    350 consumption.</p></li>
    351 </ul>
    352 
    353 <h3>Choose the optimal radius for your geofence</h3>
    354 <p>For best results, the minimium radius of the geofence should be set between 100 - 150 meters.
    355 When Wi-Fi is available location accuracy is usually between 20 - 50 meters. When indoor
    356 location is available, the accuracy range can be as small as 5 meters. Unless you know indoor
    357 location is available inside the geofence, assume that Wi-Fi location accuracy is about
    358 50 meters.</p>
    359 
    360 <p>When Wi-Fi location is not available (for example, when you are driving in rural areas) the
    361 location accuracy degrades. The accuracy range can be as large as several hundred meters to
    362 several kilometers. In cases like this, you should create geofences using a larger radius.</p>
    363 
    364 <h3>Use the dwell transition type to reduce alert spam</h3>
    365 
    366 <p>If you receive a large number of alerts when driving briefly past a geofence, the best way to
    367 reduce the alerts is to use a transition type of <code>
    368 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_DWELL">
    369 GEOFENCE_TRANSITION_DWELL</a></code> instead of <code>
    370 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    371 GEOFENCE_TRANSITION_ENTER</a></code>. This way, the dwelling alert is sent only when the user stops
    372 inside a geofence for a given period of time. You can choose the duration by setting a
    373 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html#setLoiteringDelay(int)">
    374 loitering delay</a>.</p>
    375 
    376 <h3>Re-register geofences only when required</h3>
    377 
    378 <p>Registered geofences are kept in the <code>com.google.process.location</code> process owned by
    379 the <code>com.google.android.gms</code> package.
    380 The app doesnt need to do anything to handle the following events, because the system
    381 restores geofences after these events:</p>
    382 <ul>
    383 <li>Google Play services is upgraded.</li>
    384 <li>Google Play services is killed and restarted by the system due resource restriction.</li>
    385 <li>The location process crashes.</li>
    386 </ul>
    387 <p>The app must re-register geofences if they're still needed after the following events, since
    388 the system cannot recover the geofences in the following cases:</p>
    389 
    390 <ul>
    391 <li>The device is rebooted. The app should listen for the device's boot complete action, and then re-
    392 register the geofences required.</li>
    393 <li>The app is uninstalled and re-installed.</li>
    394 <li>The app's data is cleared.</li>
    395 <li>Google Play services data is cleared.</li>
    396 <li>The app has received a <code><a href="{@docRoot}reference/com/google/android/gms/location/LocationStatusCodes.html#GEOFENCE_NOT_AVAILABLE">GEOFENCE_NOT_AVAILABLE</a></code>
    397 alert. This typically happens
    398 after NLP (Android's Network Location Provider) is disabled.</li>
    399 </ul>
    400 
    401 <h2 id="Troubleshooting">Troubleshoot the Geofence Entrance Event</h2>
    402 
    403 <p>If geofences are not being triggered when the device enters a geofence
    404 (the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    405 GEOFENCE_TRANSITION_ENTER</a></code> alert isnt triggered), first ensure that your geofences are
    406 registered properly as described in this guide.</p>
    407 
    408 <p>Here are some possible reasons for alerts not working as expected:</p>
    409 
    410 <ul>
    411 <li><strong>Accurate location is not available inside your geofence or your geofence is too
    412 small.</strong> On most devices, the geofence service uses only network location for geofence
    413 triggering. The service uses this approach because network location consumes much less
    414 power, it takes less time to get discrete locations, and most importantly its available indoors.
    415 Starting with Google Play services 3.2, the geofence service calculates the overlapping ratio of
    416 the location circle and the geofence circle and only generates the entrance alert when the ratio
    417 is at least 85% for a bigger geofence or 75% for a smaller geofence. For an exit alert, the ratio
    418 threshold used is 15% or 25%. Any ratio between these thresholds makes the geofence service mark
    419 the geofence state as <code>INSIDE_LOW_CONFIDENCE</code> or <code>OUTSIDE_LOW_CONFIDENCE</code> and
    420 no alert is sent.</li>
    421 <li><strong>Wi-Fi is turned off on the device.</strong> Having Wi-Fi on can significantly improve
    422 the location accuracy, so if Wi-Fi is turned off, your application might never get geofence alerts
    423 depending on several settings including the radius of the geofence, the device model, or the
    424 Android version. Starting from Android 4.3 (API level 18), we added the capability of Wi-Fi scan
    425 only mode which allows users to disable Wi-Fi but still get good network location. Its good
    426 practice to prompt the user and provide a shortcut for the user to enable Wi-Fi or Wi-Fi scan only
    427 mode if both of them are disabled. Use <a href="{@docRoot}reference/com/google/android/gms/location/SettingsApi">
    428 SettingsApi</a> to ensure that the device's system settings are properly configured for optimal
    429 location detection.</li>
    430 <li><strong>There is no reliable network connectivity inside your geofence.</strong> If there is
    431 no reliable data connection, alerts might not be generated. This is because the geofence service
    432 depends on the network location provider which in turn requires a data connection.</li>
    433 <li><strong>Alerts can be late.</strong> The geofence service does not continuously query for
    434 location, so expect some latency when receiving alerts. Usually the latency is less than 2
    435 minutes, even less when the device has been moving. If the device has been stationary for a
    436 significant period of time, the latency may increase (up to 6 minutes).</li>
    437 </ul>
    438