PageRenderTime 50ms CodeModel.GetById 1ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 0ms

/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 */
 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}