Lecture 12 Location

This lecture discusses localization: the process for determining location. This is particularly important for Android, which is primarily intended as an operating system for mobile devices. What makes phones and tablets special, and different from desktops, is that they can and do move around. And this mobility makes means that a device’s position and location can matter significantly for how they are used; it’s a major part of what separates the functionality of Android apps from any other computer application. Indeed: localization gives apps the ability to create new kinds of user experiences, and to adjust their functionality to fit the user’s context, supporting context-aware applications.

  • The classic example of context-awareness is having software determine if you are at home, in the office, or on a bus, and change its usage accordingly.

    • In fact, one of the winners of the first Android Developer Challenge (2008) was Ecorio, an app that figured out whether you were driving, walking, or busing and calculated your carbon footprint from that.
  • Note that the emphasis on context-awareness comes out of Ubiquitous Computing, a discipline that considers technology that is ubiquitous or everywhere, to the point that it “blends into the surroundings.” That’s the author’s take on why phone development is important; so that you can compute without thinking about it.

    I highly recommend you read Mark Weiser’s original 1991 Scientific American article. It’s a neat vision and is foundational for a lot of modern research into mobile systems. It marks the “official” start of the field of Ubicomp.

In short: localization can let us know about the user’s situation (though mobile phone location is not necessarily a proxy for user location).

12.1 Localization Techniques

Ubicomp researchers have been developing localization systems for years. A classical reference is a survey paper by Jeff Hightower (who was getting his PhD in the CSE department at UW!)

  • As an early example: the Active Badge (AT&T) system had a name-badge emit an infrared message, that was picked up by sensors in a room to determine where the wearer was! This is room-level precision, but improvements and triangulation (calculating angles to what you see) got it down to about 10cm precision. However, this system required a lot of infrastructure to be built into a particular room.

With Android, we’re usually interested in more general-purpose localization. Mobile devices use a couple of different kinds of localization (either independently or together).

GPS

GPS is the most common general-purpose localization technology, and what most people think of when they think of localization. GPS stands for “Global Position System”—and yes, it can work anywhere on the globe.

GPS’s functionality depends on satellites: 24 satellites in high orbit (not geo-synchronous) around the Earth. Satellites are distributed so that 4 to 12 are visible from any point on Earth at any time, and their locations are known with high precision. These satellites are each equipped with an atomic, synchronized clock that “ticks” every nanosecond. At every tick, the satellite broadcasts its current time and position. You can almost think of them as really loud alarm clocks.

The thing in your phone (or your car, or your watch) that you call a “GPS” or a “GPS device” is actually a GPS receiver. It is able to listen for the messages broadcast by these satellites, and determine its (the device’s) position based on that information.

First, the receiver calculates the time of arrival (TOA) based on its own clock and comparing time-codes from the satellites. It then uses the announced time of transmission (TOT; what the satellite was shouting) to calculate the time of flight, or how long it took for the satellite’s message to reach the receiver. Because these messages are sent at (basically) the speed of light, the time of flight is equivalent to the distance from the satellite!

  • There is some other synchronization work that is done to make sure clocks are all the same, but we won’t go into that here.

And once it has distances from the satellites, the receiver can use trilateration to determine its position based on the satellites it “sees”. (Trilateration is like Triangulation, but relies on measuring distances rather than measuring angles. Basically, you construct three spheres of given radii, and then look to see where they intersect).

GPS precision is generally about 5 meters (15 feet); however, by repeatedly calculating the receiver’s position (since the satellites tick every nanosecond), we can use differential positioning to extrapolate position with even higher precision, increasing precision to less than 1 meter! This is in part how Google can determine where you’re walking.

While GPS is ubiquitous, scalable, and sufficiently accurate, it does have some limitations. The biggest problem with GPS is that you need to be able to see the satellites! This means that GPS frequently doesn’t work indoors, as many building walls block the signals. Similarly, in highly urban areas (think downtown Seattle), the buildings can bounce the signal around and throw off the TOF calculations, making it harder to pinpoint position accurately.

  • Additionally, receivers requires a lot of energy to constantly listen for the satellite messages. This means that utilizing the GPS can lead to a big hit on device battery life—which is of particular importance for mobile devices!

Cell Tower Localization

But your phone can also give you a rough estimate of your location even without GPS. It does this through a couple of techniques, such as relying on the cell phone towers that provide the phone network service. This is also known as GSM localization (Global System for Mobile Communications; the standard for cell phone communication used by many service providers). The location of these towers are known, so we can determine location based off them in a couple of ways:

  • If you’re connected to a tower, you must be within range of it. So that gives you some measure of localization right off the bat. This would not be a very accurate measure though (you might be anywhere within that range).

  • If you can see multiple towers (which is important for “handoff” purposes, so your call doesn’t drop as you move), you can trilaterate the position between them (e.g., finding the possible overlapping area and picking a location in the middle of that). This can give accuracy within 50m in urban areas, with more towers producing better precision.

WiFi Localization

But wait there’s more! What other kinds of communication antennas do you have in your phone? WiFi! As WiFi has became more popular, efforts have been made to identify the location of WiFi hotspots so that they too can be used for trilateration and localization.

This is often done through crowdsourced databases, with information gathered via war driving. War driving involves driving around with a GPS receiver and a laptop, and simply recording what WiFi routers you see at what locations. This then all gets compiled into a database that can be queried—given that you see these routers, where must you be?

  • Google got in hot water for doing this as it was driving around to capture Street-View images.

WiFi localization can then be combined with Cell Tower localization to produce a pretty good estimate of your location, even without GPS.

And in fact, Google provides the ability to automatically use all of these different techniques, abstracted into a single method call!

I want to flag that just like the old Active Badge systems, all of these localizations systems rely on some kind of existing infrastructure: GPS requires satellites; GSM requires cell towers, and WiFi needs the database of routers. All these systems require and react to the world around them, making localization influenced by the actual location as well as both social and computational systems!

Representing Location

So once we have a location, how do we represent it?

First, note that there is a philosophical difference between a “place” and a “space.” A space is a location, but without any social connotations. For example, GPS coordinates, or Cartesian xy-coordinates will all indicate a “space.” A place on the other hand is somewhere that has social meaning: Mary Gates Hall; the University of Washington; my kitchen. Space is a computational construct; place is a human construct. When we talk about localization with a mobile device, we’ll be mostly talking about space. But often place is what we’re really interested in, and we may have to convert between the two (Google does provide a few ways to convert between the two, such as with its Places API).

Our space locations will generally be reported as two coordinates: Latitude and Longitude. (Altitude or height can also be reported, but that isn’t very relevant for us).

  • Latitude (“lat”) is the angle between the equatorial plane and a line that passes through a point and the center of the Earth—the angle you have to go up the earth’s surface from the equator. Effectively, it’s a measure of “north/south”. Latitude is usually measured in degrees north, so going south of the equator gives a negative latitude (though this can be expressed positively as “degrees south”).

  • Longitude (“lng”) is the angle between the prime meridian plane and a line that passes through a point and the center of the Earth—the angle you have to go across the earth’s surface from the meridian. Effectively, it’s a measure of “east/west”. Latitude is measured in degrees east, so going east of the meridian. That mean that the western hemisphere has “negative longitude” (though this can be expressed as positive “degrees west”).

As an example: UW’s GPS Coordinates38 are N/W, so this would be expressed as N (positive) and E (negative).

The distance between degrees and miles depends on where you you are (particularly for longitude—the curvature of the earth means that each degree has less space between it as you get closer to their “joining” at the poles). However, for a very rough sense of scale, in the American Northwest, .01 degrees corresponds with a distance of about a mile (again: this is not an accurate conversion, and is intended only for a sense of the “units”).

12.2 Android Location

The remainder of the lecture will discuss how to implement an app that is able to access the device’s location. This location will simply be displayed for now; connecting the location to a visual display (e.g., a map) is left as an exercise to the reader.

This lecture references code found at https://github.com/info448/lecture12-location.

Google Play Services

In order to effectively access location, we first need to make sure we include the Google Play Services. These are a special set of libraries (similar to the support libraries) that provide additional functionality to Android. That functionality will include the location and mapping tools we’re interested in. (Much of this functionality was originally built into core Android, but Google has since been moving it into a separate app that can be more easily distributed and updated!)

There are a few steps to including the Play Services library:

  1. Confirm that the project-level build.gradle file to include a reference to Google’s Maven Repository:

    allprojects {
        repositories {
            google()
            jcenter()
            // If you're using a version of Gradle lower than 4.1, you must instead use:
            maven {
                url 'https://maven.google.com'
            }
        }
    }

    Make sure you put this under allprojects, and not buildscripts!

  2. Make sure the device supports these services (e.g., that it’s a Google device and not an Amazon device). For the emulator, go to the AVD Manager, and confirm the target platform includes the Google APIs.

  3. Modify your build.gradle file so that you can get access to the Location classes. In the module-level build.gradle file, under dependencies add

    implementation 'com.google.android.gms:play-services-location:16.0.0'

    This will load in the location services (but not the other play services, which take up extra space and may require additional API keys). Note that you can specify a different version of the services, as long as it is greater than 11.6.0.

Additionally, you’ll need to request permission to access the device’s location. There are two permission levels we can ask for: ACCESS_COARSE_LOCATION (for GSM/WiFi level precision), and ACCESS_FINE_LOCATION (for GPS level precision). We’ll use the later because we want GPS-level precision.

This is a dangerous permission, so we need to make sure to ask for permission at run-time! See the lecture on permissions for details.

We’re going to use Google Play Services to access the device’s location. The Google APIs provide a nice set of methods for accessing location (without us needing to specify the source of that localization, GPS or GSM), and is the recommended API to use.

  • There is a built-in android.location API (e.g., for non-Google based Android devices), but it’s not recommended practice and is harder to use.

Accessing Location

Google provides location access through a FusedLocationProviderClient. This is a “unified” interface for accessing location. It fuses together all of the different ways of getting location, providing whichever one best suits our specified needs. You can think of it as a “wrapper” around more detailed location services.

  • It will let us specify at a high level whether we want to trade accuracy for power consumption, rather than us needing to be explicit about that. And it will make decisions about what how best to fetch location given our stated needs and other contextual information.

  • You can get access to the (singleton) client by calling a method on the LocationServices class:

    val fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

We’re going to specify this “high level” requirement using a LocationRequest39 object, which represents the details of our request (e.g., how we want to have our phone search for it’s location).

//java
LocationRequest request = new LocationRequest();
request.setInterval(10000);
request.setFastestInterval(5000);
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
//kotlin
val locationRequest = LocationRequest().apply {
    interval = 10000
    fastestInterval = 5000
    priority = LocationRequest.PRIORITY_HIGH_ACCURACY
}
  • We create the object, then specify the “interval” that we want to check for updates. We can also specify the “fastest” interval, which is the maximum rate we want updates (assuming they are available). It’s a bit like a minimum and maximum. 5 to 10 seconds is good for real-time navigation. See Set up a location request for more details.

    It is alternatively possible to only access the current location, if you don’t need regularly updates

  • We also specify the priority, which is the indicator to the FusedLocationApi about what kind of precision we want. HIGH_ACCURACY basically means GPS (trade power for accuracy!)

We will also need to specify a LocationCallback object, which represents the “callback function” that will be executed when each location update is received. This is usually defined as an anonymous object:

//kotlin
locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult?) {
        if(locationResult != null) {
            //do something with result!
        } 
    }
}

The onLocationResult() callback will be passed an object that is a “batch collection” of location updates (which can be useful to preserve battery); access the location property to get a list of Location objects. Each Location contains the latitude/longitude of the location. We can then use that location (such as display it). We can access the latitude and longitude with getters:

```java
//java
textLat.setText("" + location.getLatitude());
textLng.setText("" + location.getLongitude());
```

Finally, you can actually send the request for location updates using the FusedLocationProviderClient:

fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null)

(The third parameter is a Looper), which is used to perform asynchronous operations in a background thread.

Before actually sending the request, check for run-time permissions! Remember to implement onRequestPermissionResult

Importantly, in order to preserve battery life, you’ll want to make sure to stop requesting location updates when the app isn’t in use, such as when it is paused or stopped:

//kotlin
override fun onStop() {
    super.onStop()
    fusedLocationClient.removeLocationUpdates(locationCallback) //stop the updates that go to this callback
}

It is possible to test this out (even when indoors) by using the emulator. Although the emulator doesn’t actually have a GPS receiver, it is possible to give it a “fake” location using the emulator’s options sidebar (where we previously sent SMS messages from). This allows us to “send” the phone a location, almost as if we as humans were the GPS receiver!

  • You can test by giving the emulator UW’s coordinates (47.6550 N, -122.3080 E), and you can watch it update!

    • Note that you may need to start up the Maps application to make sure the devices’s location settings are enabled and correct. See here for how we can prompt for that ourselves (it’s a lot of repetitive code, so leaving it as exercise to the reader).
  • The FusedLocationApi class also has a setMockLocation() method, which can allow you to programmatically define locations (e.g., you can make a button that changes your location). This can be useful for testing and debugging.

The FusedLocationProviderApi was added in Google Play Services v12, and simplifies the process of getting location a lot!