Mobile Phone Handheld Hardware Hardware Rick Rogers John Lombardo O'Reilly Media, Inc. O'Reilly Media Android Application Development, 1st Edition9.6. Location Without MapsWhat if your Activity needs to access location information, but
it doesn't include a MapView? When you use a MapView, Android makes
everything very easy with MyLocationOverlay, but even if you don't
need a map, it isn't difficult to get location information. The code in
this section is not part of MJAndroid, but it shows how you would go about
getting location information without a map. Let's look at a very simple, one-Activity application that displays
the current location in a TextView. 9.6.1. The Manifest and Layout FilesAn appropriate AndroidManifest.xml file follows. We created this file using the Android SDK and the
Android Manifest Editor that comes as part of the SDK. The only change
we needed to make with the editor was to add the
uses-permission tag for
android.permission.ACCESS_FINE_LOCATION (in the
next-to-last line of the file). We always need this permission in order
to get location information from a GPS location provider: <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.microjobsinc.dloc"
android:versionCode="1"
android:versionName="1.0.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION">
</uses-permission>
</manifest>We'll use a very simple layout file with four TextViews: one label
and one text box each for latitude and longitude: <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/lblLatitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Latitude:"
/>
<TextView
android:id="@+id/tvLatitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/lblLongitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Longitude:"
/>
<TextView
android:id="@+id/tvLongitude"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>9.6.2. Connecting to a Location Provider and Getting Location
UpdatesLet's start with an Activity that just connects with the GPS LocationProvider
and gets and displays our current location (no updates). The procedure
is pretty straightforward: package com.microjobsinc.dloc;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the TextViews
TextView tvLatitude = (TextView)findViewById(R.id.tvLatitude);
TextView tvLongitude = (TextView)findViewById(R.id.tvLongitude);
// get handle for LocationManager
LocationManager lm = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
// connect to the GPS location service
Location loc = lm.getLastKnownLocation("gps");
// fill in the TextViews
tvLatitude.setText(Double.toString(loc.getLatitude()));
tvLongitude.setText(Double.toString(loc.getLongitude()));
}
}Here are some of the highlights of the code: But we also want to get periodic location updates from the
LocationManager so we can track our location as we
move about. For that we need to add a listener routine and ask the
LocationManager to call it when it has an
update. Location updates from the LocationManager are
accessible to an application through a DispLocListener
class, so we will create an instance of this class in the
onCreate method of our main Activity. We are required to
override a number of methods in DispLocListener to meet the
LocationListener interface definition, but we don't
need them for this application, so we'll leave the definitions
empty. The full implementation follows: package com.microjobsinc.dloc;
import android.app.Activity;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class Main extends Activity {
private LocationManager lm;
private LocationListener locListenD;
public TextView tvLatitude;
public TextView tvLongitude;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// find the TextViews
tvLatitude = (TextView)findViewById(R.id.tvLatitude);
tvLongitude = (TextView)findViewById(R.id.tvLongitude);
// get handle for LocationManager
LocationManager lm = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
// connect to the GPS location service
Location loc = lm.getLastKnownLocation("gps");
// fill in the TextViews
tvLatitude.setText(Double.toString(loc.getLatitude()));
tvLongitude.setText(Double.toString(loc.getLongitude()));
// ask the Location Manager to send us location updates
locListenD = new DispLocListener();
lm.requestLocationUpdates("gps", 30000L, 10.0f, locListenD);
}
private class DispLocListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
// update TextViews
tvLatitude.setText(Double.toString(location.getLatitude()));
tvLongitude.setText(Double.toString(location.getLongitude()));
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
}
}Our onCreate method creates an instance of
DispLocListener and requests that the
LocationManager update it as needed using
requestLocationUpdates. This method takes four
parameters:
String provider Which location provider to use. We assume GPS is available
in this case.
long minTime Minimum update time, in milliseconds. The
LocationManager will wait at least this long
between updates. Here's an opportunity to tune your application
for battery life: more frequent updates means more battery
usage.
float minDistance Minimum distance, in meters, required to trigger an update.
The LocationManager will update us only if
we've moved at least this far since the last update.
LocationListener
listener The name of the listener method to call when there is an
update. This is the DispLocListener
instance we just created.
Finally, we want to add the onPause and
onResume code to turn off location updates when we're not
actually displaying on the user's screen, and then turn them back on
when we are: /**
* Turn off location updates if we're paused
*/
@Override
public void onPause() {
super.onPause();
lm.removeUpdates(locListenD);
}
/**
* Resume location updates when we're resumed
*/
@Override
public void onResume() {
super.onResume();
lm.requestLocationUpdates("gps", 30000L, 10.0f, locListenD);
}
9.6.3. Updating the Emulated LocationWhile you are developing and debugging an application like the one just shown, you're
normally running on the emulator. It would be nice (maybe even
essential) to be able to update the current location that the emulator
uses as it's running your code. Such a Mock Location Provider can get
very fancy, but Android provides some built-in ways of updating the
emulated location: The geo program built into the Android shell One-time updates via DDMS Tracks that are sequentially updated via DDMS
We'll look at each of these. 9.6.3.1. Using geo to update locationThe geo utility is built into the Android image that runs on the
emulator. It has a number of capabilities, the most important of which
is geo fix:
geo fix You can use the geo fix command to
send a location to Android by telnetting to the console of the
emulated Android. The LocationProvider will
then use this as the current location: telnet localhost 5554
Android Console: type 'help' for a list of commands
OK
geo fix -122.842232 38.411908 0
OK geo fix takes three
parameters:
longitude Specified in decimal
latitude Also specified in decimal
altitude Specified in meters
9.6.3.2. Using DDMS to update locationWe talked a lot about DDMS (the Dalvik Debug Monitor Service) in Chapter 5, but two features are related
to location updates. The Emulator Control pane of the DDMS screen
provides several ways of controlling the running emulator. After
switching to the DDMS perspective (click on DDMS in the upper right of
the Eclipse window), you should see the Emulator Control pane in the
middle left of the DDMS window (Figure 9-1). You will probably
have to scroll down in that pane to see the controls related to
Location Controls. 
To send a one-time update of a location to the emulator, just
enter the longitude and latitude in the appropriate boxes and click
Send. If you click on the GPX or KML tabs, you will be able to load a GPX or KML file that
describes a path, as shown in Figure 9-2. Here we've already loaded the
file OR.kml, which is included on
the website for this book. It traces a path near O'Reilly headquarters
in Sebastopol, California. 
You can create GPX tracks with many GPS navigation software
tools, and KML tracks with Google Earth or many other navigation
programs. The OR.kml file was
generated by plotting a series of Google Earth Placemarks and
concatenating them together into a single file. Here's an excerpt
from OR.kml: <?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<name>OR1.kml</name>
<StyleMap id="msn_ylw-pushpin">
<Pair>
<key>normal</key>
<styleUrl>#sn_ylw-pushpin</styleUrl>
</Pair>
<Pair>
<key>highlight</key>
<styleUrl>#sh_ylw-pushpin</styleUrl>
</Pair>
</StyleMap>
<Style id="sh_ylw-pushpin">
<IconStyle>
<scale>1.3</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
</Icon>
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Style id="sn_ylw-pushpin">
<IconStyle>
<scale>1.1</scale>
<Icon>
<href>http://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png</href>
</Icon>
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle>
<ListStyle>
</ListStyle>
</Style>
<Placemark>
<name>OR1</name>
<LookAt>
<longitude>-122.7583711698369</longitude>
<latitude>38.38922415809942</latitude>
<altitude>0</altitude>
<range>14591.7166300043</range>
<tilt>0</tilt>
<heading>0.04087372005871314</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.8239277647483,38.40273084940345,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>OR2</name>
<LookAt>
<longitude>-122.7677364592949</longitude>
<latitude>38.3819544049429</latitude>
<altitude>0</altitude>
<range>11881.3330990845</range>
<tilt>0</tilt>
<heading>-8.006283077460853e-010</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.8064486052584,38.40786910573772,0</coordinates>
</Point>
</Placemark>
<Placemark>
<name>OR3</name>
<LookAt>
<longitude>-122.7677364592949</longitude>
<latitude>38.3819544049429</latitude>
<altitude>0</altitude>
<range>11881.3330990845</range>
<tilt>0</tilt>
<heading>-8.006283077460853e-010</heading>
<altitudeMode>relativeToGround</altitudeMode>
</LookAt>
<styleUrl>#msn_ylw-pushpin</styleUrl>
<Point>
<coordinates>-122.7911077944045,38.41500788727795,0</coordinates>
</Point>
</Placemark>
...
|