/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

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