CHAPTER ELEVEN: Using the GPS and Location Services

Chapter opener image: © Fon_nongkran/Shutterstock

Introduction

Many apps today use the location services of the Android device. One such app is Uber, which people use to find a car to go somewhere for a fee. The app uses the device’s Global Positioning System (GPS) to locate where we are and find registered car drivers who are nearby. It uses satellites to provide location and time information.

11.1 Accessing Google Play Services, GPS App, Version 0

In this app, we intend to retrieve the location of the device, ask the user for a destination, and calculate the distance and time to destination. In order for the app to retrieve the location of the device using its GPS, it needs to access Google Play services. We use an Empty Activity template for this app. In Version 0 of this app, we show how we can check if a device can access Google Play services. We need to do the following:

  • ▸ Edit the build.gradle file in order to include Google Play services in the compilation process.

  • ▸ Edit the MainActivity class in order to access Google Play services.

EXAMPLE 11.1 shows the build.gradle (Module: app) file. We edit it in order to make the Google Play services libraries available to the app (note that there are two build.gradle files). The only addition is at line 26: we include the appropriate version of the Google Play services libraries. At the time of this writing, it is 9.4.0.

EXAMPLE 11.1 The build.gradle (Module: app) file

After editing the build.gradle file, we should click on the Sync Project with Gradle Files icon on the tool bar, as shown on FIGURE 11.1.

Inside the MainActivity class, we do the following:

  • ▸ Try to access Google Play services from the device.

  • ▸ If we cannot and the issue can be resolved, we try to resolve it. Otherwise, we exit the app.

  • ▸ Retrieve the current location and display it.

FIGURE 11.1 The Sync Project with Gradle Files icon

TABLE 11.1 Selected methods of the GoogleApiClient.Builder class

Method Description
GoogleApiClient.Builder( Context context ) Constructs a GoogleApiClient object.
GoogleApiClient.Builder addConnectionCallbacks( GoogleApiClient. ConnectionCallbacks listener ) Registers listener to receive connection events. Returns this GoogleApiClient.Builder reference so method calls can be chained.
GoogleApiClient.Builder addOnConnectionFailedListener( GoogleApiClient.ConnectionFailedListener listener ) Registers listener to receive failed connection events. Returns this GoogleApiClient.Builder reference so method calls can be chained.
GoogleApiClient.Builder addApi( API<? extends Api.ApiOptions.NotRequiredOptions> api ) Specifies api as an API requested by this app. We should use the API constant of LocationServices. Returns this GoogleApiClient.Builder reference so method calls can be chained.
GoogleApiClient build( ) Builds and returns a GoogleApiClient object for communicating with the Google APIs.

The GoogleApiClient abstract class, from the com.google.android.gms.common.api package, is the main entry point for Google Play services. It includes the functionality to establish a connection to Google Play services and manage it. Since it is abstract, we cannot instantiate an object of that class using the new operator. It includes a static inner class, Builder, which includes methods to specify attributes of a GoogleApiClient and a build method to create one. TABLE 11.1 lists some of these methods. These methods, except the build method, return the GoogleApiClient.Builder reference that calls them, so that method calls can be chained. The build method returns a GoogleApiClient reference.

The GoogleApiClient class includes the ConnectionCallbacks and OnConnectionFailedListener static inner interfaces. ConnectionCallbacks provides callback methods that are automatically called when we connect or are disconnected from the Google service. OnConnectionFailedListener provides a callback method that is automatically called if the connection attempt failed. TABLE 11.2 lists them. The int parameter of the onConnectionSuspended method can be tested against the CAUSE_SERVICE_DISCONNECTED and CAUSE_NETWORK_LOST constants of the ConnectionCallbacks interface in order to determine the cause of the disconnection.

TABLE 11.2 The ConnectionCallbacks and OnConnectionFailedListener interfaces and their methods

Interface Method Description
ConnectionCallbacks void onConnected( Bundle connectionHint) Automatically called after successful completion of a connection request made by calling the connect method with a GoogleApiClient reference.
ConnectionCallbacks void onConnectionSuspended(int cause) Automatically called when the connection is lost. The GoogleApiClient object will automatically attempt to restore the connection.
OnConnectionFailedListener void onConnectionFailed(ConnectionResult result) Automatically called when there is an error connecting to the service.

Thus, assuming we are inside an Activity class that implements the ConnectionCallbacks and OnConnectionFailedListener interfaces, we can instantiate a GoogleApiClient object using the following sequence:

// Assuming that we are inside an Activity class and that it
// implements ConnectionCallbacks and OnConnectionFailedListener
GoogleApiClient.Builder builder = new GoogleApiClient.Builder( this );
builder.addConnectionCallbacks( this );
builder.addOnConnectionFailedListener( this );
builder.addApi( LocationServices.API );
GoogleApiClient gac = builder.build( );

Since we are inside an Activity class, we can use this as the argument of the GoogleApiClient.Builder constructor. Since the Activity class implements both interfaces, we can also use this as the argument of addConnectionCallbacks and addOnConnectionFailedListener. We use the API constant of the LocationServices class, shown in TABLE 11.3, as the argument of the addApi method. Alternatively, since these three methods return the GoogleApiClient.Builder reference that calls them, we can chain method calls as follows:

GoogleApiClient gac = new GoogleApiClient.Builder( this )
                   .addConnectionCallbacks( this )
                   .addOnConnectionFailedListener( this )
                   .addApi( LocationServices.API ).build( );

TABLE 11.3 Selected fields of the LocationServices class

Constant Description
API A constant that should be used to pass to the addApi method of the GoogleApi.Builder class during the process of building a GoogleApiClient.
FusedLocationAPI Static constant of type FusedLocationProviderAPI, an interface that includes methods to retrieve the location of a device and manage location updates.

TABLE 11.4 Selected methods of the GoogleApiClient class

Methods Description
void connect( ) Establishes a connection with Google Play services. If successful, the onConnected method of ConnectionCallbacks is called. If unsuccessful, onConnectionFailed is called.
void disconnect( ) Closes the connection with Google Play services.

Once we have a GoogleApiClient reference, and assuming its name is gac, we can attempt to establish a connection by calling the connect method of GoogleApiClient, shown in TABLE 11.4, as in the code that follows:

// Assuming that gac is a GoogleApiClient reference
gac.connect( );

If the connection is successful, the onConnected method of the ConnectionCallbacks interface is automatically called. Inside that method, we can retrieve the location of the device.

If the device fails to connect to Google Play services, the onConnectionFailed callback method is called. We want to check if that issue can be resolved (for example, Google Play services may need to be updated on the device). We can do that by calling the hasResolution method with the ConnectionResult parameter of onConnectionFailed. If that method returns false, the issue cannot be resolved and we can exit the app. If that method returns true, the issue can be resolved and we want to try to resolve it. We can do so by calling the startResolutionForResult method of ConnectionResult. TABLE 11.5 shows both methods. This requires user interaction. After it is over, the onActivityResult method of the Activity class will be called. Inside that method, we can check if the issue was resolved. If it was, we can try to connect again to Google Play services.

TABLE 11.5 Selected methods of the ConnectionResult class

Method Description
boolean hasResolution( ) Returns true if there is a resolution that can be started to attempt to solve the connection issue.
void startResolutionForResult( Activity activity, int requestCode ) Starts an intent to attempt to resolve a connection issue. This requires user interaction.

We can implement this with the following pseudo-code:

// inside onConnectionFailed method
if( there is a possible resolution to the issue )
  call startResolutionForResult to try to resolve it
else
  exit the app
// inside onActivityResult
if( the problem was resolved )
  try to connect again

EXAMPLE 11.2 shows the MainActivity class. It implements the ConnectionCallbacks and OnConnectionFailedListener interfaces (lines 14–15). We declare a GoogleApiClient instance variable at line 18. We instantiate it at lines 25–28. The onStart method is automatically called after onCreate executes. If gac is not null (line 66), we try to establish the connection at line 67. If successful, this triggers a call to the onConnected method (lines 31–34). In this version, we simply output some feedback to Logcat. If the connection attempt fails, we execute inside onConnectionFailed (lines 41–54). At line 44, we test if there is a possible resolution to that problem. If there is, we try to start an activity to solve it at line 46. If we cannot, we exit the app after showing a Toast (lines 48–51). If we were successful in starting an activity to try to solve the connection problem, and after interaction with the user, the app will resume execution inside the onActivityResult method (lines 56–62). If the resolution was successful (line 58), we try to connect to Google Play services again at line 60.

EXAMPLE 11.2 The MainActivity class, GPS app, Version 0

When running the GPS app, Version 0, the output inside Logcat shows that we are connected.

11.2 Using the GPS to Retrieve Our Location, GPS App, Version 1

In Version 1, we retrieve the location of the device and display it in a TextView. Since the app accesses the GPS, it will not work in the emulator, although we could hard code latitude and longitude data using the emulator. To use our current location, we need to run it on a device. Because the app uses location services from Google, we need to specify that in the AndroidManifest.xml file. Thus, we need to do the following:

  • ▸ In the AndroidManifest.xml file, specify that we use location services and add meta data about the Google Play services version this app uses.

  • ▸ Inside the MainActivity class, capture our current location and display it.

EXAMPLE 11.3 shows the AndroidManifest.xml file. At lines 5–6, we specify that this app accesses the approximate location of the device. The ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION String constants of the Manifest.permission class can be used to specify an approximate or a precise location, respectively. At lines 15–17, we specify the version of Google Play services that this app uses. To make it simple, we only allow the app to work in vertical orientation (line 20).

Inside the MainActivity class, we do the following:

  • ▸ Establish a connection with Google Play services.

  • ▸ Retrieve the location.

  • ▸ Display the location.

The Location class, part of the android.location package, encapsulates a geographical location on Earth. A location is typically identified by its latitude and longitude. TABLE 11.6 lists a few methods of the Location class. Note that the Location class uses the metric system and distances, when calculated by methods, are returned in meters.

The lastLocation method of the FusedLocationProviderApi interface returns the current location of the device as a Location reference. It accepts a GoogleApiClient parameter, as shown in TABLE 11.7. We use this method to retrieve the device’s location. Thus, in order to call that method, we need a FusedLocationProviderApi reference to call it, and a GoogleApiClient reference to pass as its only argument. As shown in Table 11.3, the LocationServices class, part of the com.google.android.gms.location package, includes a FusedLocationProviderApi constant named FusedLocationApi. Thus, assuming we have a GoogleApiClient reference named gac, we can retrieve the current location using the following sequence:

// Assuming that gac is a GoogleApiClient reference
FusedLocationProviderApi flpa = LocationServices.FusedLocationApi;
Location location = flpa.getLastLocation( gac );

EXAMPLE 11.3 The AndroidManifest.xml file

TABLE 11.6 Selected methods of the Location class

Method Description
double getLatitude( ) Returns the latitude of this Location.
double getLongitude( ) Returns the longitude of this Location.
float getAccuracy( ) Returns the accuracy of this Location, in meters.
float distanceTo( Location destination ) Returns the distance between this Location and destination, in meters.

TABLE 11.7 The getLastLocation method of the FusedLocationProviderApi interface

Method Description
Location getLastLocation( GoogleApiClient gac) Returns the most recent location, null if no location is available.

Once we have a Location reference for the current location, we can retrieve the latitude and longitude of that location by calling the getLatitude and getLongitude methods as follows:

double latitude = location.getLatitude( );
double longitude = location.getLongitude( );

EXAMPLE 11.4 shows the MainActivity class. We declare two additional instance variables at lines 23–24: location, a Location to store the current location; and locationTV, a TextView to display the location. Inside onCreate, we instantiate the TextView at line 30. This assumes that there is a TextView whose id is location_tv inside activity_main.xml. Inside the onConnected method, we call the displayLocation method at line 52. The displayLocation method (lines 38–48) retrieves the current device location at lines 39–40. If the location is not null (line 41), we retrieve its latitude and longitude, display them inside the TextView (line 44), and output them to Logcat (line 45).

EXAMPLE 11.4 The MainActivity class, GPS app, Version 1

EXAMPLE 11.5 shows the activity_main.xml file. The id of the TextView is assigned at line 13. EXAMPLE 11.6 shows the styles.xml file, which specifies a font size of 22 at line 5.

FIGURE 11.2 shows the output of the app inside Logcat, showing the latitude and longitude data. Note that we must run this app on a connected device (which has GPS), not the emulator.

EXAMPLE 11.5 The activity_main.xml file, GPS app, Version 1

EXAMPLE 11.6 The styles.xml file, GPS app, Version 1

FIGURE 11.2 The Logcat output of the GPS app Version 1

11.3 Model for Distance and Time to Destination

In Version 2, we ask the user to input an address for his or her destination, and we provide a button to display the distance and time left to that destination. Before building the GUI and the controller for it, we add the TravelManager class, the Model for the app, shown in EXAMPLE 11.7. It includes a Location instance variable to store a destination (line 9) and methods to calculate the distance and time left from the current location to the destination location. In order to keep this app simple, we assume that the user travels at 55 miles per hour (line 6).

EXAMPLE 11.7 The TravelManager class, GPS app, Version 2

In the distanceToDestination method (lines 15–21), we call the distanceTo method of the Location class shown in Table 11.6 in order to calculate the distance between its Location parameter and destination. If one of them is null, it returns –1. Otherwise, we return the distance between them. The milesToDestination method (lines 23–31) converts and returns that distance to a String representing the number of miles.

The timeToDestination method (lines 33–54) calculates and returns the time that it takes to go from its Location parameter and destination, assuming a speed of 55 miles per hour. At lines 35–36, we compute the distance to the destination from its Location parameter in meters. At 37–38, we compute the time in hours, as a float, that it takes to drive that distance at a speed of 55 miles per hour. We then convert that value to the String result, which represents the number of hours and the number of minutes at lines 40–52. Note that if the time is either 0 or negative (line 51), we assign less than a minute left to result at line 52.

11.4 Distance and Time to Destination, GPS App, Version 2

We include the following elements in the GUI, all centered and lined up vertically:

  • ▸ One EditText for the user to enter the destination address.

  • ▸ Two TextViews to display the distance and time to destination.

  • ▸ One Button: when the user clicks on it, we update the distance and time to destination in the two TextViews.

EXAMPLE 11.8 shows the updated activity_main.xml file. We give all the elements an id (lines 13, 18, 23, 28) so we can position them and retrieve them as needed in the MainActivity class. We want to specify the WRAP_CONTENT value for both the width and height of all the elements. We also want to have 20 pixels between them and center them horizontally. Thus, we define the WrappedAndCentered style in styles.xml (lines 11–16 of EXAMPLE 11.9) and use it for all the four elements (lines 15, 20, 25, 32). We specify a hint, Enter destination, defined in the strings.xml file (line 3 of EXAMPLE 11.10) for the EditText at line 14. At line 30, we define the text inside the button as the String Update, defined at line 4 of Example 11.10. At line 31, we specify that the updateTrip method is called when the user clicks on the Button.

EXAMPLE 11.8 The activity_main.xml file, GPS app, Version 2

Inside the MainActivity class, we need to make the following edits:

  • ▸ Add the appropriate import statements.

  • ▸ Add a TravelManager instance variable so that we can access the functionality of the Model.

  • ▸ Add instance variables for the EditText and the two TextViews of the GUI and a String to store the destination address.

  • ▸ Delete the displayLocation method: we are no longer interested in displaying our location.

  • ▸ Add the updateTrip method.

  • ▸ Delete the body of the onConnected method: we want to wait for the user to input a destination address before we do anything.

EXAMPLE 11.9 The styles.xml file, GPS app, Version 2

EXAMPLE 11.10 The strings.xml file, GPS app, Version 2

EXAMPLE 11.11 shows the updated MainActivity class. We declare the additional five instance variables at lines 29–33. The TravelManager and the three GUI components are instantiated inside onCreate at lines 39–42. Inside the updateTrip method (lines 50–79), we retrieve user input, update the Model if necessary, call methods of the Model to calculate the distance and time left to the destination, and update the View accordingly.

EXAMPLE 11.11 The MainActivity class, GPS app, Version 2

We first retrieve the destination address entered by the user at line 51. If the destination address is different from the current destination address (line 53), we update the current destination address (line 54). We then try to geocode it into a Location object (lines 57–59). Geocoding is the process of converting a street address into a (latitude, longitude) coordinate. TABLE 11.8 shows a constructor and a getFromLocationName method of the Geocoder class. If the geocoding is successful (line 60), we assign the Location to the destination instance variable of the TravelManager (line 66). We keep track of whether the geocoding is successful or not with the state variable goodGeocoding. We initialize it to true at line 52, and switch it to false if we end up in the catch block at line 69. We retrieve the current location at lines 73–74. If we are successful retrieving the current location and if the geocoding was successful (line 75), we update the two TextViews displaying the distance and time left to the destination at lines 76–77. The manager instance variable calls the milesToDestination and timeToDestination methods, passing the current location.

TABLE 11.8 Selected methods of the Geocoder class

Methods Description
Geocoder( Context context ) Constructs a Geocoder.
List getFromLocationName( String locationName, int maxResults ) Returns a list of Address objects that match locationName. Throws an IllegalArgumentException and an IOException.

FIGURE 11.3 The GPS app, Version 2, running inside the tablet

FIGURE 11.3 shows the app running inside the tablet after the user enters the address of the White House and clicks on update.

11.5 Updating Distance and Time to Destination, GPS App, Version 3

In Version 3, we want to update the distance and time left to destination automatically, without having to click on the Update button. We keep the Update button in case the user wants an instant update. Thus, the user interface is identical to the one in Version 2.

The LocationListener interface, part of the com.google.android.gms.location package, provides a callback method, onLocationChanged, that is automatically called based on various specified parameters, such as frequency and distance travelled, as shown in TABLE 11.9. This is very similar to event handling; we need to do the following:

  • ▸ Create a private class that implements LocationListener (and override onLocationChanged).

  • ▸ Declare and instantiate an object of that class.

  • ▸ Register that object on a fused location provider (a FusedLocationProviderApi reference).

TABLE 11.9 The onLocationChanged method of the LocationListener class

Method Description
void onLocationChanged( Location location ) Callback method called automatically as defined by a LocationRequest; location represents the most recent location.

TABLE 11.10 Selected methods of the FusedLocationProviderApi interface

Method Description
PendingResult requestLocationUpdates( GoogleApiClient gap, LocationRequest request, LocationListener listener ) Requests listener to listen to location updates based on request.
PendingResult removeLocationUpdates( GoogleApiClient gap, LocationListener listener ) Discontinues location updates for listener.

Alternatively, we can do the following:

  • ▸ Have our Activity class implement LocationListener (and override onLocationChanged).

  • ▸ Register this on a fused location provider (a FusedLocationProviderApi reference).

We choose to implement the second strategy. TABLE 11.10 shows one of the requestLocationUpdates methods of the FusedLocationProviderApi interface. It requests that its LocationListener parameter provides location updates, via the onLocationChanged method, as defined by its LocationRequest parameter. Thus, assuming that we are inside an Activity class that implements the LocationListener interface, and that a LocationRequest named request has been defined, we can request location updates using the following code sequence:

// we are inside an Activity class that implements LocationListener
// thus, this "is a" LocationListener
// gac is a GoogleApiClient reference
// request is a LocationRequest reference
FusedLocationProviderApi flpa = LocationServices.FusedLocationApi;
flpa.requestLocationUpdates( gac, request, this );

TABLE 11.11 Selected methods of the LocationRequest class

Method Description
LocationRequest setInterval( long ms ) Sets the interval for location updates in milliseconds. Returns this LocationRequest so method calls can be chained.
LocationRequest setPriority( int priority ) Sets priority of this request. The LocationRequest class includes constants (see Table 11.12) that can be used as the argument. Returns this LocationRequest so method calls can be chained.
LocationRequest setSmallestDisplacement( float meters ) Sets the minimum distance between consecutive updates. Returns this LocationRequest so method calls can be chained.

At that point, we will receive updates and the onLocationChanged method will be called at the frequency specified by the LocationRequest. Its Location parameter stores the most recent location, as follows.

public void onLocationChanged( Location location ) {
// location is the most recent location
}

The LocationRequest class provides the functionality to define a request for location updates by specifying the frequency of updates, their accuracy, etc.

TABLE 11.11 shows the two most important methods of the LocationRequest class. We use the setInterval method to specify the desired frequency, in milliseconds, of location updates. A location update consumes power, and frequent updates can drain the device’s battery. We use the setPriority method to specify a desired accuracy level, which in turn is a hint at what source to use, GPS or Wi-Fi and cell tower. However, other factors, such as the current location and availability or such sources, as well as the device itself, can impact the accuracy of the location returned. All the set methods of the LocationRequest class return the LocationRequest reference that calls them, so that we can chain method calls. If we do not want updates—if we have not moved by a minimum distance—we can use the setSmallestDisplacement method and specify such minimum distance between two consecutive updates. For example, in a travel app, the user does not need distance updates if he or she is stuck in traffic and is not moving.

The following code sequence shows how to define a LocationRequest:

LocationRequest request = new LocationRequest( );
request.setInterval( 30000); // 30 seconds interval
request.setPriority( LocationRequest.PRIORITY_HIGH_ACCURACY );
request.setSmallestDisplacement(100); // 100 meters minimum

TABLE 11.12 shows the constants of the LocationRequest class that we can use as the argument of the setPriority method. The higher the accuracy requested, the higher the battery usage. Without specifically setting the priority by calling setPriority, the default priority, defined by PRIORITY_BALANCED_POWER_ACCURACY, is used. If we build a golf app that measures the distance to the pin, we want accuracy to the nearest yard or meter, so we specify the highest possible accuracy. For this travel app, the default accuracy is adequate.

TABLE 11.12 Priority constants of the LocationRequest class

Constant Value Description
PRIORITY_HIGH_ACCURACY 100 The highest available accuracy.
PRIORITY_BALANCED_POWER_ACCURACY 102 The default value—block level accuracy, around 100 meters.
PRIORITY_LOW_POWER 104 City level accuracy, around 10 kilometers.
PRIORITY_NO_POWER 105 The worst accuracy, requesting no power consumption.

EXAMPLE 11.12 shows the changes in the MainActivity class. We only want to set up location updates if we are successfully connected. Thus, we do that inside the onConnected method (lines 98–108). We create and define a LocationRequest at lines 100–103. We added the calls to setPriority and setSmallestDisplacement in order to illustrate them, but commented them out. Indeed, if we test the app without moving, we do not want to set a minimum distance for location updates. It is actually possible that we get disconnected in the middle of the onConnected method, in which case the app will crash when we try to set up location updates. Thus, we test that we are connected (line 104) before we set up location updates (line 105). If we lost the connection, we try to establish another connection (line 107).

Inside the onLocationChanged method (lines 54–59), we call updateTrip at line 58 in order to update the two TextViews showing the distance and time left to the destination. For feedback, we output to Logcat information about the accuracy and the timeline of the automatic calls to onLocationChanged. TABLE 11.13 shows the getAccuracy and getElapsedRealtimeNanos methods. The getElapsedRealtimeNanos method requires API level 17. Thus, we update the build.gradle file accordingly.

If the app is running and goes in the background, we want to stop requesting location updates. When that happens, the onPause method (lines 92–96) is called automatically. We disable location updates at line 95 by calling the removeLocationUpdates method (shown in Table 11.10). When the app comes back to the foreground, onStart is called, reconnects to Google Play services if necessary, and we request location updates again when onConnected executes.

FIGURE 11.4 shows the Logcat output of the app when running on the author’s tablet. The output shows that the accuracy of the location returned by the GPS can vary from measurement to measurement. In this instance, it varies from 30 meters to 64.5 meters. One nanosecond is equal to 10–9 second. The interval frequency of the measurements is always very close to the 30 seconds specified. It varies between 30.016 seconds (time elapsed between the last and next to last measurements) and 30.034 seconds (time elapsed between the third and fourth measurements). When the app starts, the two TextViews show 0 mile and seconds left. If we enter an address and wait, the distance and time to that location is automatically updated after fewer than 30 seconds without clicking on the Update button, illustrating that the onLocationChanged method has been called.

EXAMPLE 11.12 The MainActivity class, GPS app, Version 3

TABLE 11.13 Selected methods of the Location class

Method Description
float getAccuracy( ) Returns the accuracy for this Location in meters.
long getElapsedRealtimeNanos( ) Returns the time since the last boot in nanoseconds.

FIGURE 11.4 Logcat output of the GPS app, Version 3, when running inside the tablet

Accuracy can be device and location dependent too. Further testing on the author’s tablet from his home shows an accuracy varying from 12 meters to 36 meters when setting the priority using PRIORITY_HIGH_ACCURACY (by un-commenting line 102 in Example 11.12).

Chapter Summary

  • The GoogleApiClient class is the entry point to Google Play services.

  • If Google Play services are not available, it is possible that they can be made available via user interaction.

  • The Builder static inner class of GoogleApiClient enables us to build a GoogleApiClient.

  • We can obtain the current location of the device by calling the lastLocation method of the FusedLocationProviderApi interface.

  • The LocationServices has a FusedLocationProviderApi static constant field named FusedLocationApi.

  • The getLatitude and getLongitude methods of the Location class return the latitude and longitude of a location.

  • The distanceTo method of the Location class returns the distance, in meters, between the Location reference calling it and a parameter Location reference.

  • If the app accesses Google Play services to retrieve the device’s location, we should add a uses-permission element in the AndroidManifest.xml file and specify ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION, two constants of the Manifest.permission class.

  • The Geocoder class provides methods to convert an address into a Location object (i.e., latitude and longitude) and vice versa.

  • We can get location updates at a regular interval by implementing the LocationListener interface. LocationListener contains one callback method, onLocationChanged. It takes a Location parameter that represents the current location of the device.

  • We use the requestLocationUpdates method to register a LocationListener on a FusedLocationProviderApi, defining various parameters of the updates using a LocationRequest parameter. Such registration triggers automatic calls to the onLocationChanged method of LocationListener.

  • The most important attributes of a LocationRequest are the frequency of the updates and the priority, which translates into the accuracy of the locations retrieved.

Exercises, Problems, and Projects

Multiple-Choice Exercises

  1. How can we obtain a GoogleApiClient reference?

    • Use a constructor of GoogleApiClient

    • Use the getInstance method of GoogleApiClient

    • Create a GoogleApiClient.Builder and call the build method

    • We cannot

  2. What is the name of the FusedLocationProviderApi constant of LocationServices?

    • Api

    • FusedLocationApi

    • FusedApi

    • Fused

  3. The Location class encapsulates a location on Earth. What method can we use to retrieve its latitude?

    • latitude

    • getLat

    • getLatitude

    • locationLatitude

  4. The distanceTo method of the Location class returns a distance in

    • yards

    • meters

    • miles

    • kilometers

  5. What class contains methods to convert an address to a Location and vice versa?

    • Geocoder

    • LocationCoder

    • Mapping

    • Geography

  6. If we want to get location updates at regular intervals, what interface should we implement?

    • Listener

    • UpdateListener

    • GeoListener

    • LocationListener

  7. What is the meaning of the Location parameter of the onLocationChanged method of the interface of question 6?

    • It stores a random location

    • It stores the most recent location

    • It stores the next location

    • It is null

  8. We call the requestLocationUpdates of the FusedLocationProviderApi interface to request regular location updates. Two of its parameters are a GoogleApiClient and a LocationListener. What is the type of the third one?

    • double

    • Request

    • Time

    • LocationRequest

Fill in the Code

  1. Declare and instantiate a GoogleApiClient that listens to connection success and failures.

  2. The Location reference myLocation stores a location. Output to Logcat its accuracy.

  3. The String address stores an address. Output its latitude and longitude to Logcat. Use the first Address geocoded for this.

  4. The MyActivity class wants to get location updates. Write its class header.

  5. Code the onLocationChanged method so that we display the latitude and longitude of the current location in a TextView name MyTV.

  6. Build a LocationRequest that can be used to trigger updates every 100 seconds with the highest possible accuracy.

  7. We are coding inside an Activity class that implements LocationListener. We have already instantiated a FusedLocationProviderApi named providerApi, a GoogleClientApi named clientApi, and a LocationRequest named request. Write one statement so that we get location updates as defined by request inside this Activity class.

Write an App

  1. Expand the app in the chapter by calculating the time left using the speed between the last two location updates rather than 55 miles per hour.

  2. Expand the app in the chapter by calculating the time left using the average speed between the last five location updates rather than 55 miles per hour. If there have not been five location updates yet, use 55 miles per hour.

  3. Write an app that identifies the closest location from where the user is among five locations. The five locations can be hard coded inside the Model of the app.

  4. Write an app that identifies how far the user is from five locations. The five locations can be hard coded inside the Model of the app. As the user moves, the five distances should be updated at regular intervals. The app should let the user decide the frequency of the updates and the accuracy of the locations (priority).

  5. Write an app that enables the user to select a friend in a list, retrieve his or her address, and calculate how far that friend is. The list should be stored either in a file or can be hard coded. Include a Model.

  6. Same as 20 but the list is not hard coded, is persistent and is expandable. The user can add to the list.

  7. Same as 21 but the user can also delete and update a friend’s data from the list.

  8. Write a 1-hole golf app. The app allows the user to enter the location of the middle of the green by simply clicking on a button. That data should be stored on the device. The app allows the user to compute the distance from where the user is to the middle of the green location (previously stored).

  9. Same as 23 but the app is an 18-hole golf app, not a 1-hole golf app.

  10. Write an app that stores a list of locations and descriptions on the device. The user can enter a description for a location (where the user is) and can click on a button to retrieve the current location and write to the device’s storage the description and the location. The app also allows the user to retrieve the list of descriptions and locations and display them.

  11. Write an app that sends an email and includes the latitude and longitude of the user’s location in the body of the email.

  12. Same as 26 but convert the current location to an address and include the current address in the body of the email.

  13. Write an app that helps the user retrieve the parking location of his or her car. When the user parks his or her car, the user clicks on a button to store the car’s location. If the user wants to know where his or her car is, the app displays a map with two circles showing both the car and the user location.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.254.245