• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Detecting Location on Android Wear
2page.tags="gps"
3
4page.article=true
5@jd:body
6
7<div id="tb-wrapper">
8<div id="tb">
9<h2>In this document</h2>
10<ol class="nolist">
11  <li><a href="#Connect">Connect to Google Play Services</a></li>
12  <li><a href="#Request">Request Location Updates</a></li>
13  <li><a href="#DetectGPS">Detect On-Board GPS</a></li>
14  <li><a href="#Disconnection">Handle Disconnection Events</a></li>
15  <li><a href="#Notify">Handle Location Not Found</a></li>
16  <li><a href="#Synchronize">Synchronize Data</a></li>
17</ol>
18<!-- Required platform, tools, add-ons, devices, knowledge, etc. -->
19<h2>Dependencies and prerequisites</h2>
20<ul>
21  <li>Android 4.3 (API Level 18) or higher on the handset device</li>
22  <li><a href="{@docRoot}google/play-services/index.html">Google Play services</a> 6.1 or higher</li>
23  <li>An Android Wear device</li>
24</ul>
25<h2>See also</h2>
26<ul>
27  <li><a href="{@docRoot}training/location/index.html">Making Your App Location-Aware
28  </a></li>
29</ul>
30</div></div>
31
32<p>Location awareness on wearable devices enables you to create apps that give users a better
33understanding of their geographic position, movement and what's around them. With the small form
34factor and glanceable nature of a wearable device, you can build low-friction apps that record and
35respond to location data.</p>
36
37<p>Some wearable devices include a GPS sensor that can retrieve location data without another
38tethered device. However, when you request location data in a wearable app, you don't have to worry
39about where the location data originates; the system retrieves the location updates using the most
40power-efficient method. Your app should be able to handle loss of location data, in case the wear
41device loses connection with its paired device and does not have a built-in GPS sensor.</p>
42
43<p>This document shows you how to check for on-device location sensors, receive location data, and
44monitor tethered data connections.</p>
45
46<p class="note"><b>Note:</b> The article assumes that you know how to use the Google Play services
47API to retrieve location data. For more information, see <a href="{@docRoot}training/
48location/index.html">Making Your App Location-Aware</a>.</p>
49
50<h2 id="Connect">Connect to Google Play Services</h2>
51
52<p>Location data on wearable devices is obtained though the Google Play services location APIs. You
53use the <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">
54<code>FusedLocationProviderApi</code></a> and its accompanying classes to obtain this data.
55To access location services, create an instance of
56<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">
57<code>GoogleApiClient</code></a>, which is
58the main entry point for any of the Google Play services APIs.
59</p>
60
61<p class="caution"><b>Caution:</b> Do not use the existing <a href="{@docRoot}reference/android/location/package-summary.html">Location</a>
62APIs in the Android framework. The best practice for retrieving location updates is through the
63Google Play services API as outlined in this article.</p>
64
65<p>To connect to Google Play services, configure your app to create an instance of
66<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">
67<code>GoogleApiClient</code></a>:</p>
68
69<ol>
70  <li>Create an activity that specifies an implementation for the interfaces <a
71href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html"
72>{@code ConnectionCallbacks}</a>, <a href="{@docRoot}reference/com/google/android/gms/common/api/
73GoogleApiClient.OnConnectionFailedListener.html">{@code OnConnectionFailedListener}</a>, and <a
74href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code
75LocationListener}</a>.</li>
76  <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, create an instance
77of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>
78GoogleApiClient</code></a> and add the Location service.
79  </li>
80  <li>To gracefully manage the lifecycle of the connection, call  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
81  {@code connect()}</a> in the {@link android.app.Activity#onResume onResume()} method and
82  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#disconnect()">
83  {@code disconnect()}</a> in the {@link android.app.Activity#onPause onPause()} method.
84  </li>
85</ol>
86
87<p>The following code example shows an implementation of an activity that implements the
88<a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">
89{@code LocationListener}</a> interface:</p>
90
91<pre>
92public class WearableMainActivity extends Activity implements
93    GoogleApiClient.ConnectionCallbacks,
94    GoogleApiClient.OnConnectionFailedListener,
95    LocationListener {
96
97    private GoogleApiClient mGoogleApiClient;
98    ...
99
100    &#64;Override
101    protected void onCreate(Bundle savedInstanceState) {
102        super.onCreate(savedInstanceState);
103
104        ...
105        mGoogleApiClient = new GoogleApiClient.Builder(this)
106                .addApi(LocationServices.API)
107                .addApi(Wearable.API)  // used for data layer API
108                .addConnectionCallbacks(this)
109                .addOnConnectionFailedListener(this)
110                .build();
111    }
112
113    &#64;Override
114    protected void onResume() {
115        super.onResume();
116        mGoogleApiClient.connect();
117        ...
118    }
119
120    &#64;Override
121    protected void onPause() {
122        super.onPause();
123        ...
124        mGoogleApiClient.disconnect();
125    }
126}
127</pre>
128
129<p>For more information on connecting to Google Play services, see <a href="{@docRoot}google/auth
130/api-client.html">Accessing Google APIs</a>.</p>
131
132<h2 id="Request">Request Location Updates</h2>
133
134<p>After your app has connected to the Google Play services API, it is ready to start receiving
135location updates. When the system invokes the
136<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">
137<code>onConnected()</code></a> callback for your client, you build the location data request as
138follows:</p>
139
140<ol>
141  <li>Create a <a
142href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html"
143>{@code LocationRequest}</a> object and set any options using methods like <a
144href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)"
145>{@code setPriority()}</a>.
146  </li>
147  <li>Request location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)">
148  <code>requestLocationUpdates()</code></a>.
149  </li>
150  <li>Remove location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)">
151  <code>removeLocationUpdates()</code></a> in the {@link android.app.Activity#onPause
152  onPause()} method.
153  </li>
154</ol>
155
156<p>The following example shows how to retrieve and remove location updates:</p>
157
158<pre>
159&#64;Override
160public void onConnected(Bundle bundle) {
161    LocationRequest locationRequest = LocationRequest.create()
162            .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
163            .setInterval(UPDATE_INTERVAL_MS)
164            .setFastestInterval(FASTEST_INTERVAL_MS);
165
166    LocationServices.FusedLocationApi
167            .requestLocationUpdates(mGoogleApiClient, locationRequest, this)
168            .setResultCallback(new ResultCallback<Status>() {
169
170                &#64;Override
171                public void onResult(Status status) {
172                    if (status.getStatus().isSuccess()) {
173                        if (Log.isLoggable(TAG, Log.DEBUG)) {
174                            Log.d(TAG, "Successfully requested location updates");
175                        }
176                    } else {
177                        Log.e(TAG,
178                                "Failed in requesting location updates, "
179                                        + "status code: "
180                                        + status.getStatusCode()
181                                        + ", message: "
182                                        + status.getStatusMessage());
183                    }
184                }
185            });
186}
187
188&#64;Override
189protected void onPause() {
190    super.onPause();
191    if (mGoogleApiClient.isConnected()) {
192        LocationServices.FusedLocationApi
193             .removeLocationUpdates(mGoogleApiClient, this);
194    }
195    mGoogleApiClient.disconnect();
196}
197
198&#64;Override
199public void onConnectionSuspended(int i) {
200    if (Log.isLoggable(TAG, Log.DEBUG)) {
201        Log.d(TAG, "connection to location client suspended");
202    }
203}
204
205</pre>
206
207<p>Now that you have enabled location updates, the system calls the {@link android.location.LocationListener#onLocationChanged
208onLocationChanged()} method with the updated location at the interval specified in <a
209href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)">
210{@code setInterval()}</a>
211</p>
212
213<h2 id="DetectGPS">Detect On-Board GPS</h2>
214
215<p>Not all wearables have a GPS sensor. If your user goes out for a run and leaves their phone at
216home, your wearable app cannot receive location data through a tethered connection. If the
217wearable device does not have a sensor, you should detect this situation and warn the user that
218location functionality is not available.
219
220<p>To determine whether your Android Wear device has a built-in GPS sensor, use the
221{@link android.content.pm.PackageManager#hasSystemFeature hasSystemFeature()}
222method. The following code detects whether the device has built-in GPS when you start an activity:
223</p>
224
225<pre>
226
227protected void onCreate(Bundle savedInstanceState) {
228    super.onCreate(savedInstanceState);
229
230    setContentView(R.layout.main_activity);
231    if (!hasGps()) {
232        Log.d(TAG, "This hardware doesn't have GPS.");
233        // Fall back to functionality that does not use location or
234        // warn the user that location function is not available.
235    }
236
237    ...
238}
239
240private boolean hasGps() {
241    return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS);
242}
243</pre>
244
245<h2 id="Disconnection">Handle Disconnection Events</h2>
246
247<p>Wearable devices relying on a tethered connection for location data may lose their connections
248abruptly. If your wearable app expects a constant stream of data, you must handle the
249disconnection based upon where that data is interrupted or unavailable. On a wearable device with no
250onboard GPS sensor, loss of location data occurs when the device loses its tethered data connection.
251</p>
252
253<p>In cases where your app depends on a tethered data connection for location data and the wear
254device does not have a GPS sensor, you should detect the loss of that connection, warn the user, and
255gracefully degrade the functionality of your app.</p>
256
257<p>To detect the loss of a tethered data connection:</p>
258
259<ol>
260  <li>Extend a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
261  <code>WearableListenerService</code></a> that lets you listen for important data layer events.
262  </li>
263  <li>Declare an intent filter in your Android manifest to notify the system about your
264  <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>
265  WearableListenerService</code></a>.
266  This filter allows the system to bind your service as needed.
267<pre>
268&lt;service android:name=".NodeListenerService"&gt;
269    &lt;intent-filter&gt;
270        &lt;action android:name="com.google.android.gms.wearable.BIND_LISTENER" /&gt;
271    &lt;/intent-filter&gt;
272&lt;/service>
273</pre>
274  </li>
275  <li>Implement the <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)">
276  <code>onPeerDisconnected()</code></a> method and handle cases of whether or not the device has
277  built-in
278  GPS.
279<pre>
280public class NodeListenerService extends WearableListenerService {
281
282    private static final String TAG = "NodeListenerService";
283
284    &#64;Override
285    public void onPeerDisconnected(Node peer) {
286        Log.d(TAG, "You have been disconnected.");
287        if(!hasGPS()) {
288            // Notify user to bring tethered handset
289            // Fall back to functionality that does not use location
290        }
291    }
292    ...
293}
294</pre>
295  </li>
296</ol>
297
298For more information, read the <a href="{@docRoot}training/wearables/data-layer/events.html#Listen">
299Listen for Data Layer Events</a> guide.
300
301<h2 id="Notify">Handle Location Not Found</h2>
302
303<p>When the GPS signal is lost, you can still retrieve the last known location using
304<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">
305<code>getLastLocation()</code></a>. This method can be helpful in situations where you are unable to
306get a GPS fix, or when your wearable doesn't have built-in GPS and loses its connection with the
307phone.</p>
308
309<p>The following code uses <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">
310<code>getLastLocation()</code></a> to retrieve the last known location if available:
311</p>
312
313<pre>
314Location location = LocationServices.FusedLocationApi
315                .getLastLocation(mGoogleApiClient);
316</pre>
317
318<h2 id="Synchronize">Synchronize Data</h2>
319
320<p>If your wearable app records data using the built-in GPS, you may want to synchronize
321the location data with the handset. With the {@link android.location.LocationListener}, you
322implement the {@link android.location.LocationListener#onLocationChanged onLocationChanged()}
323method to detect and record the location as it changes.
324
325<p>The following code for wearable apps detects when the location changes and uses the data layer
326API to store the data for later retrieval by your phone app:</p>
327
328<pre>
329&#64;Override
330public void onLocationChanged(Location location) {
331    ...
332    addLocationEntry(location.getLatitude(), location.getLongitude());
333
334}
335
336private void addLocationEntry(double latitude, double longitude) {
337    if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) {
338        return;
339    }
340
341    mCalendar.setTimeInMillis(System.currentTimeMillis());
342
343    // Set the path of the data map
344    String path = Constants.PATH + "/" + mCalendar.getTimeInMillis();
345    PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path);
346
347    // Set the location values in the data map
348    putDataMapRequest.getDataMap()
349            .putDouble(Constants.KEY_LATITUDE, latitude);
350    putDataMapRequest.getDataMap()
351            .putDouble(Constants.KEY_LONGITUDE, longitude);
352    putDataMapRequest.getDataMap()
353            .putLong(Constants.KEY_TIME, mCalendar.getTimeInMillis());
354
355    // Prepare the data map for the request
356    PutDataRequest request = putDataMapRequest.asPutDataRequest();
357
358    // Request the system to create the data item
359    Wearable.DataApi.putDataItem(mGoogleApiClient, request)
360            .setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
361                &#64;Override
362                public void onResult(DataApi.DataItemResult dataItemResult) {
363                    if (!dataItemResult.getStatus().isSuccess()) {
364                        Log.e(TAG, "Failed to set the data, "
365                                + "status: " + dataItemResult.getStatus()
366                                .getStatusCode());
367                    }
368                }
369            });
370}
371</pre>
372
373<p>For more information on how to use the Data Layer API, see the <a href="{@docRoot}training/
374wearables/data-layer/index.html">Sending and Syncing Data</a>
375guide.</p>
376