blob: 99e475f8747a611815be58a02e973551066d291c [file] [log] [blame]
Joe Malin3ddba7e2013-03-04 10:33:30 -08001page.title=Retrieving the Current Location
2trainingnavtop=true
3@jd:body
4<div id="tb-wrapper">
5<div id="tb">
6
7<h2>This lesson teaches you to</h2>
8<ol>
9 <li><a href="#AppPermissions">Specify App Permissions</a></li>
10 <li><a href="#CheckServices">Check for Google Play services</a></li>
11 <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li>
12 <li><a href="#ConnectClient">Connect the Location Client</a></li>
13 <li><a href="#GetLocation">Get the Current Location</a></li>
14</ol>
15
16<h2>You should also read</h2>
17<ul>
18 <li>
19 <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
20 </li>
21</ul>
22
23<h2>Try it out</h2>
24
25<div class="download-box">
26 <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample</a>
27 <p class="filename">LocationUpdates.zip</p>
28</div>
29
30</div>
31</div>
32
33<p>
34 Location Services automatically maintains the user's current location, so all your app has to do
35 is retrieve it as needed. The location's accuracy is based on the location permissions you've
36 requested and location sensors that are currently active for the device.
37<p>
38 Location Services sends the current location to your app through a location client, which is
39 an instance of the Location Services class
40<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">LocationClient</a></code>.
41 All requests for location information go through this client.
42</p>
43<p class="note">
44 <strong>Note:</strong> Before you start the lesson, be sure that your development environment
45 and test device are set up correctly. To learn more about this, read the
46 <a href="{@docRoot}google/play-services/setup.html">Setup</a> section in the Google Play
47 services guide.
48</p>
49<!--
50 Specify App Permissions
51 -->
52<h2 id="AppPermissions">Specify App Permissions</h2>
53<p>
54 Apps that use Location Services must request location permissions. Android has two location
55 permissions: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
56 and {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. The
57 permission you choose controls the accuracy of the current location. If you request only coarse
58 location permission, Location Services obfuscates the returned location to an accuracy
59 that's roughly equivalent to a city block.
60</p>
61<p>
62 Requesting {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} implies
63 a request for {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}.
64</p>
65<p>
66 For example, to add {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
67 ACCESS_COARSE_LOCATION}, insert the following as a child element of the
68 <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
69 element:
70</p>
71<pre>
72&lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/&gt;
73</pre>
74<!--
75 Check for Google Play Services
76 -->
77<h2 id="CheckServices">Check for Google Play Services</h2>
78<p>
79 Location Services is part of the Google Play services APK. Since it's hard to anticipate the
80 state of the user's device, you should always check that the APK is installed before you attempt
81 to connect to Location Services. To check that the APK is installed, call
82<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>,
83 which returns one of the
84 integer result codes listed in the reference documentation for
85<code><a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a></code>.
86 If you encounter an error, call
87<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code>
88 to retrieve localized dialog that prompts users to take the correct action, then display
89 the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the
90 user to correct the problem, in which case Google Play services may send a result back to your
91 activity. To handle this result, override the method
92 {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}.
93</p>
94<p>
95 Since you usually need to check for Google Play services in more than one place in your code,
96 define a method that encapsulates the check, then call the method before each connection
97 attempt. The following snippet contains all of the code required to check for Google
98 Play services:
99</p>
100<pre>
101public class MainActivity extends FragmentActivity {
102 ...
103 // Global constants
104 /*
105 * Define a request code to send to Google Play services
106 * This code is returned in Activity.onActivityResult
107 */
108 private final static int
109 CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
110 ...
111 // Define a DialogFragment that displays the error dialog
112 public static class ErrorDialogFragment extends DialogFragment {
113 // Global field to contain the error dialog
114 private Dialog mDialog;
115 // Default constructor. Sets the dialog field to null
116 public ErrorDialogFragment() {
117 super();
118 mDialog = null;
119 }
120 // Set the dialog to display
121 public void setDialog(Dialog dialog) {
122 mDialog = dialog;
123 }
124 // Return a Dialog to the DialogFragment.
125 &#64;Override
126 public Dialog onCreateDialog(Bundle savedInstanceState) {
127 return mDialog;
128 }
129 }
130 ...
131 /*
132 * Handle results returned to the FragmentActivity
133 * by Google Play services
134 */
135 &#64;Override
136 protected void onActivityResult(
137 int requestCode, int resultCode, Intent data) {
138 // Decide what to do based on the original request code
139 switch (requestCode) {
140 ...
141 case CONNECTION_FAILURE_RESOLUTION_REQUEST :
142 /*
143 * If the result code is Activity.RESULT_OK, try
144 * to connect again
145 */
146 switch (resultCode) {
147 case Activity.RESULT_OK :
148 /*
149 * Try the request again
150 */
151 ...
152 break;
153 }
154 ...
155 }
156 }
157 ...
158 private boolean servicesConnected() {
159 // Check that Google Play services is available
160 int resultCode =
161 GooglePlayServicesUtil.
162 isGooglePlayServicesAvailable(this);
163 // If Google Play services is available
164 if (ConnectionResult.SUCCESS == resultCode) {
165 // In debug mode, log the status
166 Log.d("Location Updates",
167 "Google Play services is available.");
168 // Continue
169 return true;
170 // Google Play services was not available for some reason
171 } else {
172 // Get the error code
173 int errorCode = connectionResult.getErrorCode();
174 // Get the error dialog from Google Play services
175 Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
176 errorCode,
177 this,
178 CONNECTION_FAILURE_RESOLUTION_REQUEST);
179
180 // If Google Play services can provide an error dialog
181 if (errorDialog != null) {
182 // Create a new DialogFragment for the error dialog
183 ErrorDialogFragment errorFragment =
184 new ErrorDialogFragment();
185 // Set the dialog in the DialogFragment
186 errorFragment.setDialog(errorDialog);
187 // Show the error dialog in the DialogFragment
188 errorFragment.show(getSupportFragmentManager(),
189 "Location Updates");
190 }
191 }
192 }
193 ...
194}
195</pre>
196<p>
197 Snippets in the following sections call this method to verify that Google Play services is
198 available.
199</p>
200<!--
201 Define Location Services Callbacks
202 -->
203<h2 id="DefineCallbacks">Define Location Services Callbacks</h2>
204<p>
205 To get the current location, create a location client, connect it
206 to Location Services, and then call its
207<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>
208 method. The return value is the best, most recent location, based on the permissions your
209 app requested and the currently-enabled location sensors.
210<p>
211<p>
212 Before you create the location client, implement the interfaces that Location Services uses to
213 communicate with your app:
214</p>
215<dl>
216 <dt>
217<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code>
218 </dt>
219 <dd>
220 Specifies methods that Location Services calls when a location client is connected or
221 disconnected.
222 </dd>
223 <dt>
224<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code>
225 </dt>
226 <dd>
227 Specifies a method that Location Services calls if an error occurs while attempting to
228 connect the location client. This method uses the previously-defined {@code showErrorDialog}
229 method to display an error dialog that attempts to fix the problem using Google Play
230 services.
231 </dd>
232</dl>
233<p>
234 The following snippet shows how to specify the interfaces and define the methods:
235</p>
236<pre>
237public class MainActivity extends FragmentActivity implements
238 GooglePlayServicesClient.ConnectionCallbacks,
239 GooglePlayServicesClient.OnConnectionFailedListener {
240 ...
241 /*
242 * Called by Location Services when the request to connect the
243 * client finishes successfully. At this point, you can
244 * request the current location or start periodic updates
245 */
246 &#64;Override
247 public void onConnected(Bundle dataBundle) {
248 // Display the connection status
249 Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();
250
251 }
252 ...
253 /*
254 * Called by Location Services if the connection to the
255 * location client drops because of an error.
256 */
257 &#64;Override
258 public void onDisconnected() {
259 // Display the connection status
260 Toast.makeText(this, "Disconnected. Please re-connect.",
261 Toast.LENGTH_SHORT).show();
262 }
263 ...
264 /*
265 * Called by Location Services if the attempt to
266 * Location Services fails.
267 */
268 &#64;Override
269 public void onConnectionFailed(ConnectionResult connectionResult) {
270 /*
271 * Google Play services can resolve some errors it detects.
272 * If the error has a resolution, try sending an Intent to
273 * start a Google Play services activity that can resolve
274 * error.
275 */
276 if (connectionResult.hasResolution()) {
277 try {
278 // Start an Activity that tries to resolve the error
279 connectionResult.startResolutionForResult(
280 this,
281 CONNECTION_FAILURE_RESOLUTION_REQUEST);
282 /*
283 * Thrown if Google Play services canceled the original
284 * PendingIntent
285 */
286 } catch (IntentSender.SendIntentException e) {
287 // Log the error
288 e.printStackTrace();
289 }
290 } else {
291 /*
292 * If no resolution is available, display a dialog to the
293 * user with the error.
294 */
295 showErrorDialog(connectionResult.getErrorCode());
296 }
297 }
298 ...
299}
300</pre>
301<!--
302 Connect the Location Client
303 -->
304<h2 id="ConnectClient">Connect the Location Client</h2>
305<p>
306 Now that the callback methods are in place, create the location client and connect it to
307 Location Services.
308</p>
309<p>
310 You should create the location client in {@link android.support.v4.app.FragmentActivity#onCreate
311 onCreate()}, then connect it in
312 {@link android.support.v4.app.FragmentActivity#onStart onStart()}, so that Location Services
313 maintains the current location while your activity is fully visible. Disconnect the client in
314 {@link android.support.v4.app.FragmentActivity#onStop onStop()}, so that when your app is not
315 visible, Location Services is not maintaining the current location. Following this pattern of
316 connection and disconnection helps save battery power. For example:
317</p>
318<p class="note">
319 <strong>Note:</strong> The current location is only maintained while a location client is
320 connected to Location Service. Assuming that no other apps are connected to Location Services,
321 if you disconnect the client and then sometime later call
322<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>,
323 the result may be out of date.
324</p>
325<pre>
326public class MainActivity extends FragmentActivity implements
327 GooglePlayServicesClient.ConnectionCallbacks,
328 GooglePlayServicesClient.OnConnectionFailedListener {
329 ...
330 &#64;Override
331 protected void onCreate(Bundle savedInstanceState) {
332 ...
333 /*
334 * Create a new location client, using the enclosing class to
335 * handle callbacks.
336 */
337 mLocationClient = new LocationClient(this, this, this);
338 ...
339 }
340 ...
341 /*
342 * Called when the Activity becomes visible.
343 */
344 &#64;Override
345 protected void onStart() {
346 super.onStart();
347 // Connect the client.
348 mLocationClient.connect();
349 }
350 ...
351 /*
352 * Called when the Activity is no longer visible.
353 */
354 &#64;Override
355 protected void onStop() {
356 // Disconnecting the client invalidates it.
357 mLocationClient.disconnect();
358 super.onStop();
359 }
360 ...
361}
362</pre>
363<!--
364 Get the Current Location
365 -->
366<h2 id="GetLocation">Get the Current Location</h2>
367<p>
368 To get the current location, call
369<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>.
370 For example:
371</p>
372<pre>
373public class MainActivity extends FragmentActivity implements
374 GooglePlayServicesClient.ConnectionCallbacks,
375 GooglePlayServicesClient.OnConnectionFailedListener {
376 ...
377 // Global variable to hold the current location
378 Location mCurrentLocation;
379 ...
380 mCurrentLocation = mLocationClient.getLastLocation();
381 ...
382}
383</pre>
384<p>
385 The next lesson, <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
386 you how to receive periodic location updates from Location Services.
387</p>