/there/src/com/google/marvin/there/Guide.java
Java | 332 lines | 267 code | 49 blank | 16 comment | 57 complexity | 7d6c7fcfa292e5f2aec93e330643e3fb MD5 | raw file
1package com.google.marvin.there; 2 3 4import com.google.marvin.there.StreetLocator.StreetLocatorListener; 5 6import android.content.Context; 7import android.location.Location; 8import android.location.LocationListener; 9import android.location.LocationManager; 10import android.location.LocationProvider; 11import android.os.Bundle; 12import android.util.Log; 13 14/** 15 * Guide uses the magnetic compass, GPS/Network location provider, and the 16 * Google Maps API to generate a meaningful spoken string to let users know 17 * where they are. 18 * 19 * @author clchen@google.com (Charles L. Chen) 20 */ 21public class Guide implements Runnable, StreetLocatorListener { 22 23 private LocationListener networkLocationListener = new LocationListener() { 24 public void onLocationChanged(Location arg0) { 25 networkLoc = arg0; 26 networkLocLastUpdateTime = System.currentTimeMillis(); 27 networkFixCount++; 28 parent.tts.speak("[tock]", 1, null); 29 if (networkFixCount > minFixCount) { 30 unregisterLocationServices(); 31 log("Network location", "Lat: " + arg0.getLatitude() + ", Long: " + arg0.getLongitude()); 32 log("Network location", "Accuracy: " + arg0.getAccuracy()); 33 (new Thread(self)).start(); 34 } 35 } 36 37 public void onProviderDisabled(String arg0) { 38 unregisterLocationServices(); 39 networkLoc = null; 40 networkLocLastUpdateTime = -1; 41 } 42 43 public void onProviderEnabled(String arg0) { 44 } 45 46 public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 47 if (arg1 != LocationProvider.AVAILABLE) { 48 unregisterLocationServices(); 49 networkLoc = null; 50 networkLocLastUpdateTime = -1; 51 (new Thread(self)).start(); 52 } 53 } 54 55 }; 56 57 private LocationListener gpsLocationListener = new LocationListener() { 58 public void onLocationChanged(Location arg0) { 59 gpsLoc = arg0; 60 gpsLocLastUpdateTime = System.currentTimeMillis(); 61 gpsFixCount++; 62 parent.tts.speak("[tock]", 1, null); 63 if (gpsFixCount > minFixCount) { 64 unregisterLocationServices(); 65 log("GPS location", "Lat: " + arg0.getLatitude() + ", Long: " + arg0.getLongitude()); 66 log("GPS location", "Accuracy: " + arg0.getAccuracy()); 67 (new Thread(self)).start(); 68 } 69 } 70 71 public void onProviderDisabled(String arg0) { 72 unregisterLocationServices(); 73 gpsLoc = null; 74 gpsLocLastUpdateTime = -1; 75 } 76 77 public void onProviderEnabled(String arg0) { 78 } 79 80 public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 81 if (arg1 != LocationProvider.AVAILABLE) { 82 unregisterLocationServices(); 83 gpsLoc = null; 84 gpsLocLastUpdateTime = -1; 85 LocationManager locationManager = 86 (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE); 87 locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, 88 networkLocationListener); 89 } 90 } 91 92 }; 93 94 private LocationListener dummyLocationListener = new LocationListener() { 95 public void onLocationChanged(Location arg0) { 96 } 97 98 public void onProviderDisabled(String arg0) { 99 } 100 101 public void onProviderEnabled(String arg0) { 102 } 103 104 public void onStatusChanged(String arg0, int arg1, Bundle arg2) { 105 } 106 }; 107 108 private boolean triedGpsLastTime = false; 109 private long networkLocLastUpdateTime = -1; 110 private long gpsLocLastUpdateTime = -1; 111 private long lastLocateTime = 0; 112 private Location networkLoc = null; 113 private Location gpsLoc = null; 114 private StreetLocator locator = null; 115 116 private int gpsFixCount = 0; 117 private int networkFixCount = 0; 118 private int minFixCount = 0; // lockwood suggested this should be 5, but 5 119 // seems to take way too long 120 121 private There parent; 122 123 private Guide self; 124 private Compass compass; 125 126 public Guide(There parentActivity) { 127 self = this; 128 parent = parentActivity; 129 locator = new StreetLocator(this); 130 LocationManager locationManager = 131 (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE); 132 // Run the dummy listener a bit more often than once per hour to ensure that 133 // the GPS ephemeris data is fresh so that when the location is trying to be 134 // determined, a GPS fix can be acquired quickly. 135 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000000, 0, 136 dummyLocationListener); 137 compass = new Compass(parent); 138 } 139 140 141 public void speakLocation() { 142 LocationManager locationManager = 143 (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE); 144 145 networkLocLastUpdateTime = -1; 146 gpsLocLastUpdateTime = -1; 147 lastLocateTime = 0; 148 networkLoc = null; 149 gpsLoc = null; 150 151 currentLocation = null; 152 currentAddress = ""; 153 currentIntersection = ""; 154 155 if (triedGpsLastTime) { 156 locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, 157 networkLocationListener); 158 triedGpsLastTime = false; 159 } else { 160 locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, 161 gpsLocationListener); 162 triedGpsLastTime = true; 163 } 164 165 String heading = compass.getCurrentHeading(); 166 if (heading.length() > 1) { 167 parent.tts.speak(heading, 0, null); 168 } 169 } 170 171 172 public synchronized void run() { 173 locate(); 174 } 175 176 177 private void locate() { 178 // Ignore all events after the first event if there is a burst of events 179 if (System.currentTimeMillis() - lastLocateTime < 5000) { 180 return; 181 } 182 lastLocateTime = System.currentTimeMillis(); 183 long gpsTimeAdvantage = 300000; 184 currentLocation = null; 185 boolean usingGPS = false; 186 if ((networkLoc == null) && (gpsLoc == null)) { 187 parent.tts.speak("Unable to determine location. Please retry later.", 0, null); 188 return; 189 } else if ((networkLoc == null) && (gpsLoc != null)) { 190 currentLocation = gpsLoc; 191 usingGPS = true; 192 } else if ((networkLoc != null) && (gpsLoc == null)) { 193 currentLocation = networkLoc; 194 } else { 195 if (gpsLocLastUpdateTime + gpsTimeAdvantage > networkLocLastUpdateTime) { 196 currentLocation = gpsLoc; 197 usingGPS = true; 198 } else { 199 currentLocation = networkLoc; 200 } 201 } 202 203 if (usingGPS) { 204 parent.tts.speak("G P S", 1, null); 205 } else { 206 parent.tts.speak("network", 1, null); 207 } 208 if (currentLocation != null) { 209 locator.getAddressAsync(currentLocation.getLatitude(), currentLocation.getLongitude()); 210 } else { 211 if (currentIntersection.length() + currentAddress.length() < 1) { 212 parent.tts.speak("Unable to determine location. Please try again later.", 1, null); 213 } 214 } 215 216 } 217 218 private void unregisterLocationServices() { 219 LocationManager locationManager = 220 (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE); 221 locationManager.removeUpdates(networkLocationListener); 222 locationManager.removeUpdates(gpsLocationListener); 223 gpsFixCount = 0; 224 networkFixCount = 0; 225 } 226 227 public void shutdown() { 228 LocationManager locationManager = 229 (LocationManager) parent.getSystemService(Context.LOCATION_SERVICE); 230 locationManager.removeUpdates(dummyLocationListener); 231 unregisterLocationServices(); 232 compass.shutdown(); 233 } 234 235 private void log(String tag, String message) { 236 // Comment out the following line to turn off logging. 237 Log.i(tag, message); 238 } 239 240 241 private Location currentLocation; 242 private String currentAddress; 243 private String currentIntersection; 244 245 public void onAddressLocated(String address) { 246 currentAddress = ""; 247 if (address.length() > 0) { 248 // Drop the country 249 address = address.substring(0, address.lastIndexOf(",")); 250 // Extract the state and zip and insert spaces in the state name 251 // that the synthesizer will do the right thing. 252 String rawStateZip = address.substring(address.lastIndexOf(",") + 1); 253 String zip = rawStateZip.substring(rawStateZip.lastIndexOf(" ") + 1); 254 String state = rawStateZip.substring(0, rawStateZip.lastIndexOf(" ") + 1); 255 String stateZip = ""; 256 for (int i = 0; i < state.length(); i++) { 257 stateZip = stateZip + state.charAt(i) + " "; 258 } 259 stateZip = stateZip + zip; 260 currentAddress = address.substring(0, address.lastIndexOf(",")) + ". " + stateZip; 261 262 parent.tts.speak("Near " + currentAddress, 1, null); 263 } 264 if (currentLocation != null) { 265 double heading = compass.getCurrentHeadingValue(); 266 if (heading != -1) { 267 locator.getStreetsInFrontAndBackAsync(currentLocation.getLatitude(), currentLocation 268 .getLongitude(), compass.getCurrentHeadingValue()); 269 } 270 } 271 } 272 273 public void onIntersectionLocated(String[] streetnames) { 274 if (streetnames.length == 0) { 275 return; 276 } 277 currentIntersection = ""; 278 for (String ad : streetnames) { 279 if (currentAddress.indexOf(ad) == -1) { 280 currentIntersection += ad + " and "; 281 } 282 } 283 if (currentIntersection.length() > 5) { 284 currentIntersection = currentIntersection.substring(0, currentIntersection.length() - 4); 285 currentIntersection = " Nearby streets are: " + currentIntersection; 286 parent.tts.speak(currentIntersection, 1, null); 287 288 } 289 if (currentIntersection.length() + currentAddress.length() < 1) { 290 parent.tts.speak("Unable to determine address from lat long. Please try again later.", 1, 291 null); 292 } 293 } 294 295 296 public void onFrontBackLocated(String[] streetsFront, String[] streetsBack) { 297 String currentIntersection = ""; 298 boolean spokeSomething = false; 299 if (streetsFront.length > 0) { 300 for (String ad : streetsFront) { 301 if (currentAddress.indexOf(ad) == -1) { 302 currentIntersection += ad + " and "; 303 } 304 } 305 if (currentIntersection.length() > 5) { 306 currentIntersection = currentIntersection.substring(0, currentIntersection.length() - 4); 307 parent.tts.speak("Ahead. " + currentIntersection, 1, null); 308 spokeSomething = true; 309 } 310 } 311 312 currentIntersection = ""; 313 if (streetsBack.length > 0) { 314 for (String ad : streetsBack) { 315 if (currentAddress.indexOf(ad) == -1) { 316 currentIntersection += ad + " and "; 317 } 318 } 319 if (currentIntersection.length() > 5) { 320 currentIntersection = currentIntersection.substring(0, currentIntersection.length() - 4); 321 parent.tts.speak("Behind. " + currentIntersection, 1, null); 322 spokeSomething = true; 323 } 324 } 325 326 if (!spokeSomething) { 327 locator.getStreetIntersectionAsync(currentLocation.getLatitude(), currentLocation 328 .getLongitude()); 329 } 330 } 331 332}