Home | History | Annotate | Download | only in location
      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">&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>
    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         &#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>
    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     &#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>
    326 public 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>
    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>
    388