/actionslib/src/com/google/android/marvin/commands/impls/Guide.java

http://eyes-free.googlecode.com/ · Java · 369 lines · 281 code · 53 blank · 35 comment · 57 complexity · 36ff8847d1088f5b6d12a7e8821a1b99 MD5 · raw file

  1. /*
  2. * Copyright (C) 2010 Google Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.google.android.marvin.commands.impls;
  17. import com.google.android.marvin.actionslib.R;
  18. import com.google.android.marvin.commands.impls.StreetLocator.StreetLocatorListener;
  19. import android.content.Context;
  20. import android.location.GpsStatus;
  21. import android.location.Location;
  22. import android.location.LocationListener;
  23. import android.location.LocationManager;
  24. import android.location.LocationProvider;
  25. import android.os.Bundle;
  26. import android.speech.tts.TextToSpeech;
  27. /**
  28. * Guide uses the magnetic compass, GPS/Network location provider, and the
  29. * Google Maps API to generate a meaningful spoken string to let users know
  30. * where they are.
  31. *
  32. * @author clchen@google.com (Charles L. Chen)
  33. */
  34. public class Guide implements Runnable, StreetLocatorListener {
  35. class GiveUpTimer implements Runnable {
  36. public void run() {
  37. try {
  38. Thread.sleep(10000);
  39. if (!mGotResponse) {
  40. String heading = mCompass.getCurrentHeading();
  41. if (heading.length() > 1) {
  42. mTts.speak(heading, 0, null);
  43. }
  44. mTts.speak("Location not found.", 1, null);
  45. mSelf.shutdown();
  46. }
  47. mGiveUpTimerThread = null;
  48. } catch (InterruptedException e) {
  49. e.printStackTrace();
  50. }
  51. }
  52. }
  53. private LocationListener networkLocationListener = new LocationListener() {
  54. public void onLocationChanged(Location arg0) {
  55. mNetworkLoc = arg0;
  56. mNetworkLocLastUpdateTime = System.currentTimeMillis();
  57. mNetworkFixCount++;
  58. mTts.playEarcon(mContext.getString(R.string.earcon_tock), 1, null);
  59. if (mNetworkFixCount > mMinFixCount) {
  60. mGotResponse = true;
  61. mGiveUpTimerThread = null;
  62. unregisterLocationServices();
  63. log("Network location", "Lat: " + arg0.getLatitude() + ", Long: "
  64. + arg0.getLongitude());
  65. log("Network location", "Accuracy: " + arg0.getAccuracy());
  66. (new Thread(mSelf)).start();
  67. }
  68. }
  69. public void onProviderDisabled(String arg0) {
  70. unregisterLocationServices();
  71. mNetworkLoc = null;
  72. mNetworkLocLastUpdateTime = -1;
  73. }
  74. public void onProviderEnabled(String arg0) {
  75. }
  76. public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
  77. if (arg1 != LocationProvider.AVAILABLE) {
  78. unregisterLocationServices();
  79. mNetworkLoc = null;
  80. mNetworkLocLastUpdateTime = -1;
  81. (new Thread(mSelf)).start();
  82. }
  83. }
  84. };
  85. private LocationListener gpsLocationListener = new LocationListener() {
  86. public void onLocationChanged(Location arg0) {
  87. mGpsLoc = arg0;
  88. mGpsLocLastUpdateTime = System.currentTimeMillis();
  89. mGpsFixCount++;
  90. mTts.playEarcon(mContext.getString(R.string.earcon_tock), 1, null);
  91. if (mGpsFixCount > mMinFixCount) {
  92. mGotResponse = true;
  93. mGiveUpTimerThread = null;
  94. unregisterLocationServices();
  95. log("GPS location", "Lat: " + arg0.getLatitude() + ", Long: "
  96. + arg0.getLongitude());
  97. log("GPS location", "Accuracy: " + arg0.getAccuracy());
  98. (new Thread(mSelf)).start();
  99. }
  100. }
  101. public void onProviderDisabled(String arg0) {
  102. unregisterLocationServices();
  103. mGpsLoc = null;
  104. mGpsLocLastUpdateTime = -1;
  105. }
  106. public void onProviderEnabled(String arg0) {
  107. }
  108. public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
  109. }
  110. };
  111. // This is a fix for the Droid - the status listener must be set or GPS will
  112. // not work right.
  113. GpsStatus.Listener dummyGpsStatusListener = new GpsStatus.Listener() {
  114. public void onGpsStatusChanged(int event) {
  115. }
  116. };
  117. private long mNetworkLocLastUpdateTime = -1;
  118. private long mGpsLocLastUpdateTime = -1;
  119. private long mLastLocateTime = 0;
  120. private Location mNetworkLoc = null;
  121. private Location mGpsLoc = null;
  122. private StreetLocator mLocator = null;
  123. private int mGpsFixCount = 0;
  124. private int mNetworkFixCount = 0;
  125. private int mMinFixCount = 0; // lockwood suggested this should be 5, but 5
  126. // seems to take way too long
  127. private Thread mGiveUpTimerThread = null;
  128. private boolean mGotResponse = false;
  129. private Context mContext;
  130. private Guide mSelf;
  131. private Compass mCompass;
  132. private TextToSpeech mTts;
  133. public Guide(Context parentActivity, TextToSpeech tts) {
  134. mSelf = this;
  135. mContext = parentActivity;
  136. mLocator = new StreetLocator(this);
  137. mCompass = new Compass(mContext);
  138. this.mTts = tts;
  139. LocationManager locationManager = (LocationManager) mContext
  140. .getSystemService(Context.LOCATION_SERVICE);
  141. }
  142. public void speakLocation(boolean useGps) {
  143. if (mGiveUpTimerThread != null) {
  144. mTts.speak("Determining your location.", 0, null);
  145. return;
  146. }
  147. mGiveUpTimerThread = new Thread(new GiveUpTimer());
  148. mGiveUpTimerThread.start();
  149. mGotResponse = false;
  150. LocationManager locationManager = (LocationManager) mContext
  151. .getSystemService(Context.LOCATION_SERVICE);
  152. mNetworkLocLastUpdateTime = -1;
  153. mGpsLocLastUpdateTime = -1;
  154. mLastLocateTime = 0;
  155. mNetworkLoc = null;
  156. mGpsLoc = null;
  157. currentLocation = null;
  158. currentAddress = "";
  159. currentIntersection = "";
  160. if (useGps) {
  161. locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0,
  162. gpsLocationListener);
  163. } else {
  164. locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0,
  165. networkLocationListener);
  166. }
  167. }
  168. public synchronized void run() {
  169. locate();
  170. }
  171. private void locate() {
  172. // Ignore all events after the first event if there is a burst of events
  173. if (System.currentTimeMillis() - mLastLocateTime < 5000) {
  174. return;
  175. }
  176. mLastLocateTime = System.currentTimeMillis();
  177. long gpsTimeAdvantage = 300000;
  178. currentLocation = null;
  179. boolean usingGPS = false;
  180. if ((mNetworkLoc == null) && (mGpsLoc == null)) {
  181. mTts.speak("Location not found.", 1, null);
  182. mSelf.shutdown();
  183. return;
  184. } else if ((mNetworkLoc == null) && (mGpsLoc != null)) {
  185. currentLocation = mGpsLoc;
  186. usingGPS = true;
  187. } else if ((mNetworkLoc != null) && (mGpsLoc == null)) {
  188. currentLocation = mNetworkLoc;
  189. } else {
  190. if (mGpsLocLastUpdateTime + gpsTimeAdvantage > mNetworkLocLastUpdateTime) {
  191. currentLocation = mGpsLoc;
  192. usingGPS = true;
  193. } else {
  194. currentLocation = mNetworkLoc;
  195. }
  196. }
  197. String heading = mCompass.getCurrentHeading();
  198. if (heading.length() > 1) {
  199. mTts.speak(heading, 0, null);
  200. }
  201. if (usingGPS) {
  202. mTts.speak("G P S", 1, null);
  203. } else {
  204. mTts.speak("network", 1, null);
  205. }
  206. if (currentLocation != null) {
  207. mLocator.getAddressAsync(currentLocation.getLatitude(), currentLocation.getLongitude());
  208. } else {
  209. if (currentIntersection.length() + currentAddress.length() < 1) {
  210. mTts.speak("Location not found.", 1, null);
  211. mSelf.shutdown();
  212. }
  213. }
  214. }
  215. private void unregisterLocationServices() {
  216. LocationManager locationManager = (LocationManager) mContext
  217. .getSystemService(Context.LOCATION_SERVICE);
  218. locationManager.removeUpdates(networkLocationListener);
  219. locationManager.removeUpdates(gpsLocationListener);
  220. locationManager.removeGpsStatusListener(dummyGpsStatusListener);
  221. mGpsFixCount = 0;
  222. mNetworkFixCount = 0;
  223. }
  224. public void shutdown() {
  225. unregisterLocationServices();
  226. mCompass.shutdown();
  227. }
  228. private void log(String tag, String message) {
  229. // Comment out the following line to turn off logging.
  230. // Log.i(tag, message);
  231. }
  232. private Location currentLocation;
  233. private String currentAddress;
  234. private String currentIntersection;
  235. public void onAddressLocated(String address) {
  236. currentAddress = "";
  237. if (address.length() > 0) {
  238. // Drop the country
  239. address = address.substring(0, address.lastIndexOf(","));
  240. // Extract the state and zip and insert spaces in the state name
  241. // that the synthesizer will do the right thing.
  242. String rawStateZip = address.substring(address.lastIndexOf(",") + 1);
  243. String zip = rawStateZip.substring(rawStateZip.lastIndexOf(" ") + 1);
  244. String state = rawStateZip.substring(0, rawStateZip.lastIndexOf(" ") + 1);
  245. String stateZip = "";
  246. for (int i = 0; i < state.length(); i++) {
  247. stateZip = stateZip + state.charAt(i) + " ";
  248. }
  249. stateZip = stateZip + zip;
  250. currentAddress = address.substring(0, address.lastIndexOf(",")) + ". " + stateZip;
  251. mTts.speak("Near " + currentAddress, 1, null);
  252. }
  253. // If there was no location, just give up.
  254. // Otherwise, try to get the intersection.
  255. if (currentLocation != null) {
  256. mLocator.getStreetIntersectionAsync(currentLocation.getLatitude(), currentLocation
  257. .getLongitude());
  258. } else {
  259. mSelf.shutdown();
  260. }
  261. }
  262. public void onIntersectionLocated(String[] streetnames) {
  263. if (streetnames.length == 0) {
  264. // No intersection, try to get front/back streets
  265. mLocator.getStreetsInFrontAndBackAsync(currentLocation.getLatitude(), currentLocation
  266. .getLongitude(), mCompass.getCurrentHeadingValue());
  267. return;
  268. }
  269. currentIntersection = "";
  270. for (String ad : streetnames) {
  271. if (currentAddress.indexOf(ad) == -1) {
  272. currentIntersection += ad + " and ";
  273. }
  274. }
  275. if (currentIntersection.length() > 5) {
  276. currentIntersection = currentIntersection
  277. .substring(0, currentIntersection.length() - 4);
  278. currentIntersection = " Nearby streets are: " + currentIntersection;
  279. mTts.speak(currentIntersection, 1, null);
  280. mSelf.shutdown();
  281. } else {
  282. // No intersection, try to get front/back streets
  283. mLocator.getStreetsInFrontAndBackAsync(currentLocation.getLatitude(), currentLocation
  284. .getLongitude(), mCompass.getCurrentHeadingValue());
  285. }
  286. }
  287. public void onFrontBackLocated(String[] streetsFront, String[] streetsBack) {
  288. currentIntersection = "";
  289. if (streetsFront.length > 0) {
  290. for (String ad : streetsFront) {
  291. if (currentAddress.indexOf(ad) == -1) {
  292. currentIntersection += ad + " and ";
  293. }
  294. }
  295. if (currentIntersection.length() > 5) {
  296. currentIntersection = currentIntersection.substring(0,
  297. currentIntersection.length() - 4);
  298. mTts.speak("Ahead. " + currentIntersection, 1, null);
  299. }
  300. }
  301. currentIntersection = "";
  302. if (streetsBack.length > 0) {
  303. for (String ad : streetsBack) {
  304. if (currentAddress.indexOf(ad) == -1) {
  305. currentIntersection += ad + " and ";
  306. }
  307. }
  308. if (currentIntersection.length() > 5) {
  309. currentIntersection = currentIntersection.substring(0,
  310. currentIntersection.length() - 4);
  311. mTts.speak("Behind. " + currentIntersection, 1, null);
  312. }
  313. }
  314. mSelf.shutdown();
  315. }
  316. }