LocationManager.java revision f5d95cbc1a6974afeb4d3155bdaa8dae55722a39
13a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams/* 23a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * Copyright (C) 2007 The Android Open Source Project 33a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * 43a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * Licensed under the Apache License, Version 2.0 (the "License"); 53a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * you may not use this file except in compliance with the License. 63a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * You may obtain a copy of the License at 73a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * 83a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * http://www.apache.org/licenses/LICENSE-2.0 93a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * 103a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * Unless required by applicable law or agreed to in writing, software 113a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * distributed under the License is distributed on an "AS IS" BASIS, 123a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * See the License for the specific language governing permissions and 143a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * limitations under the License. 153a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams */ 163a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams 173a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samspackage android.location; 183a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams 193a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport android.app.PendingIntent; 2080d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.content.Intent; 2180d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.os.Bundle; 2280d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.os.Looper; 2380d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.os.RemoteException; 243a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport android.os.Handler; 2580d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.os.Message; 2680d819033d4687507907f787d47379b7b37eae19Jason Samsimport android.util.Log; 273a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams 283a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport com.android.internal.location.DummyLocationProvider; 29460a04971c494fec39ffcb38e873bb8fdd82d113Tim Murray 303a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport java.util.ArrayList; 313a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport java.util.Collections; 323a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport java.util.Comparator; 333a5b8011765906c15b5474b2bc43d80f6746cb45Jason Samsimport java.util.HashMap; 3480d819033d4687507907f787d47379b7b37eae19Jason Samsimport java.util.List; 3580d819033d4687507907f787d47379b7b37eae19Jason Sams 363a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams/** 3780d819033d4687507907f787d47379b7b37eae19Jason Sams * This class provides access to the system location services. These 383a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * services allow applications to obtain periodic updates of the 39c11e25c4e653124def1fb18e203b894f42106cbeTim Murray * device's geographical location, or to fire an application-specified 4080d819033d4687507907f787d47379b7b37eae19Jason Sams * {@link Intent} when the device enters the proximity of a given 413a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * geographical location. 4280d819033d4687507907f787d47379b7b37eae19Jason Sams * 433a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * <p>You do not 443a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * instantiate this class directly; instead, retrieve it through 45bddc7ffb5203602e6e84941b1840aef5d606bcb4Tim Murray * {@link android.content.Context#getSystemService 4680d819033d4687507907f787d47379b7b37eae19Jason Sams * Context.getSystemService(Context.LOCATION_SERVICE)}. 4780d819033d4687507907f787d47379b7b37eae19Jason Sams */ 48460a04971c494fec39ffcb38e873bb8fdd82d113Tim Murraypublic class LocationManager { 4980d819033d4687507907f787d47379b7b37eae19Jason Sams private static final String TAG = "LocationManager"; 5080d819033d4687507907f787d47379b7b37eae19Jason Sams private ILocationManager mService; 5180d819033d4687507907f787d47379b7b37eae19Jason Sams private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners = 523a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>(); 533a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners = 5480d819033d4687507907f787d47379b7b37eae19Jason Sams new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>(); 5580d819033d4687507907f787d47379b7b37eae19Jason Sams private final GpsStatus mGpsStatus = new GpsStatus(); 5680d819033d4687507907f787d47379b7b37eae19Jason Sams 5780d819033d4687507907f787d47379b7b37eae19Jason Sams /** 5880d819033d4687507907f787d47379b7b37eae19Jason Sams * Name of the network location provider. This provider determines location based on 5980d819033d4687507907f787d47379b7b37eae19Jason Sams * availability of cell tower and WiFi access points. Results are retrieved 603a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * by means of a network lookup. 613a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * 62e6a7886674c167b4e17f6dc72d41d5b9c604cdd1Jason Sams * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION 633a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * or android.permission.ACCESS_FINE_LOCATION. 643a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams */ 6580d819033d4687507907f787d47379b7b37eae19Jason Sams public static final String NETWORK_PROVIDER = "network"; 6680d819033d4687507907f787d47379b7b37eae19Jason Sams 6780d819033d4687507907f787d47379b7b37eae19Jason Sams /** 6831864d76a3624f2c5908218b32bf09051b1b9d24Jason Sams * Name of the GPS location provider. This provider determines location using 6980d819033d4687507907f787d47379b7b37eae19Jason Sams * satellites. Depending on conditions, this provider may take a while to return 7080d819033d4687507907f787d47379b7b37eae19Jason Sams * a location fix. 7180d819033d4687507907f787d47379b7b37eae19Jason Sams * 7280d819033d4687507907f787d47379b7b37eae19Jason Sams * Requires the permission android.permission.ACCESS_FINE_LOCATION. 7331864d76a3624f2c5908218b32bf09051b1b9d24Jason Sams * 7431864d76a3624f2c5908218b32bf09051b1b9d24Jason Sams * <p> The extras Bundle for the GPS location provider can contain the 753a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * following key/value pairs: 7680d819033d4687507907f787d47379b7b37eae19Jason Sams * 773a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * <ul> 783a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams * <li> satellites - the number of satellites used to derive the fix 7980d819033d4687507907f787d47379b7b37eae19Jason Sams * </ul> 8080d819033d4687507907f787d47379b7b37eae19Jason Sams */ 8180d819033d4687507907f787d47379b7b37eae19Jason Sams public static final String GPS_PROVIDER = "gps"; 8280d819033d4687507907f787d47379b7b37eae19Jason Sams 8380d819033d4687507907f787d47379b7b37eae19Jason Sams /** 8480d819033d4687507907f787d47379b7b37eae19Jason Sams * Key used for the Bundle extra holding a boolean indicating whether 8580d819033d4687507907f787d47379b7b37eae19Jason Sams * a proximity alert is entering (true) or exiting (false).. 863a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams */ 87949610653fdf55dd2cb3c846047e6aa2c6d73f0dChris Wailes public static final String KEY_PROXIMITY_ENTERING = "entering"; 883a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams 893a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams /** 9008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams * Key used for a Bundle extra holding an Integer status value 916f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray * when a status change is broadcast using a PendingIntent. 926f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray */ 936f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray public static final String KEY_STATUS_CHANGED = "status"; 946f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray 956f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray /** 966f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray * Key used for a Bundle extra holding an Boolean status value 976f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray * when a provider enabled/disabled event is broadcast using a PendingIntent. 986f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray */ 9948ba506dfa591d0bcd79a088457eb95a9bd4c575Stephen Hines public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; 1006f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray 1016f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray /** 1026f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray * Key used for a Bundle extra holding a Location value 1036f842ac8aa37dd855fbffdc09f5491bd85ab3c9aTim Murray * when a location change is broadcast using a PendingIntent. 10408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams */ 10508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public static final String KEY_LOCATION_CHANGED = "location"; 10608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 10708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams public interface GeocodeProvider { 10808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams String getFromLocation(double latitude, double longitude, int maxResults, 10908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams GeocoderParams params, List<Address> addrs); 11008a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 11108a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams String getFromLocationName(String locationName, 11208a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams double lowerLeftLatitude, double lowerLeftLongitude, 11308a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams double upperRightLatitude, double upperRightLongitude, int maxResults, 11408a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams GeocoderParams params, List<Address> addrs); 11508a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams } 11608a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 11708a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private static final class GeocodeProviderProxy extends IGeocodeProvider.Stub { 11808a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams private GeocodeProvider mProvider; 11908a81583c18a849e442ceeb8d7baeca743fb3be8Jason Sams 1203a5b8011765906c15b5474b2bc43d80f6746cb45Jason Sams GeocodeProviderProxy(GeocodeProvider provider) { 121 mProvider = provider; 122 } 123 124 /** 125 * This method is overridden to implement the 126 * {@link Geocoder#getFromLocation(double, double, int)} method. 127 * Classes implementing this method should not hold a reference to the params parameter. 128 */ 129 public String getFromLocation(double latitude, double longitude, int maxResults, 130 GeocoderParams params, List<Address> addrs) { 131 return mProvider.getFromLocation(latitude, longitude, maxResults, params, addrs); 132 } 133 134 /** 135 * This method is overridden to implement the 136 * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method. 137 * Classes implementing this method should not hold a reference to the params parameter. 138 */ 139 public String getFromLocationName(String locationName, 140 double lowerLeftLatitude, double lowerLeftLongitude, 141 double upperRightLatitude, double upperRightLongitude, int maxResults, 142 GeocoderParams params, List<Address> addrs) { 143 return mProvider.getFromLocationName(locationName, lowerLeftLatitude, 144 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, 145 maxResults, params, addrs); 146 } 147 } 148 149 // Map from LocationListeners to their associated ListenerTransport objects 150 private HashMap<LocationListener,ListenerTransport> mListeners = 151 new HashMap<LocationListener,ListenerTransport>(); 152 153 private class ListenerTransport extends ILocationListener.Stub { 154 private static final int TYPE_LOCATION_CHANGED = 1; 155 private static final int TYPE_STATUS_CHANGED = 2; 156 private static final int TYPE_PROVIDER_ENABLED = 3; 157 private static final int TYPE_PROVIDER_DISABLED = 4; 158 159 private LocationListener mListener; 160 private final Handler mListenerHandler; 161 162 ListenerTransport(LocationListener listener, Looper looper) { 163 mListener = listener; 164 165 if (looper == null) { 166 mListenerHandler = new Handler() { 167 @Override 168 public void handleMessage(Message msg) { 169 _handleMessage(msg); 170 } 171 }; 172 } else { 173 mListenerHandler = new Handler(looper) { 174 @Override 175 public void handleMessage(Message msg) { 176 _handleMessage(msg); 177 } 178 }; 179 } 180 } 181 182 public void onLocationChanged(Location location) { 183 Message msg = Message.obtain(); 184 msg.what = TYPE_LOCATION_CHANGED; 185 msg.obj = location; 186 mListenerHandler.sendMessage(msg); 187 } 188 189 public void onStatusChanged(String provider, int status, Bundle extras) { 190 Message msg = Message.obtain(); 191 msg.what = TYPE_STATUS_CHANGED; 192 Bundle b = new Bundle(); 193 b.putString("provider", provider); 194 b.putInt("status", status); 195 if (extras != null) { 196 b.putBundle("extras", extras); 197 } 198 msg.obj = b; 199 mListenerHandler.sendMessage(msg); 200 } 201 202 public void onProviderEnabled(String provider) { 203 Message msg = Message.obtain(); 204 msg.what = TYPE_PROVIDER_ENABLED; 205 msg.obj = provider; 206 mListenerHandler.sendMessage(msg); 207 } 208 209 public void onProviderDisabled(String provider) { 210 Message msg = Message.obtain(); 211 msg.what = TYPE_PROVIDER_DISABLED; 212 msg.obj = provider; 213 mListenerHandler.sendMessage(msg); 214 } 215 216 private void _handleMessage(Message msg) { 217 switch (msg.what) { 218 case TYPE_LOCATION_CHANGED: 219 Location location = new Location((Location) msg.obj); 220 mListener.onLocationChanged(location); 221 break; 222 case TYPE_STATUS_CHANGED: 223 Bundle b = (Bundle) msg.obj; 224 String provider = b.getString("provider"); 225 int status = b.getInt("status"); 226 Bundle extras = b.getBundle("extras"); 227 mListener.onStatusChanged(provider, status, extras); 228 break; 229 case TYPE_PROVIDER_ENABLED: 230 mListener.onProviderEnabled((String) msg.obj); 231 break; 232 case TYPE_PROVIDER_DISABLED: 233 mListener.onProviderDisabled((String) msg.obj); 234 break; 235 } 236 try { 237 mService.locationCallbackFinished(this); 238 } catch (RemoteException e) { 239 Log.e(TAG, "locationCallbackFinished: RemoteException", e); 240 } 241 } 242 } 243 /** 244 * @hide - hide this constructor because it has a parameter 245 * of type ILocationManager, which is a system private class. The 246 * right way to create an instance of this class is using the 247 * factory Context.getSystemService. 248 */ 249 public LocationManager(ILocationManager service) { 250 if (false) { 251 Log.d(TAG, "Constructor: service = " + service); 252 } 253 mService = service; 254 } 255 256 private LocationProvider createProvider(String name, Bundle info) { 257 DummyLocationProvider provider = 258 new DummyLocationProvider(name); 259 provider.setRequiresNetwork(info.getBoolean("network")); 260 provider.setRequiresSatellite(info.getBoolean("satellite")); 261 provider.setRequiresCell(info.getBoolean("cell")); 262 provider.setHasMonetaryCost(info.getBoolean("cost")); 263 provider.setSupportsAltitude(info.getBoolean("altitude")); 264 provider.setSupportsSpeed(info.getBoolean("speed")); 265 provider.setSupportsBearing(info.getBoolean("bearing")); 266 provider.setPowerRequirement(info.getInt("power")); 267 provider.setAccuracy(info.getInt("accuracy")); 268 return provider; 269 } 270 271 /** 272 * Returns a list of the names of all known location providers. All 273 * providers are returned, including ones that are not permitted to be 274 * accessed by the calling activity or are currently disabled. 275 * 276 * @return list of Strings containing names of the providers 277 */ 278 public List<String> getAllProviders() { 279 if (false) { 280 Log.d(TAG, "getAllProviders"); 281 } 282 try { 283 return mService.getAllProviders(); 284 } catch (RemoteException ex) { 285 Log.e(TAG, "getAllProviders: RemoteException", ex); 286 } 287 return null; 288 } 289 290 /** 291 * Returns a list of the names of location providers. Only providers that 292 * are permitted to be accessed by the calling activity will be returned. 293 * 294 * @param enabledOnly if true then only the providers which are currently 295 * enabled are returned. 296 * @return list of Strings containing names of the providers 297 */ 298 public List<String> getProviders(boolean enabledOnly) { 299 try { 300 return mService.getProviders(enabledOnly); 301 } catch (RemoteException ex) { 302 Log.e(TAG, "getProviders: RemoteException", ex); 303 } 304 return null; 305 } 306 307 /** 308 * Returns the information associated with the location provider of the 309 * given name, or null if no provider exists by that name. 310 * 311 * @param name the provider name 312 * @return a LocationProvider, or null 313 * 314 * @throws IllegalArgumentException if name is null 315 * @throws SecurityException if the caller is not permitted to access the 316 * given provider. 317 */ 318 public LocationProvider getProvider(String name) { 319 if (name == null) { 320 throw new IllegalArgumentException("name==null"); 321 } 322 try { 323 Bundle info = mService.getProviderInfo(name); 324 if (info == null) { 325 return null; 326 } 327 return createProvider(name, info); 328 } catch (RemoteException ex) { 329 Log.e(TAG, "getProvider: RemoteException", ex); 330 } 331 return null; 332 } 333 334 /** 335 * Returns a list of the names of LocationProviders that satisfy the given 336 * criteria, or null if none do. Only providers that are permitted to be 337 * accessed by the calling activity will be returned. 338 * 339 * @param criteria the criteria that the returned providers must match 340 * @param enabledOnly if true then only the providers which are currently 341 * enabled are returned. 342 * @return list of Strings containing names of the providers 343 */ 344 public List<String> getProviders(Criteria criteria, boolean enabledOnly) { 345 List<String> goodProviders = Collections.emptyList(); 346 List<String> providers = getProviders(enabledOnly); 347 for (String providerName : providers) { 348 LocationProvider provider = getProvider(providerName); 349 if (provider.meetsCriteria(criteria)) { 350 if (goodProviders.isEmpty()) { 351 goodProviders = new ArrayList<String>(); 352 } 353 goodProviders.add(providerName); 354 } 355 } 356 return goodProviders; 357 } 358 359 /** 360 * Returns the next looser power requirement, in the sequence: 361 * 362 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT 363 */ 364 private int nextPower(int power) { 365 switch (power) { 366 case Criteria.POWER_LOW: 367 return Criteria.POWER_MEDIUM; 368 case Criteria.POWER_MEDIUM: 369 return Criteria.POWER_HIGH; 370 case Criteria.POWER_HIGH: 371 return Criteria.NO_REQUIREMENT; 372 case Criteria.NO_REQUIREMENT: 373 default: 374 return Criteria.NO_REQUIREMENT; 375 } 376 } 377 378 /** 379 * Returns the next looser accuracy requirement, in the sequence: 380 * 381 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT 382 */ 383 private int nextAccuracy(int accuracy) { 384 if (accuracy == Criteria.ACCURACY_FINE) { 385 return Criteria.ACCURACY_COARSE; 386 } else { 387 return Criteria.NO_REQUIREMENT; 388 } 389 } 390 391 private abstract class LpComparator implements Comparator<LocationProvider> { 392 393 public int compare(int a1, int a2) { 394 if (a1 < a2) { 395 return -1; 396 } else if (a1 > a2) { 397 return 1; 398 } else { 399 return 0; 400 } 401 } 402 403 public int compare(float a1, float a2) { 404 if (a1 < a2) { 405 return -1; 406 } else if (a1 > a2) { 407 return 1; 408 } else { 409 return 0; 410 } 411 } 412 } 413 414 private class LpPowerComparator extends LpComparator { 415 public int compare(LocationProvider l1, LocationProvider l2) { 416 int a1 = l1.getPowerRequirement(); 417 int a2 = l2.getPowerRequirement(); 418 return compare(a1, a2); // Smaller is better 419 } 420 421 public boolean equals(LocationProvider l1, LocationProvider l2) { 422 int a1 = l1.getPowerRequirement(); 423 int a2 = l2.getPowerRequirement(); 424 return a1 == a2; 425 } 426 } 427 428 private class LpAccuracyComparator extends LpComparator { 429 public int compare(LocationProvider l1, LocationProvider l2) { 430 int a1 = l1.getAccuracy(); 431 int a2 = l2.getAccuracy(); 432 return compare(a1, a2); // Smaller is better 433 } 434 435 public boolean equals(LocationProvider l1, LocationProvider l2) { 436 int a1 = l1.getAccuracy(); 437 int a2 = l2.getAccuracy(); 438 return a1 == a2; 439 } 440 } 441 442 private class LpCapabilityComparator extends LpComparator { 443 444 private static final int ALTITUDE_SCORE = 4; 445 private static final int BEARING_SCORE = 4; 446 private static final int SPEED_SCORE = 4; 447 448 private int score(LocationProvider p) { 449 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + 450 (p.supportsBearing() ? BEARING_SCORE : 0) + 451 (p.supportsSpeed() ? SPEED_SCORE : 0); 452 } 453 454 public int compare(LocationProvider l1, LocationProvider l2) { 455 int a1 = score(l1); 456 int a2 = score(l2); 457 return compare(-a1, -a2); // Bigger is better 458 } 459 460 public boolean equals(LocationProvider l1, LocationProvider l2) { 461 int a1 = score(l1); 462 int a2 = score(l2); 463 return a1 == a2; 464 } 465 } 466 467 private LocationProvider best(List<String> providerNames) { 468 List<LocationProvider> providers = new ArrayList<LocationProvider>(providerNames.size()); 469 for (String name : providerNames) { 470 providers.add(getProvider(name)); 471 } 472 473 if (providers.size() < 2) { 474 return providers.get(0); 475 } 476 477 // First, sort by power requirement 478 Collections.sort(providers, new LpPowerComparator()); 479 int power = providers.get(0).getPowerRequirement(); 480 if (power < providers.get(1).getPowerRequirement()) { 481 return providers.get(0); 482 } 483 484 int idx, size; 485 486 List<LocationProvider> tmp = new ArrayList<LocationProvider>(); 487 idx = 0; 488 size = providers.size(); 489 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { 490 tmp.add(providers.get(idx)); 491 idx++; 492 } 493 494 // Next, sort by accuracy 495 Collections.sort(tmp, new LpAccuracyComparator()); 496 int acc = tmp.get(0).getAccuracy(); 497 if (acc < tmp.get(1).getAccuracy()) { 498 return tmp.get(0); 499 } 500 501 List<LocationProvider> tmp2 = new ArrayList<LocationProvider>(); 502 idx = 0; 503 size = tmp.size(); 504 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { 505 tmp2.add(tmp.get(idx)); 506 idx++; 507 } 508 509 // Finally, sort by capability "score" 510 Collections.sort(tmp2, new LpCapabilityComparator()); 511 return tmp2.get(0); 512 } 513 514 /** 515 * Returns the name of the provider that best meets the given criteria. Only providers 516 * that are permitted to be accessed by the calling activity will be 517 * returned. If several providers meet the criteria, the one with the best 518 * accuracy is returned. If no provider meets the criteria, 519 * the criteria are loosened in the following sequence: 520 * 521 * <ul> 522 * <li> power requirement 523 * <li> accuracy 524 * <li> bearing 525 * <li> speed 526 * <li> altitude 527 * </ul> 528 * 529 * <p> Note that the requirement on monetary cost is not removed 530 * in this process. 531 * 532 * @param criteria the criteria that need to be matched 533 * @param enabledOnly if true then only a provider that is currently enabled is returned 534 * @return name of the provider that best matches the requirements 535 */ 536 public String getBestProvider(Criteria criteria, boolean enabledOnly) { 537 List<String> goodProviders = getProviders(criteria, enabledOnly); 538 if (!goodProviders.isEmpty()) { 539 return best(goodProviders).getName(); 540 } 541 542 // Make a copy of the criteria that we can modify 543 criteria = new Criteria(criteria); 544 545 // Loosen power requirement 546 int power = criteria.getPowerRequirement(); 547 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { 548 power = nextPower(power); 549 criteria.setPowerRequirement(power); 550 goodProviders = getProviders(criteria, enabledOnly); 551 } 552 if (!goodProviders.isEmpty()) { 553 return best(goodProviders).getName(); 554 } 555 556// // Loosen response time requirement 557// int responseTime = criteria.getPreferredResponseTime(); 558// while (goodProviders.isEmpty() && 559// (responseTime != Criteria.NO_REQUIREMENT)) { 560// responseTime += 1000; 561// if (responseTime > 60000) { 562// responseTime = Criteria.NO_REQUIREMENT; 563// } 564// criteria.setPreferredResponseTime(responseTime); 565// goodProviders = getProviders(criteria); 566// } 567// if (!goodProviders.isEmpty()) { 568// return best(goodProviders); 569// } 570 571 // Loosen accuracy requirement 572 int accuracy = criteria.getAccuracy(); 573 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { 574 accuracy = nextAccuracy(accuracy); 575 criteria.setAccuracy(accuracy); 576 goodProviders = getProviders(criteria, enabledOnly); 577 } 578 if (!goodProviders.isEmpty()) { 579 return best(goodProviders).getName(); 580 } 581 582 // Remove bearing requirement 583 criteria.setBearingRequired(false); 584 goodProviders = getProviders(criteria, enabledOnly); 585 if (!goodProviders.isEmpty()) { 586 return best(goodProviders).getName(); 587 } 588 589 // Remove speed requirement 590 criteria.setSpeedRequired(false); 591 goodProviders = getProviders(criteria, enabledOnly); 592 if (!goodProviders.isEmpty()) { 593 return best(goodProviders).getName(); 594 } 595 596 // Remove altitude requirement 597 criteria.setAltitudeRequired(false); 598 goodProviders = getProviders(criteria, enabledOnly); 599 if (!goodProviders.isEmpty()) { 600 return best(goodProviders).getName(); 601 } 602 603 return null; 604 } 605 606 /** 607 * Registers the current activity to be notified periodically by 608 * the named provider. Periodically, the supplied LocationListener will 609 * be called with the current Location or with status updates. 610 * 611 * <p> It may take a while to receive the most recent location. If 612 * an immediate location is required, applications may use the 613 * {@link #getLastKnownLocation(String)} method. 614 * 615 * <p> In case the provider is disabled by the user, updates will stop, 616 * and the {@link LocationListener#onProviderDisabled(String)} 617 * method will be called. As soon as the provider is enabled again, 618 * the {@link LocationListener#onProviderEnabled(String)} method will 619 * be called and location updates will start again. 620 * 621 * <p> The frequency of notification may be controlled using the 622 * minTime and minDistance parameters. If minTime is greater than 0, 623 * the LocationManager could potentially rest for minTime milliseconds 624 * between location updates to conserve power. If minDistance is greater than 0, 625 * a location will only be broadcasted if the device moves by minDistance meters. 626 * To obtain notifications as frequently as possible, set both parameters to 0. 627 * 628 * <p> Background services should be careful about setting a sufficiently high 629 * minTime so that the device doesn't consume too much power by keeping the 630 * GPS or wireless radios on all the time. In particular, values under 60000ms 631 * are not recommended. 632 * 633 * <p> The calling thread must be a {@link android.os.Looper} thread such as 634 * the main thread of the calling Activity. 635 * 636 * @param provider the name of the provider with which to register 637 * @param minTime the minimum time interval for notifications, in 638 * milliseconds. This field is only used as a hint to conserve power, and actual 639 * time between location updates may be greater or lesser than this value. 640 * @param minDistance the minimum distance interval for notifications, 641 * in meters 642 * @param listener a {#link LocationListener} whose 643 * {@link LocationListener#onLocationChanged} method will be called for 644 * each location update 645 * 646 * @throws IllegalArgumentException if provider is null or doesn't exist 647 * @throws IllegalArgumentException if listener is null 648 * @throws RuntimeException if the calling thread has no Looper 649 * @throws SecurityException if no suitable permission is present for the provider. 650 */ 651 public void requestLocationUpdates(String provider, 652 long minTime, float minDistance, LocationListener listener) { 653 if (provider == null) { 654 throw new IllegalArgumentException("provider==null"); 655 } 656 if (listener == null) { 657 throw new IllegalArgumentException("listener==null"); 658 } 659 _requestLocationUpdates(provider, minTime, minDistance, listener, null); 660 } 661 662 /** 663 * Registers the current activity to be notified periodically by 664 * the named provider. Periodically, the supplied LocationListener will 665 * be called with the current Location or with status updates. 666 * 667 * <p> It may take a while to receive the most recent location. If 668 * an immediate location is required, applications may use the 669 * {@link #getLastKnownLocation(String)} method. 670 * 671 * <p> In case the provider is disabled by the user, updates will stop, 672 * and the {@link LocationListener#onProviderDisabled(String)} 673 * method will be called. As soon as the provider is enabled again, 674 * the {@link LocationListener#onProviderEnabled(String)} method will 675 * be called and location updates will start again. 676 * 677 * <p> The frequency of notification may be controlled using the 678 * minTime and minDistance parameters. If minTime is greater than 0, 679 * the LocationManager could potentially rest for minTime milliseconds 680 * between location updates to conserve power. If minDistance is greater than 0, 681 * a location will only be broadcasted if the device moves by minDistance meters. 682 * To obtain notifications as frequently as possible, set both parameters to 0. 683 * 684 * <p> Background services should be careful about setting a sufficiently high 685 * minTime so that the device doesn't consume too much power by keeping the 686 * GPS or wireless radios on all the time. In particular, values under 60000ms 687 * are not recommended. 688 * 689 * <p> The supplied Looper is used to implement the callback mechanism. 690 * 691 * @param provider the name of the provider with which to register 692 * @param minTime the minimum time interval for notifications, in 693 * milliseconds. This field is only used as a hint to conserve power, and actual 694 * time between location updates may be greater or lesser than this value. 695 * @param minDistance the minimum distance interval for notifications, 696 * in meters 697 * @param listener a {#link LocationListener} whose 698 * {@link LocationListener#onLocationChanged} method will be called for 699 * each location update 700 * @param looper a Looper object whose message queue will be used to 701 * implement the callback mechanism. 702 * 703 * @throws IllegalArgumentException if provider is null or doesn't exist 704 * @throws IllegalArgumentException if listener is null 705 * @throws IllegalArgumentException if looper is null 706 * @throws SecurityException if no suitable permission is present for the provider. 707 */ 708 public void requestLocationUpdates(String provider, 709 long minTime, float minDistance, LocationListener listener, 710 Looper looper) { 711 if (provider == null) { 712 throw new IllegalArgumentException("provider==null"); 713 } 714 if (listener == null) { 715 throw new IllegalArgumentException("listener==null"); 716 } 717 if (looper == null) { 718 throw new IllegalArgumentException("looper==null"); 719 } 720 _requestLocationUpdates(provider, minTime, minDistance, listener, looper); 721 } 722 723 private void _requestLocationUpdates(String provider, 724 long minTime, float minDistance, LocationListener listener, 725 Looper looper) { 726 if (minTime < 0L) { 727 minTime = 0L; 728 } 729 if (minDistance < 0.0f) { 730 minDistance = 0.0f; 731 } 732 733 try { 734 synchronized (mListeners) { 735 ListenerTransport transport = mListeners.get(listener); 736 if (transport == null) { 737 transport = new ListenerTransport(listener, looper); 738 } 739 mListeners.put(listener, transport); 740 mService.requestLocationUpdates(provider, minTime, minDistance, transport); 741 } 742 } catch (RemoteException ex) { 743 Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex); 744 } 745 } 746 747 /** 748 * Registers the current activity to be notified periodically by 749 * the named provider. Periodically, the supplied PendingIntent will 750 * be broadcast with the current Location or with status updates. 751 * 752 * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. 753 * 754 * <p> It may take a while to receive the most recent location. If 755 * an immediate location is required, applications may use the 756 * {@link #getLastKnownLocation(String)} method. 757 * 758 * <p> The frequency of notification or new locations may be controlled using the 759 * minTime and minDistance parameters. If minTime is greater than 0, 760 * the LocationManager could potentially rest for minTime milliseconds 761 * between location updates to conserve power. If minDistance is greater than 0, 762 * a location will only be broadcast if the device moves by minDistance meters. 763 * To obtain notifications as frequently as possible, set both parameters to 0. 764 * 765 * <p> Background services should be careful about setting a sufficiently high 766 * minTime so that the device doesn't consume too much power by keeping the 767 * GPS or wireless radios on all the time. In particular, values under 60000ms 768 * are not recommended. 769 * 770 * <p> In case the provider is disabled by the user, updates will stop, 771 * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value 772 * of false. If the provider is re-enabled, an intent will be sent with an 773 * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will 774 * start again. 775 * 776 * <p> If the provider's status changes, an intent will be sent with an extra with key 777 * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated 778 * with the status update will be sent as well. 779 * 780 * @param provider the name of the provider with which to register 781 * @param minTime the minimum time interval for notifications, in 782 * milliseconds. This field is only used as a hint to conserve power, and actual 783 * time between location updates may be greater or lesser than this value. 784 * @param minDistance the minimum distance interval for notifications, 785 * in meters 786 * @param intent a {#link PendingIntet} to be sent for each location update 787 * 788 * @throws IllegalArgumentException if provider is null or doesn't exist 789 * @throws IllegalArgumentException if intent is null 790 * @throws SecurityException if no suitable permission is present for the provider. 791 */ 792 public void requestLocationUpdates(String provider, 793 long minTime, float minDistance, PendingIntent intent) { 794 if (provider == null) { 795 throw new IllegalArgumentException("provider==null"); 796 } 797 if (intent == null) { 798 throw new IllegalArgumentException("intent==null"); 799 } 800 _requestLocationUpdates(provider, minTime, minDistance, intent); 801 } 802 803 private void _requestLocationUpdates(String provider, 804 long minTime, float minDistance, PendingIntent intent) { 805 if (minTime < 0L) { 806 minTime = 0L; 807 } 808 if (minDistance < 0.0f) { 809 minDistance = 0.0f; 810 } 811 812 try { 813 mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent); 814 } catch (RemoteException ex) { 815 Log.e(TAG, "requestLocationUpdates: RemoteException", ex); 816 } 817 } 818 819 /** 820 * Removes any current registration for location updates of the current activity 821 * with the given LocationListener. Following this call, updates will no longer 822 * occur for this listener. 823 * 824 * @param listener {#link LocationListener} object that no longer needs location updates 825 * @throws IllegalArgumentException if listener is null 826 */ 827 public void removeUpdates(LocationListener listener) { 828 if (listener == null) { 829 throw new IllegalArgumentException("listener==null"); 830 } 831 if (false) { 832 Log.d(TAG, "removeUpdates: listener = " + listener); 833 } 834 try { 835 ListenerTransport transport = mListeners.remove(listener); 836 if (transport != null) { 837 mService.removeUpdates(transport); 838 } 839 } catch (RemoteException ex) { 840 Log.e(TAG, "removeUpdates: DeadObjectException", ex); 841 } 842 } 843 844 /** 845 * Removes any current registration for location updates of the current activity 846 * with the given PendingIntent. Following this call, updates will no longer 847 * occur for this intent. 848 * 849 * @param intent {#link PendingIntent} object that no longer needs location updates 850 * @throws IllegalArgumentException if intent is null 851 */ 852 public void removeUpdates(PendingIntent intent) { 853 if (intent == null) { 854 throw new IllegalArgumentException("intent==null"); 855 } 856 if (false) { 857 Log.d(TAG, "removeUpdates: intent = " + intent); 858 } 859 try { 860 mService.removeUpdatesPI(intent); 861 } catch (RemoteException ex) { 862 Log.e(TAG, "removeUpdates: RemoteException", ex); 863 } 864 } 865 866 /** 867 * Sets a proximity alert for the location given by the position 868 * (latitude, longitude) and the given radius. When the device 869 * detects that it has entered or exited the area surrounding the 870 * location, the given PendingIntent will be used to create an Intent 871 * to be fired. 872 * 873 * <p> The fired Intent will have a boolean extra added with key 874 * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is 875 * entering the proximity region; if false, it is exiting. 876 * 877 * <p> Due to the approximate nature of position estimation, if the 878 * device passes through the given area briefly, it is possible 879 * that no Intent will be fired. Similarly, an Intent could be 880 * fired if the device passes very close to the given area but 881 * does not actually enter it. 882 * 883 * <p> After the number of milliseconds given by the expiration 884 * parameter, the location manager will delete this proximity 885 * alert and no longer monitor it. A value of -1 indicates that 886 * there should be no expiration time. 887 * 888 * <p> In case the screen goes to sleep, checks for proximity alerts 889 * happen only once every 4 minutes. This conserves battery life by 890 * ensuring that the device isn't perpetually awake. 891 * 892 * <p> Internally, this method uses both {@link #NETWORK_PROVIDER} 893 * and {@link #GPS_PROVIDER}. 894 * 895 * @param latitude the latitude of the central point of the 896 * alert region 897 * @param longitude the longitude of the central point of the 898 * alert region 899 * @param radius the radius of the central point of the 900 * alert region, in meters 901 * @param expiration time for this proximity alert, in milliseconds, 902 * or -1 to indicate no expiration 903 * @param intent a PendingIntent that will be used to generate an Intent to 904 * fire when entry to or exit from the alert region is detected 905 * 906 * @throws SecurityException if no permission exists for the required 907 * providers. 908 */ 909 public void addProximityAlert(double latitude, double longitude, 910 float radius, long expiration, PendingIntent intent) { 911 if (false) { 912 Log.d(TAG, "addProximityAlert: latitude = " + latitude + 913 ", longitude = " + longitude + ", radius = " + radius + 914 ", expiration = " + expiration + 915 ", intent = " + intent); 916 } 917 try { 918 mService.addProximityAlert(latitude, longitude, radius, 919 expiration, intent); 920 } catch (RemoteException ex) { 921 Log.e(TAG, "addProximityAlert: RemoteException", ex); 922 } 923 } 924 925 /** 926 * Removes the proximity alert with the given PendingIntent. 927 * 928 * @param intent the PendingIntent that no longer needs to be notified of 929 * proximity alerts 930 */ 931 public void removeProximityAlert(PendingIntent intent) { 932 if (false) { 933 Log.d(TAG, "removeProximityAlert: intent = " + intent); 934 } 935 try { 936 mService.removeProximityAlert(intent); 937 } catch (RemoteException ex) { 938 Log.e(TAG, "removeProximityAlert: RemoteException", ex); 939 } 940 } 941 942 /** 943 * Returns the current enabled/disabled status of the given provider. If the 944 * user has enabled this provider in the Settings menu, true is returned 945 * otherwise false is returned 946 * 947 * @param provider the name of the provider 948 * @return true if the provider is enabled 949 * 950 * @throws SecurityException if no suitable permission is present for the provider. 951 * @throws IllegalArgumentException if provider is null or doesn't exist 952 */ 953 public boolean isProviderEnabled(String provider) { 954 if (provider == null) { 955 throw new IllegalArgumentException("provider==null"); 956 } 957 try { 958 return mService.isProviderEnabled(provider); 959 } catch (RemoteException ex) { 960 Log.e(TAG, "isProviderEnabled: RemoteException", ex); 961 return false; 962 } 963 } 964 965 /** 966 * Returns a Location indicating the data from the last known 967 * location fix obtained from the given provider. This can be done 968 * without starting the provider. Note that this location could 969 * be out-of-date, for example if the device was turned off and 970 * moved to another location. 971 * 972 * <p> If the provider is currently disabled, null is returned. 973 * 974 * @param provider the name of the provider 975 * @return the last known location for the provider, or null 976 * 977 * @throws SecurityException if no suitable permission is present for the provider. 978 * @throws IllegalArgumentException if provider is null or doesn't exist 979 */ 980 public Location getLastKnownLocation(String provider) { 981 if (provider == null) { 982 throw new IllegalArgumentException("provider==null"); 983 } 984 try { 985 return mService.getLastKnownLocation(provider); 986 } catch (RemoteException ex) { 987 Log.e(TAG, "getLastKnowLocation: RemoteException", ex); 988 return null; 989 } 990 } 991 992 // Mock provider support 993 994 /** 995 * Creates a mock location provider and adds it to the set of active providers. 996 * 997 * @param name the provider name 998 * @param requiresNetwork 999 * @param requiresSatellite 1000 * @param requiresCell 1001 * @param hasMonetaryCost 1002 * @param supportsAltitude 1003 * @param supportsSpeed 1004 * @param supportsBearing 1005 * @param powerRequirement 1006 * @param accuracy 1007 * 1008 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1009 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1010 * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled 1011 * @throws IllegalArgumentException if a provider with the given name already exists 1012 */ 1013 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, 1014 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, 1015 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { 1016 try { 1017 mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell, 1018 hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement, 1019 accuracy); 1020 } catch (RemoteException ex) { 1021 Log.e(TAG, "addTestProvider: RemoteException", ex); 1022 } 1023 } 1024 1025 /** 1026 * Removes the mock location provider with the given name. 1027 * 1028 * @param provider the provider name 1029 * 1030 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1031 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1032 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1033 * @throws IllegalArgumentException if no provider with the given name exists 1034 */ 1035 public void removeTestProvider(String provider) { 1036 try { 1037 mService.removeTestProvider(provider); 1038 } catch (RemoteException ex) { 1039 Log.e(TAG, "removeTestProvider: RemoteException", ex); 1040 } 1041 } 1042 1043 /** 1044 * Sets a mock location for the given provider. This location will be used in place 1045 * of any actual location from the provider. 1046 * 1047 * @param provider the provider name 1048 * @param loc the mock location 1049 * 1050 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1051 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1052 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1053 * @throws IllegalArgumentException if no provider with the given name exists 1054 */ 1055 public void setTestProviderLocation(String provider, Location loc) { 1056 try { 1057 mService.setTestProviderLocation(provider, loc); 1058 } catch (RemoteException ex) { 1059 Log.e(TAG, "setTestProviderLocation: RemoteException", ex); 1060 } 1061 } 1062 1063 /** 1064 * Removes any mock location associated with the given provider. 1065 * 1066 * @param provider the provider name 1067 * 1068 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1069 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1070 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1071 * @throws IllegalArgumentException if no provider with the given name exists 1072 */ 1073 public void clearTestProviderLocation(String provider) { 1074 try { 1075 mService.clearTestProviderLocation(provider); 1076 } catch (RemoteException ex) { 1077 Log.e(TAG, "clearTestProviderLocation: RemoteException", ex); 1078 } 1079 } 1080 1081 /** 1082 * Sets a mock enabled value for the given provider. This value will be used in place 1083 * of any actual value from the provider. 1084 * 1085 * @param provider the provider name 1086 * @param enabled the mock enabled value 1087 * 1088 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1089 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1090 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1091 * @throws IllegalArgumentException if no provider with the given name exists 1092 */ 1093 public void setTestProviderEnabled(String provider, boolean enabled) { 1094 try { 1095 mService.setTestProviderEnabled(provider, enabled); 1096 } catch (RemoteException ex) { 1097 Log.e(TAG, "setTestProviderEnabled: RemoteException", ex); 1098 } 1099 } 1100 1101 /** 1102 * Removes any mock enabled value associated with the given provider. 1103 * 1104 * @param provider the provider name 1105 * 1106 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1107 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1108 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1109 * @throws IllegalArgumentException if no provider with the given name exists 1110 */ 1111 public void clearTestProviderEnabled(String provider) { 1112 try { 1113 mService.clearTestProviderEnabled(provider); 1114 } catch (RemoteException ex) { 1115 Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex); 1116 } 1117 1118 } 1119 1120 /** 1121 * Sets mock status values for the given provider. These values will be used in place 1122 * of any actual values from the provider. 1123 * 1124 * @param provider the provider name 1125 * @param status the mock status 1126 * @param extras a Bundle containing mock extras 1127 * @param updateTime the mock update time 1128 * 1129 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1130 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1131 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1132 * @throws IllegalArgumentException if no provider with the given name exists 1133 */ 1134 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { 1135 try { 1136 mService.setTestProviderStatus(provider, status, extras, updateTime); 1137 } catch (RemoteException ex) { 1138 Log.e(TAG, "setTestProviderStatus: RemoteException", ex); 1139 } 1140 } 1141 1142 /** 1143 * Removes any mock status values associated with the given provider. 1144 * 1145 * @param provider the provider name 1146 * 1147 * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present 1148 * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION 1149 * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled 1150 * @throws IllegalArgumentException if no provider with the given name exists 1151 */ 1152 public void clearTestProviderStatus(String provider) { 1153 try { 1154 mService.clearTestProviderStatus(provider); 1155 } catch (RemoteException ex) { 1156 Log.e(TAG, "clearTestProviderStatus: RemoteException", ex); 1157 } 1158 } 1159 1160 // GPS-specific support 1161 1162 // This class is used to send GPS status events to the client's main thread. 1163 private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { 1164 1165 private final GpsStatus.Listener mListener; 1166 private final GpsStatus.NmeaListener mNmeaListener; 1167 1168 // This must not equal any of the GpsStatus event IDs 1169 private static final int NMEA_RECEIVED = 1000; 1170 1171 private class Nmea { 1172 long mTimestamp; 1173 String mNmea; 1174 1175 Nmea(long timestamp, String nmea) { 1176 mTimestamp = timestamp; 1177 mNmea = nmea; 1178 } 1179 } 1180 private ArrayList<Nmea> mNmeaBuffer; 1181 1182 GpsStatusListenerTransport(GpsStatus.Listener listener) { 1183 mListener = listener; 1184 mNmeaListener = null; 1185 } 1186 1187 GpsStatusListenerTransport(GpsStatus.NmeaListener listener) { 1188 mNmeaListener = listener; 1189 mListener = null; 1190 mNmeaBuffer = new ArrayList<Nmea>(); 1191 } 1192 1193 public void onGpsStarted() { 1194 if (mListener != null) { 1195 Message msg = Message.obtain(); 1196 msg.what = GpsStatus.GPS_EVENT_STARTED; 1197 mGpsHandler.sendMessage(msg); 1198 } 1199 } 1200 1201 public void onGpsStopped() { 1202 if (mListener != null) { 1203 Message msg = Message.obtain(); 1204 msg.what = GpsStatus.GPS_EVENT_STOPPED; 1205 mGpsHandler.sendMessage(msg); 1206 } 1207 } 1208 1209 public void onFirstFix(int ttff) { 1210 if (mListener != null) { 1211 mGpsStatus.setTimeToFirstFix(ttff); 1212 Message msg = Message.obtain(); 1213 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; 1214 mGpsHandler.sendMessage(msg); 1215 } 1216 } 1217 1218 public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, 1219 float[] elevations, float[] azimuths, int ephemerisMask, 1220 int almanacMask, int usedInFixMask) { 1221 if (mListener != null) { 1222 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, 1223 ephemerisMask, almanacMask, usedInFixMask); 1224 1225 Message msg = Message.obtain(); 1226 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; 1227 // remove any SV status messages already in the queue 1228 mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); 1229 mGpsHandler.sendMessage(msg); 1230 } 1231 } 1232 1233 public void onNmeaReceived(long timestamp, String nmea) { 1234 if (mNmeaListener != null) { 1235 synchronized (mNmeaBuffer) { 1236 mNmeaBuffer.add(new Nmea(timestamp, nmea)); 1237 } 1238 Message msg = Message.obtain(); 1239 msg.what = NMEA_RECEIVED; 1240 // remove any NMEA_RECEIVED messages already in the queue 1241 mGpsHandler.removeMessages(NMEA_RECEIVED); 1242 mGpsHandler.sendMessage(msg); 1243 } 1244 } 1245 1246 private final Handler mGpsHandler = new Handler() { 1247 @Override 1248 public void handleMessage(Message msg) { 1249 if (msg.what == NMEA_RECEIVED) { 1250 synchronized (mNmeaBuffer) { 1251 int length = mNmeaBuffer.size(); 1252 for (int i = 0; i < length; i++) { 1253 Nmea nmea = mNmeaBuffer.get(i); 1254 mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea); 1255 } 1256 mNmeaBuffer.clear(); 1257 } 1258 } else { 1259 // synchronize on mGpsStatus to ensure the data is copied atomically. 1260 synchronized(mGpsStatus) { 1261 mListener.onGpsStatusChanged(msg.what); 1262 } 1263 } 1264 } 1265 }; 1266 } 1267 1268 /** 1269 * Adds a GPS status listener. 1270 * 1271 * @param listener GPS status listener object to register 1272 * 1273 * @return true if the listener was successfully added 1274 * 1275 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1276 */ 1277 public boolean addGpsStatusListener(GpsStatus.Listener listener) { 1278 boolean result; 1279 1280 if (mGpsStatusListeners.get(listener) != null) { 1281 // listener is already registered 1282 return true; 1283 } 1284 try { 1285 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1286 result = mService.addGpsStatusListener(transport); 1287 if (result) { 1288 mGpsStatusListeners.put(listener, transport); 1289 } 1290 } catch (RemoteException e) { 1291 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1292 result = false; 1293 } 1294 1295 return result; 1296 } 1297 1298 /** 1299 * Removes a GPS status listener. 1300 * 1301 * @param listener GPS status listener object to remove 1302 */ 1303 public void removeGpsStatusListener(GpsStatus.Listener listener) { 1304 try { 1305 GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener); 1306 if (transport != null) { 1307 mService.removeGpsStatusListener(transport); 1308 } 1309 } catch (RemoteException e) { 1310 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1311 } 1312 } 1313 1314 /** 1315 * Adds an NMEA listener. 1316 * 1317 * @param listener a {#link GpsStatus.NmeaListener} object to register 1318 * 1319 * @return true if the listener was successfully added 1320 * 1321 * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present 1322 */ 1323 public boolean addNmeaListener(GpsStatus.NmeaListener listener) { 1324 boolean result; 1325 1326 if (mNmeaListeners.get(listener) != null) { 1327 // listener is already registered 1328 return true; 1329 } 1330 try { 1331 GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); 1332 result = mService.addGpsStatusListener(transport); 1333 if (result) { 1334 mNmeaListeners.put(listener, transport); 1335 } 1336 } catch (RemoteException e) { 1337 Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); 1338 result = false; 1339 } 1340 1341 return result; 1342 } 1343 1344 /** 1345 * Removes an NMEA listener. 1346 * 1347 * @param listener a {#link GpsStatus.NmeaListener} object to remove 1348 */ 1349 public void removeNmeaListener(GpsStatus.NmeaListener listener) { 1350 try { 1351 GpsStatusListenerTransport transport = mNmeaListeners.remove(listener); 1352 if (transport != null) { 1353 mService.removeGpsStatusListener(transport); 1354 } 1355 } catch (RemoteException e) { 1356 Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); 1357 } 1358 } 1359 1360 /** 1361 * Retrieves information about the current status of the GPS engine. 1362 * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} 1363 * callback to ensure that the data is copied atomically. 1364 * 1365 * The caller may either pass in a {@link GpsStatus} object to set with the latest 1366 * status information, or pass null to create a new {@link GpsStatus} object. 1367 * 1368 * @param status object containing GPS status details, or null. 1369 * @return status object containing updated GPS status. 1370 */ 1371 public GpsStatus getGpsStatus(GpsStatus status) { 1372 if (status == null) { 1373 status = new GpsStatus(); 1374 } 1375 status.setStatus(mGpsStatus); 1376 return status; 1377 } 1378 1379 /** 1380 * Sends additional commands to a location provider. 1381 * Can be used to support provider specific extensions to the Location Manager API 1382 * 1383 * @param provider name of the location provider. 1384 * @param command name of the command to send to the provider. 1385 * @param extras optional arguments for the command (or null). 1386 * The provider may optionally fill the extras Bundle with results from the command. 1387 * 1388 * @return true if the command succeeds. 1389 */ 1390 public boolean sendExtraCommand(String provider, String command, Bundle extras) { 1391 try { 1392 return mService.sendExtraCommand(provider, command, extras); 1393 } catch (RemoteException e) { 1394 Log.e(TAG, "RemoteException in sendExtraCommand: ", e); 1395 return false; 1396 } 1397 } 1398 1399 /** 1400 * Installs a location provider. 1401 * 1402 * @param name of the location provider 1403 * @param provider Binder interface for the location provider 1404 * 1405 * @return true if the command succeeds. 1406 * 1407 * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. 1408 * 1409 * {@hide} 1410 */ 1411 public boolean installLocationProvider(String name, ILocationProvider provider) { 1412 try { 1413 mService.installLocationProvider(name, provider); 1414 return true; 1415 } catch (RemoteException e) { 1416 Log.e(TAG, "RemoteException in installLocationProvider: ", e); 1417 return false; 1418 } 1419 } 1420 1421 /** 1422 * Installs a location provider. 1423 * 1424 * @param provider implementation of the location provider 1425 * 1426 * @return true if the command succeeds. 1427 * 1428 * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. 1429 */ 1430 public boolean installLocationProvider(LocationProviderImpl provider) { 1431 return installLocationProvider(provider.getName(), provider.getInterface()); 1432 } 1433 1434 /** 1435 * Installs a geocoder server. 1436 * 1437 * @param provider Binder interface for the geocoder provider 1438 * 1439 * @return true if the command succeeds. 1440 * 1441 * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. 1442 * 1443 * {@hide} 1444 */ 1445 public boolean installGeocodeProvider(GeocodeProvider provider) { 1446 try { 1447 mService.installGeocodeProvider(new GeocodeProviderProxy(provider)); 1448 return true; 1449 } catch (RemoteException e) { 1450 Log.e(TAG, "RemoteException in setGeocodeProvider: ", e); 1451 return false; 1452 } 1453 } 1454 1455 /** 1456 * Used by location providers to report new locations. 1457 * 1458 * @param location new Location to report 1459 * 1460 * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission. 1461 * 1462 * {@hide} 1463 */ 1464 public void reportLocation(Location location) { 1465 try { 1466 mService.reportLocation(location); 1467 } catch (RemoteException e) { 1468 Log.e(TAG, "RemoteException in reportLocation: ", e); 1469 } 1470 } 1471 1472 /** 1473 * Used by NetInitiatedActivity to report user response 1474 * for network initiated GPS fix requests. 1475 * 1476 * {@hide} 1477 */ 1478 public boolean sendNiResponse(int notifId, int userResponse) { 1479 try { 1480 return mService.sendNiResponse(notifId, userResponse); 1481 } catch (RemoteException e) { 1482 Log.e(TAG, "RemoteException in sendNiResponse: ", e); 1483 return false; 1484 } 1485 } 1486 1487} 1488