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>
    336   Reduce power consumption
    337 </h3>
    338 
    339 <p>
    340   You can use the following techniques to optimize power consumption in your
    341   apps that use geofencing:
    342 </p>
    343 
    344 <ul>
    345   <li>
    346     <p>
    347       Set the <a href=
    348       "https://developers.google.com/android/reference/com/google/android/gms/location/Geofence.Builder.html#setNotificationResponsiveness(int)">
    349       notification responsiveness</a> to a higher value. Doing so improves
    350       power consumption by increasing the latency of geofence alerts. For
    351       example, if you set a responsiveness value of five minutes your app only
    352       checks for an entrance or exit alert once every five minutes. Setting
    353       lower values does not necessarily mean that users will be notified
    354       within that time period (for example, if you set a value of 5 seconds it
    355       may take a bit longer than that to receive the alert).
    356     </p>
    357   </li>
    358 
    359   <li>
    360     <p>
    361       Use a larger geofence radius for locations where a user spends a
    362       significant amount of time, such as home or work. While a larger radius
    363       doesn't directly reduce power consumption, it reduces the frequency at
    364       which the app checks for entrance or exit, effectively lowering overall
    365       power consumption.
    366     </p>
    367   </li>
    368 </ul>
    369 
    370 <h3>Choose the optimal radius for your geofence</h3>
    371 <p>For best results, the minimium radius of the geofence should be set between 100 - 150 meters.
    372 When Wi-Fi is available location accuracy is usually between 20 - 50 meters. When indoor
    373 location is available, the accuracy range can be as small as 5 meters. Unless you know indoor
    374 location is available inside the geofence, assume that Wi-Fi location accuracy is about
    375 50 meters.</p>
    376 
    377 <p>When Wi-Fi location is not available (for example, when you are driving in rural areas) the
    378 location accuracy degrades. The accuracy range can be as large as several hundred meters to
    379 several kilometers. In cases like this, you should create geofences using a larger radius.</p>
    380 
    381 <h3>Use the dwell transition type to reduce alert spam</h3>
    382 
    383 <p>If you receive a large number of alerts when driving briefly past a geofence, the best way to
    384 reduce the alerts is to use a transition type of <code>
    385 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_DWELL">
    386 GEOFENCE_TRANSITION_DWELL</a></code> instead of <code>
    387 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    388 GEOFENCE_TRANSITION_ENTER</a></code>. This way, the dwelling alert is sent only when the user stops
    389 inside a geofence for a given period of time. You can choose the duration by setting a
    390 <a href="{@docRoot}reference/com/google/android/gms/location/Geofence.Builder.html#setLoiteringDelay(int)">
    391 loitering delay</a>.</p>
    392 
    393 <h3>Re-register geofences only when required</h3>
    394 
    395 <p>Registered geofences are kept in the <code>com.google.process.location</code> process owned by
    396 the <code>com.google.android.gms</code> package.
    397 The app doesnt need to do anything to handle the following events, because the system
    398 restores geofences after these events:</p>
    399 <ul>
    400 <li>Google Play services is upgraded.</li>
    401 <li>Google Play services is killed and restarted by the system due resource restriction.</li>
    402 <li>The location process crashes.</li>
    403 </ul>
    404 <p>The app must re-register geofences if they're still needed after the following events, since
    405 the system cannot recover the geofences in the following cases:</p>
    406 
    407 <ul>
    408 <li>The device is rebooted. The app should listen for the device's boot complete action, and then re-
    409 register the geofences required.</li>
    410 <li>The app is uninstalled and re-installed.</li>
    411 <li>The app's data is cleared.</li>
    412 <li>Google Play services data is cleared.</li>
    413 <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>
    414 alert. This typically happens
    415 after NLP (Android's Network Location Provider) is disabled.</li>
    416 </ul>
    417 
    418 <h2 id="Troubleshooting">Troubleshoot the Geofence Entrance Event</h2>
    419 
    420 <p>If geofences are not being triggered when the device enters a geofence
    421 (the <code><a href="{@docRoot}reference/com/google/android/gms/location/Geofence.html#GEOFENCE_TRANSITION_ENTER">
    422 GEOFENCE_TRANSITION_ENTER</a></code> alert isnt triggered), first ensure that your geofences are
    423 registered properly as described in this guide.</p>
    424 
    425 <p>Here are some possible reasons for alerts not working as expected:</p>
    426 
    427 <ul>
    428 <li><strong>Accurate location is not available inside your geofence or your geofence is too
    429 small.</strong> On most devices, the geofence service uses only network location for geofence
    430 triggering. The service uses this approach because network location consumes much less
    431 power, it takes less time to get discrete locations, and most importantly its available indoors.
    432 Starting with Google Play services 3.2, the geofence service calculates the overlapping ratio of
    433 the location circle and the geofence circle and only generates the entrance alert when the ratio
    434 is at least 85% for a bigger geofence or 75% for a smaller geofence. For an exit alert, the ratio
    435 threshold used is 15% or 25%. Any ratio between these thresholds makes the geofence service mark
    436 the geofence state as <code>INSIDE_LOW_CONFIDENCE</code> or <code>OUTSIDE_LOW_CONFIDENCE</code> and
    437 no alert is sent.</li>
    438 <li><strong>Wi-Fi is turned off on the device.</strong> Having Wi-Fi on can significantly improve
    439 the location accuracy, so if Wi-Fi is turned off, your application might never get geofence alerts
    440 depending on several settings including the radius of the geofence, the device model, or the
    441 Android version. Starting from Android 4.3 (API level 18), we added the capability of Wi-Fi scan
    442 only mode which allows users to disable Wi-Fi but still get good network location. Its good
    443 practice to prompt the user and provide a shortcut for the user to enable Wi-Fi or Wi-Fi scan only
    444 mode if both of them are disabled. Use <a href="{@docRoot}reference/com/google/android/gms/location/SettingsApi">
    445 SettingsApi</a> to ensure that the device's system settings are properly configured for optimal
    446 location detection.</li>
    447 <li><strong>There is no reliable network connectivity inside your geofence.</strong> If there is
    448 no reliable data connection, alerts might not be generated. This is because the geofence service
    449 depends on the network location provider which in turn requires a data connection.</li>
    450 <li><strong>Alerts can be late.</strong> The geofence service does not continuously query for
    451 location, so expect some latency when receiving alerts. Usually the latency is less than 2
    452 minutes, even less when the device has been moving. If the device has been stationary for a
    453 significant period of time, the latency may increase (up to 6 minutes).</li>
    454 </ul>
    455