/walkytalky/src/com/googlecode/eyesfree/walkytalky/PositionStatusNotificationService.java

http://eyes-free.googlecode.com/ · Java · 236 lines · 156 code · 39 blank · 41 comment · 32 complexity · 1271591983a22016c7b4feaaab4f4b93 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.googlecode.eyesfree.walkytalky;
  17. import com.googlecode.eyesfree.walkytalky.Compass.HeadingListener;
  18. import com.googlecode.eyesfree.walkytalky.ReverseGeocoder.OnAddressLocatedListener;
  19. import android.app.Notification;
  20. import android.app.NotificationManager;
  21. import android.app.PendingIntent;
  22. import android.app.Service;
  23. import android.content.Context;
  24. import android.content.Intent;
  25. import android.content.SharedPreferences;
  26. import android.location.GpsStatus;
  27. import android.location.Location;
  28. import android.location.LocationListener;
  29. import android.location.LocationManager;
  30. import android.os.Bundle;
  31. import android.os.IBinder;
  32. import android.preference.PreferenceManager;
  33. import android.speech.tts.TextToSpeech;
  34. /**
  35. * Service that will take the user's current location and place it in the status
  36. * notification bar. Note that if the user is running TalkBack, the location
  37. * will automatically be spoken because of the way TalkBack handles status
  38. * notifications.
  39. *
  40. * @author clchen@google.com (Charles L. Chen)
  41. * @author hiteshk@google.com (Hitesh Khandelwal)
  42. * @author credo@google.com (Tim Credo)
  43. */
  44. public class PositionStatusNotificationService extends Service implements OnAddressLocatedListener {
  45. private boolean needReset = true;
  46. private SharedPreferences mPrefs;
  47. private boolean mSpeak = false;
  48. private TextToSpeech mTts;
  49. private Compass mCompass;
  50. private boolean mPostMessage = true;
  51. private PositionStatusNotificationService self;
  52. NotificationManager mNotificationManager;
  53. long locLastUpdateTime = 0;
  54. long gpsLocLastUpdateTime = 0;
  55. private long locationUpdateWaitTime = 15000;
  56. private LocationManager locationManager;
  57. private ReverseGeocoder locator = null;
  58. private Address lastAddress = null;
  59. private LocationListener locationListener = new LocationListener() {
  60. /*
  61. * Use GPS signal by default, fallbacks to network signal if GPS is
  62. * unavailable
  63. */
  64. public void onLocationChanged(Location location) {
  65. if (locLastUpdateTime + locationUpdateWaitTime < System.currentTimeMillis()) {
  66. locLastUpdateTime = System.currentTimeMillis();
  67. if (location.getProvider().equals("gps")) {
  68. // GPS signal
  69. locator.getAddressAsync(location.getLatitude(), location.getLongitude());
  70. gpsLocLastUpdateTime = System.currentTimeMillis();
  71. } else if (gpsLocLastUpdateTime + 2 * locationUpdateWaitTime < System
  72. .currentTimeMillis()) {
  73. // Network signal
  74. locator.getAddressAsync(location.getLatitude(), location.getLongitude());
  75. }
  76. }
  77. }
  78. public void onProviderDisabled(String arg0) {
  79. locationManager.removeUpdates(locationListener);
  80. gpsLocLastUpdateTime = -1;
  81. locLastUpdateTime = -1;
  82. }
  83. public void onProviderEnabled(String arg0) {
  84. }
  85. public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
  86. }
  87. };
  88. GpsStatus.Listener mGpsStatusListener = new GpsStatus.Listener() {
  89. public void onGpsStatusChanged(int event) {
  90. // This is a dummy listener. It's here because the Motorola Droid
  91. // GPS does not function correctly unless a status listener is set
  92. // for it.
  93. }
  94. };
  95. public HeadingListener mHeadingListener = new HeadingListener() {
  96. @Override
  97. public void onHeadingChanged(String heading) {
  98. if (mPrefs.getBoolean("enable_compass", false) && (mTts != null)) {
  99. mTts.speak("Heading " + heading, 0, null);
  100. }
  101. }
  102. };
  103. @Override
  104. public void onStart(Intent intent, int startId) {
  105. super.onStart(intent, startId);
  106. this.setForeground(true);
  107. String action = intent.getExtras().getString("ACTION");
  108. if (action.equals("STOP")) {
  109. shutdown();
  110. final Service self = this;
  111. this.stopSelf();
  112. return;
  113. }
  114. // Need to do null checks here since it is possible that these
  115. // are already initialized. For example, if the user goes into
  116. // navigation and then turns off the screen.
  117. if (mTts == null) {
  118. mTts = new TextToSpeech(getApplicationContext(), null);
  119. }
  120. if (mPrefs == null) {
  121. mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
  122. }
  123. if (mCompass == null) {
  124. mCompass = new Compass(this, mHeadingListener);
  125. }
  126. if (needReset) {
  127. self = this;
  128. needReset = false;
  129. mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
  130. locator = new ReverseGeocoder(self);
  131. locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
  132. locationManager.requestLocationUpdates(android.location.LocationManager.GPS_PROVIDER,
  133. 1000, 1, locationListener);
  134. locationManager.requestLocationUpdates(
  135. android.location.LocationManager.NETWORK_PROVIDER, 1000, 1, locationListener);
  136. locationManager.addGpsStatusListener(mGpsStatusListener);
  137. }
  138. }
  139. public void onAddressLocated(Address address) {
  140. if (address != null && address.isValid()) {
  141. String addressString = "Near " + address.getStreetNumber() + " " + address.getRoute();
  142. String fullAddress = address.getStreetNumber() + " " + address.getRoute() + ", "
  143. + address.getCity() + ", " + address.getPostalCode();
  144. // If the city or postal code changes, announce the full address.
  145. if (lastAddress == null || !address.getCity().equals(lastAddress.getCity())
  146. || !address.getPostalCode().equals(lastAddress.getPostalCode())) {
  147. addressString = "Near " + fullAddress;
  148. }
  149. lastAddress = address;
  150. sendNotification(addressString, addressString, "", fullAddress);
  151. }
  152. }
  153. public void sendNotification(String ticker, String title, String text, String callbackMsg) {
  154. mSpeak = mPrefs.getBoolean("speak", false);
  155. mPostMessage = mPrefs.getBoolean("post_status", true);
  156. // Post the message to status bar
  157. if (mPostMessage) {
  158. long when = System.currentTimeMillis();
  159. Notification notification = new Notification(android.R.drawable.ic_dialog_map, ticker,
  160. when);
  161. Context context = getApplicationContext();
  162. Intent notificationIntent = new Intent(self, LocationBookmarker.class);
  163. notificationIntent.putExtra("LOCATION", callbackMsg);
  164. PendingIntent contentIntent = PendingIntent.getActivity(self, 0, notificationIntent, 0);
  165. notification.setLatestEventInfo(context, title, text, contentIntent);
  166. mNotificationManager.notify(1, notification);
  167. }
  168. // Speak the text
  169. if (mSpeak) {
  170. mTts.speak(ticker, 0, null);
  171. }
  172. }
  173. @Override
  174. public void onDestroy() {
  175. shutdown();
  176. super.onDestroy();
  177. }
  178. public void shutdown() {
  179. if (locationManager != null) {
  180. locationManager.removeUpdates(locationListener);
  181. }
  182. if (mNotificationManager != null) {
  183. mNotificationManager.cancel(1);
  184. }
  185. if (mTts != null) {
  186. mTts.shutdown();
  187. }
  188. if (mCompass != null) {
  189. mCompass.shutdown();
  190. }
  191. }
  192. @Override
  193. public IBinder onBind(Intent arg0) {
  194. // Do nothing - we will not be binding to this service
  195. return null;
  196. }
  197. }