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">&lt;manifest&gt;</a></code>
66    element in your app manifest:
67</p>
68<pre>
69&lt;uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/&gt;
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    &lt;application&gt;</a></code> element:
77</p>
78
79<pre>
80&lt;application
81   android:allowBackup=&quot;true&quot;&gt;
82   ...
83   &lt;service android:name=".GeofenceTransitionsIntentService"/&gt;
84&lt;application/&gt;
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