Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2f39dd77 authored by Sarah Maddox's avatar Sarah Maddox Committed by Android Git Automerger
Browse files

am 91a41ac1: am 99c5ac9e: am 48f9c8e4: am aaa37da8: am a158abe4: Merge "docs:...

am 91a41ac1: am 99c5ac9e: am 48f9c8e4: am aaa37da8: am a158abe4: Merge "docs: Updates lesson 1 of location API training: Get last-known location." into lmp-docs automerge: 8f0f627e

* commit '91a41ac1':
  docs: Updates lesson 1 of location API training: Get last-known location.
parents 87e74132 91a41ac1
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -67,9 +67,10 @@ startpage=true
<h2>Lessons</h2>
<dl>
  <dt>
    <b><a href="retrieve-current.html">Retrieving the Current Location</a></b>
    <b><a href="retrieve-current.html">Getting the Last Known Location</a></b>
  </dt> <dd>
     Learn how to retrieve the user's current location.
     Learn how to retrieve the last known location of an Android device, which
     is usually equivalent to the user's current location.
  </dd> <dt>
    <b><a href="receive-location-updates.html">Receiving Location
    Updates</a></b>
+140 −364
Original line number Diff line number Diff line
page.title=Retrieving the Current Location
page.title=Getting the Last Known Location
trainingnavtop=true
@jd:body

<div id="tb-wrapper">
  <div id="tb">

<h2>This lesson teaches you to</h2>
    <h2>This lesson teaches you how to</h2>
    <ol>
    <li><a href="#AppPermissions">Specify App Permissions</a></li>
    <li><a href="#CheckServices">Check for Google Play services</a></li>
    <li><a href="#DefineCallbacks">Define Location Services Callbacks</a></li>
    <li><a href="#ConnectClient">Connect the Location Client</a></li>
    <li><a href="#GetLocation">Get the Current Location</a></li>
      <li><a href="#setup">Set Up Google Play Services</a></li>
      <li><a href="#permissions">Specify App Permissions</a></li>
      <li><a href="#play-services">Connect to Google Play Services</a></li>
      <li><a href="#last-known">Get the Last Known Location</a></li>
    </ol>

    <h2>You should also read</h2>
    <ul>
      <li>
        <a href="{@docRoot}google/play-services/setup.html">Setup Google Play Services SDK</a>
        <a href="{@docRoot}google/play-services/setup.html">Setting up Google Play
        Services</a>
      </li>
    </ul>

    <h2>Try it out</h2>

<div class="download-box">
  <a href="http://developer.android.com/shareables/training/LocationUpdates.zip" class="button">Download the sample</a>
  <p class="filename">LocationUpdates.zip</p>
</div>

    <ul>
      <li>
        <a href="https://github.com/googlesamples/android-play-location/tree/master/BasicLocationSample" class="external-link">BasicLocationSample</a>
      </li>
    </ul>
  </div>
</div>

<p>
    Location Services automatically maintains the user's current location, so all your app has to do
    is retrieve it as needed. The location's accuracy is based on the location permissions you've
    requested and location sensors that are currently active for the device.
<p>
    Location Services sends the current location to your app through a location client, which is
    an instance of the Location Services class
<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html">LocationClient</a></code>.
    All requests for location information go through this client.
</p>
<p class="note">
    <strong>Note:</strong> Before you start the lesson, be sure that your development environment
    and test device are set up correctly. To learn more about this, read the
    <a href="{@docRoot}google/play-services/setup.html">Setup</a> section in the Google Play
    services guide.
</p>
<!--
    Specify App Permissions
 -->
<h2 id="AppPermissions">Specify App Permissions</h2>
<p>
    Apps that use Location Services must request location permissions. Android has two location
    permissions: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
    and {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}. The
    permission you choose controls the accuracy of the current location. If you request only coarse
    location permission, Location Services obfuscates the returned location to an accuracy
    that's roughly equivalent to a city block.
</p>
<p>
    Requesting {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} implies
    a request for {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}.
</p>
<p>
    For example, to add {@link android.Manifest.permission#ACCESS_COARSE_LOCATION
    ACCESS_COARSE_LOCATION}, insert the following as a child element of the
    <code><a href="{@docRoot}guide/topics/manifest/manifest-element.html">&lt;manifest&gt;</a></code>
    element:
</p>
<p>Using the Google Play services location APIs, your app can request the last
  known location of the user's device. In most cases, you are interested in the
  user's current location, which is usually equivalent to the last known
  location of the device.</p>

<p>Specifically, use the
  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html">fused
  location provider</a> to retrieve the device's last known location. The fused
  location provider is one of the location APIs in Google Play services. It
  manages the underlying location technology and provides a simple API so that
  you can specify requirements at a high level, like high accuracy or low power.
  It also optimizes the device's use of battery power.</p>

<p>This lesson shows you how to make a single request for the location of a
  device using the
  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>
  method in the fused location provider.

<h2 id="setup">Set Up Google Play Services</h2>

<p>To access the fused location provider, your app's development project must
  include Google Play services. Download and install the Google Play services
  component via the <a href="{@docRoot}tools/help/sdk-manager.html">SDK
  Manager</a> and add the library to your project. For details, see the guide to
  <a href="{@docRoot}google/play-services/setup.html">Setting Up Google Play
  Services</a>.</p>

<h2 id="permissions">Specify App Permissions</h2>

<p>Apps that use location services must request location permissions. Android
  offers two location permissions:
  {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION}
  and
  {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION}.
  The permission you choose determines the accuracy of the location returned by
  the API. If you specify
  {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION},
  the API returns a location with an accuracy approximately equivalent to a city
  block.</p>

<p>This lesson requires only coarse location. Request this permission with the
  {@code uses-permission} element in your app manifest, as shown in the
  following example:

<pre>
&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.google.android.gms.location.sample.basiclocationsample" &gt;
  
  &lt;uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/&gt;
&lt;/manifest&gt;
</pre>
<!--
    Check for Google Play Services
 -->
<h2 id="CheckServices">Check for Google Play Services</h2>
<p>
    Location Services is part of the Google Play services APK. Since it's hard to anticipate the
    state of the user's device, you should always check that the APK is installed before you attempt
    to connect to Location Services. To check that the APK is installed, call
<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#isGooglePlayServicesAvailable(android.content.Context)">GooglePlayServicesUtil.isGooglePlayServicesAvailable()</a></code>,
    which returns one of the
    integer result codes listed in the reference documentation for
<code><a href="{@docRoot}reference/com/google/android/gms/common/ConnectionResult.html">ConnectionResult</a></code>.
    If you encounter an error, call
<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesUtil.html#getErrorDialog(int, android.app.Activity, int)">GooglePlayServicesUtil.getErrorDialog()</a></code>
    to retrieve localized dialog that prompts users to take the correct action, then display
    the dialog in a {@link android.support.v4.app.DialogFragment}. The dialog may allow the
    user to correct the problem, in which case Google Play services may send a result back to your
    activity. To handle this result, override the method
    {@link android.support.v4.app.FragmentActivity#onActivityResult onActivityResult()}.
</p>
<p>
    Since you usually need to check for Google Play services in more than one place in your code,
    define a method that encapsulates the check, then call the method before each connection
    attempt. The following snippet contains all of the code required to check for Google
    Play services:
</p>
<pre>
public class MainActivity extends FragmentActivity {
    ...
    // Global constants
    /*
     * Define a request code to send to Google Play services
     * This code is returned in Activity.onActivityResult
     */
    private final static int
            CONNECTION_FAILURE_RESOLUTION_REQUEST = 9000;
    ...
    // Define a DialogFragment that displays the error dialog
    public static class ErrorDialogFragment extends DialogFragment {
        // Global field to contain the error dialog
        private Dialog mDialog;
        // Default constructor. Sets the dialog field to null
        public ErrorDialogFragment() {
            super();
            mDialog = null;
        }
        // Set the dialog to display
        public void setDialog(Dialog dialog) {
            mDialog = dialog;
        }
        // Return a Dialog to the DialogFragment.
        &#64;Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            return mDialog;
        }
    }
    ...
    /*
     * Handle results returned to the FragmentActivity
     * by Google Play services
     */
    &#64;Override
    protected void onActivityResult(
            int requestCode, int resultCode, Intent data) {
        // Decide what to do based on the original request code
        switch (requestCode) {
            ...
            case CONNECTION_FAILURE_RESOLUTION_REQUEST :
            /*
             * If the result code is Activity.RESULT_OK, try
             * to connect again
             */
                switch (resultCode) {
                    case Activity.RESULT_OK :
                    /*
                     * Try the request again
                     */
                    ...
                    break;
                }
            ...
        }
     }
    ...
    private boolean servicesConnected() {
        // Check that Google Play services is available
        int resultCode =
                GooglePlayServicesUtil.
                        isGooglePlayServicesAvailable(this);
        // If Google Play services is available
        if (ConnectionResult.SUCCESS == resultCode) {
            // In debug mode, log the status
            Log.d("Location Updates",
                    "Google Play services is available.");
            // Continue
            return true;
        // Google Play services was not available for some reason.
        // resultCode holds the error code.
        } else {
            // Get the error dialog from Google Play services
            Dialog errorDialog = GooglePlayServicesUtil.getErrorDialog(
                    resultCode,
                    this,
                    CONNECTION_FAILURE_RESOLUTION_REQUEST);

            // If Google Play services can provide an error dialog
            if (errorDialog != null) {
                // Create a new DialogFragment for the error dialog
                ErrorDialogFragment errorFragment =
                        new ErrorDialogFragment();
                // Set the dialog in the DialogFragment
                errorFragment.setDialog(errorDialog);
                // Show the error dialog in the DialogFragment
                errorFragment.show(getSupportFragmentManager(),
                        "Location Updates");
            }
        }
    }
    ...
}
</pre>
<p>
    Snippets in the following sections call this method to verify that Google Play services is
    available.
</p>
<!--
    Define Location Services Callbacks
 -->
<h2 id="DefineCallbacks">Define Location Services Callbacks</h2>
<p>
    To get the current location, create a location client, connect it
    to Location Services, and then call its
<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>
    method. The return value  is the best, most recent location, based on the permissions your
    app requested and the currently-enabled location sensors.
<p>
<p>
    Before you create the location client, implement the interfaces that Location Services uses to
    communicate with your app:
</p>
<dl>
    <dt>
<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.ConnectionCallbacks.html">ConnectionCallbacks</a></code>
    </dt>
    <dd>
        Specifies methods that Location Services calls when a location client is connected or
        disconnected.
    </dd>
    <dt>
<code><a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesClient.OnConnectionFailedListener.html">OnConnectionFailedListener</a></code>
    </dt>
    <dd>
        Specifies a method that Location Services calls if an error occurs while attempting to
        connect the location client. This method uses the previously-defined {@code showErrorDialog}
        method to display an error dialog that attempts to fix the problem using Google Play
        services.
    </dd>
</dl>
<p>
    The following snippet shows how to specify the interfaces and define the methods:
<h2 id="play-services">Connect to Google Play Services</h2>

<p>To connect to the API, you need to create an instance of the
  Google Play services API client. For details about using the client, see
  the guide to
  <a href="{@docRoot}google/auth/api-client.html#Starting">Accessing Google
  APIs</a>.
</p>
<pre>
public class MainActivity extends FragmentActivity implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener {
    ...
    /*
     * Called by Location Services when the request to connect the
     * client finishes successfully. At this point, you can
     * request the current location or start periodic updates
     */
    &#64;Override
    public void onConnected(Bundle dataBundle) {
        // Display the connection status
        Toast.makeText(this, "Connected", Toast.LENGTH_SHORT).show();

    }
    ...
    /*
     * Called by Location Services if the connection to the
     * location client drops because of an error.
     */
    &#64;Override
    public void onDisconnected() {
        // Display the connection status
        Toast.makeText(this, "Disconnected. Please re-connect.",
                Toast.LENGTH_SHORT).show();
    }
    ...
    /*
     * Called by Location Services if the attempt to
     * Location Services fails.
     */
    &#64;Override
    public void onConnectionFailed(ConnectionResult connectionResult) {
        /*
         * Google Play services can resolve some errors it detects.
         * If the error has a resolution, try sending an Intent to
         * start a Google Play services activity that can resolve
         * error.
         */
        if (connectionResult.hasResolution()) {
            try {
                // Start an Activity that tries to resolve the error
                connectionResult.startResolutionForResult(
                        this,
                        CONNECTION_FAILURE_RESOLUTION_REQUEST);
                /*
                 * Thrown if Google Play services canceled the original
                 * PendingIntent
                 */
            } catch (IntentSender.SendIntentException e) {
                // Log the error
                e.printStackTrace();
            }
        } else {
            /*
             * If no resolution is available, display a dialog to the
             * user with the error.
             */
            showErrorDialog(connectionResult.getErrorCode());
        }
    }
    ...
<p>In your activity's {@link android.app.Activity#onCreate onCreate()} method,
  create an instance of Google API Client using
  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.Builder.html">{@code GoogleApiClient.Builder}</a>.
  Use the builder to add the
  <a href="{@docRoot}reference/com/google/android/gms/location/LocationServices.html">{@code LocationServices}</a>
  API.</p>

<p>The sample app defines a {@code buildGoogleApiClient()} method, called from
  the activity's {@link android.app.Activity#onCreate onCreate()} method,
  which includes the following code.</p>

<pre>
protected synchronized void buildGoogleApiClient() {
    mGoogleApiClient = new GoogleApiClient.Builder(this)
        .addConnectionCallbacks(this)
        .addOnConnectionFailedListener(this)
        .addApi(LocationServices.API)
        .build();
}
</pre>
<!--
    Connect the Location Client
 -->
<h2 id="ConnectClient">Connect the Location Client</h2>
<p>
    Now that the callback methods are in place, create the location client and connect it to
    Location Services.
</p>
<p>
    You should create the location client in {@link android.support.v4.app.FragmentActivity#onCreate
    onCreate()}, then connect it in
    {@link android.support.v4.app.FragmentActivity#onStart onStart()}, so that Location Services
    maintains the current location while your activity is fully visible. Disconnect the client in
    {@link android.support.v4.app.FragmentActivity#onStop onStop()}, so that when your app is not
    visible, Location Services is not maintaining the current location. Following this pattern of
    connection and disconnection helps save battery power. For example:
</p>
<p class="note">
    <strong>Note:</strong> The current location is only maintained while a location client is
    connected to Location Service. Assuming that no other apps are connected to Location Services,
    if you disconnect the client and then sometime later call
<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>,
    the result may be out of date.
</p>

<h2 id="last-known">Get the Last Known Location</h2>

<p>Once you have connected to Google Play services and the location services
  API, you can get the last known location of a user's device. When your app is
  connected to these you can use the fused location provider's
  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>
  method to retrieve the device location. The precision of the location returned
  by this call is determined by the permission setting you put in your app
  manifest, as described in the <a href="#permissions">Specify App
  Permissions</a> section of this document.</p>

<p>To request the last known location, call the
  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>
  method, passing it your instance of the
  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html">{@code GoogleApiClient}</a>
  object. Do this in the
  <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)">{@code onConnected()}</a>
  callback provided by Google API Client, which is called when the client is
  ready. The following code sample illustrates the request and a simple
  handling of the response:</p>

<pre>
public class MainActivity extends FragmentActivity implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener {
    ...
    &#64;Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        /*
         * Create a new location client, using the enclosing class to
         * handle callbacks.
         */
        mLocationClient = new LocationClient(this, this, this);
        ...
    }
    ...
    /*
     * Called when the Activity becomes visible.
     */
    &#64;Override
    protected void onStart() {
        super.onStart();
        // Connect the client.
        mLocationClient.connect();
    }
public class MainActivity extends ActionBarActivity implements
        ConnectionCallbacks, OnConnectionFailedListener {
    ...
    /*
     * Called when the Activity is no longer visible.
     */
    &#64;Override
    protected void onStop() {
        // Disconnecting the client invalidates it.
        mLocationClient.disconnect();
        super.onStop();
    public void onConnected(Bundle connectionHint) {
        mLastLocation = LocationServices.FusedLocationApi.getLastLocation(
                mGoogleApiClient);
        if (mLastLocation != null) {
            mLatitudeText.setText(String.valueOf(mLastLocation.getLatitude()));
            mLongitudeText.setText(String.valueOf(mLastLocation.getLongitude()));
        }
    ...
    }
</pre>
<!--
    Get the Current Location
 -->
<h2 id="GetLocation">Get the Current Location</h2>
<p>
    To get the current location, call
<code><a href="{@docRoot}reference/com/google/android/gms/location/LocationClient.html#getLastLocation()">getLastLocation()</a></code>.
    For example:
</p>
<pre>
public class MainActivity extends FragmentActivity implements
        GooglePlayServicesClient.ConnectionCallbacks,
        GooglePlayServicesClient.OnConnectionFailedListener {
    ...
    // Global variable to hold the current location
    Location mCurrentLocation;
    ...
    mCurrentLocation = mLocationClient.getLastLocation();
    ...
}
</pre>
<p>
    The next lesson, <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
    you how to receive periodic location updates from Location Services.
</p>

<p>The
  <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)">{@code getLastLocation()}</a>
  method returns a
  <a href="{@docRoot}reference/android/location/Location.html">{@code Location}</a>
  object from which you can retrieve the latitude and longitude coordinates of a
  geographic location. The location object returned may be null in rare cases
  when the location is not available.</p>

<p>The next lesson,
  <a href="receive-location-updates.html">Receiving Location Updates</a>, shows
  you how to receive periodic location updates.</p>
+1 −1
Original line number Diff line number Diff line
@@ -694,7 +694,7 @@ include the action bar on devices running Android 2.1 or higher."
        <ul>
          <li>
            <a href="<?cs var:toroot ?>training/location/retrieve-current.html">
            Retrieving the Current Location
            Getting the Last Known Location
            </a>
          </li>
          <li>