PageRenderTime 41ms CodeModel.GetById 15ms app.highlight 22ms RepoModel.GetById 1ms app.codeStats 0ms

/there/src/com/google/marvin/there/Guide.java

http://eyes-free.googlecode.com/
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}