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