| Joe Malin | 3ddba7e | 2013-03-04 10:33:30 -0800 | [diff] [blame] | 1 | page.title=Retrieving the Current Location |
| 2 | trainingnavtop=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"><manifest></a></code> |
| 69 | element: |
| 70 | </p> |
| 71 | <pre> |
| 72 | <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> |
| 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> |
| 101 | public 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 | @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 | @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> |
| 237 | public 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 | @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 | @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 | @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> |
| 326 | public class MainActivity extends FragmentActivity implements |
| 327 | GooglePlayServicesClient.ConnectionCallbacks, |
| 328 | GooglePlayServicesClient.OnConnectionFailedListener { |
| 329 | ... |
| 330 | @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 | @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 | @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> |
| 373 | public 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> |