diff options
Diffstat (limited to 'location/java/android/location/LocationManager.java')
| -rw-r--r-- | location/java/android/location/LocationManager.java | 539 |
1 files changed, 289 insertions, 250 deletions
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 28bc599..11beadc 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -28,8 +28,6 @@ import android.util.Log; import com.android.internal.location.DummyLocationProvider; import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -249,15 +247,12 @@ public class LocationManager { * factory Context.getSystemService. */ public LocationManager(ILocationManager service) { - if (false) { - Log.d(TAG, "Constructor: service = " + service); - } mService = service; } private LocationProvider createProvider(String name, Bundle info) { DummyLocationProvider provider = - new DummyLocationProvider(name); + new DummyLocationProvider(name, mService); provider.setRequiresNetwork(info.getBoolean("network")); provider.setRequiresSatellite(info.getBoolean("satellite")); provider.setRequiresCell(info.getBoolean("cell")); @@ -299,7 +294,7 @@ public class LocationManager { */ public List<String> getProviders(boolean enabledOnly) { try { - return mService.getProviders(enabledOnly); + return mService.getProviders(null, enabledOnly); } catch (RemoteException ex) { Log.e(TAG, "getProviders: RemoteException", ex); } @@ -344,173 +339,15 @@ public class LocationManager { * @return list of Strings containing names of the providers */ public List<String> getProviders(Criteria criteria, boolean enabledOnly) { - List<String> goodProviders = Collections.emptyList(); - List<String> providers = getProviders(enabledOnly); - for (String providerName : providers) { - LocationProvider provider = getProvider(providerName); - if (provider != null && provider.meetsCriteria(criteria)) { - if (goodProviders.isEmpty()) { - goodProviders = new ArrayList<String>(); - } - goodProviders.add(providerName); - } - } - return goodProviders; - } - - /** - * Returns the next looser power requirement, in the sequence: - * - * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT - */ - private int nextPower(int power) { - switch (power) { - case Criteria.POWER_LOW: - return Criteria.POWER_MEDIUM; - case Criteria.POWER_MEDIUM: - return Criteria.POWER_HIGH; - case Criteria.POWER_HIGH: - return Criteria.NO_REQUIREMENT; - case Criteria.NO_REQUIREMENT: - default: - return Criteria.NO_REQUIREMENT; - } - } - - /** - * Returns the next looser accuracy requirement, in the sequence: - * - * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT - */ - private int nextAccuracy(int accuracy) { - if (accuracy == Criteria.ACCURACY_FINE) { - return Criteria.ACCURACY_COARSE; - } else { - return Criteria.NO_REQUIREMENT; - } - } - - private abstract class LpComparator implements Comparator<LocationProvider> { - - public int compare(int a1, int a2) { - if (a1 < a2) { - return -1; - } else if (a1 > a2) { - return 1; - } else { - return 0; - } - } - - public int compare(float a1, float a2) { - if (a1 < a2) { - return -1; - } else if (a1 > a2) { - return 1; - } else { - return 0; - } - } - } - - private class LpPowerComparator extends LpComparator { - public int compare(LocationProvider l1, LocationProvider l2) { - int a1 = l1.getPowerRequirement(); - int a2 = l2.getPowerRequirement(); - return compare(a1, a2); // Smaller is better - } - - public boolean equals(LocationProvider l1, LocationProvider l2) { - int a1 = l1.getPowerRequirement(); - int a2 = l2.getPowerRequirement(); - return a1 == a2; - } - } - - private class LpAccuracyComparator extends LpComparator { - public int compare(LocationProvider l1, LocationProvider l2) { - int a1 = l1.getAccuracy(); - int a2 = l2.getAccuracy(); - return compare(a1, a2); // Smaller is better - } - - public boolean equals(LocationProvider l1, LocationProvider l2) { - int a1 = l1.getAccuracy(); - int a2 = l2.getAccuracy(); - return a1 == a2; - } - } - - private class LpCapabilityComparator extends LpComparator { - - private static final int ALTITUDE_SCORE = 4; - private static final int BEARING_SCORE = 4; - private static final int SPEED_SCORE = 4; - - private int score(LocationProvider p) { - return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + - (p.supportsBearing() ? BEARING_SCORE : 0) + - (p.supportsSpeed() ? SPEED_SCORE : 0); - } - - public int compare(LocationProvider l1, LocationProvider l2) { - int a1 = score(l1); - int a2 = score(l2); - return compare(-a1, -a2); // Bigger is better - } - - public boolean equals(LocationProvider l1, LocationProvider l2) { - int a1 = score(l1); - int a2 = score(l2); - return a1 == a2; - } - } - - private LocationProvider best(List<String> providerNames) { - List<LocationProvider> providers = new ArrayList<LocationProvider>(providerNames.size()); - for (String name : providerNames) { - providers.add(getProvider(name)); - } - - if (providers.size() < 2) { - return providers.get(0); - } - - // First, sort by power requirement - Collections.sort(providers, new LpPowerComparator()); - int power = providers.get(0).getPowerRequirement(); - if (power < providers.get(1).getPowerRequirement()) { - return providers.get(0); - } - - int idx, size; - - List<LocationProvider> tmp = new ArrayList<LocationProvider>(); - idx = 0; - size = providers.size(); - while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { - tmp.add(providers.get(idx)); - idx++; + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); } - - // Next, sort by accuracy - Collections.sort(tmp, new LpAccuracyComparator()); - int acc = tmp.get(0).getAccuracy(); - if (acc < tmp.get(1).getAccuracy()) { - return tmp.get(0); - } - - List<LocationProvider> tmp2 = new ArrayList<LocationProvider>(); - idx = 0; - size = tmp.size(); - while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { - tmp2.add(tmp.get(idx)); - idx++; + try { + return mService.getProviders(criteria, enabledOnly); + } catch (RemoteException ex) { + Log.e(TAG, "getProviders: RemoteException", ex); } - - // Finally, sort by capability "score" - Collections.sort(tmp2, new LpCapabilityComparator()); - return tmp2.get(0); + return null; } /** @@ -536,72 +373,14 @@ public class LocationManager { * @return name of the provider that best matches the requirements */ public String getBestProvider(Criteria criteria, boolean enabledOnly) { - List<String> goodProviders = getProviders(criteria, enabledOnly); - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); - } - - // Make a copy of the criteria that we can modify - criteria = new Criteria(criteria); - - // Loosen power requirement - int power = criteria.getPowerRequirement(); - while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { - power = nextPower(power); - criteria.setPowerRequirement(power); - goodProviders = getProviders(criteria, enabledOnly); - } - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); - } - -// // Loosen response time requirement -// int responseTime = criteria.getPreferredResponseTime(); -// while (goodProviders.isEmpty() && -// (responseTime != Criteria.NO_REQUIREMENT)) { -// responseTime += 1000; -// if (responseTime > 60000) { -// responseTime = Criteria.NO_REQUIREMENT; -// } -// criteria.setPreferredResponseTime(responseTime); -// goodProviders = getProviders(criteria); -// } -// if (!goodProviders.isEmpty()) { -// return best(goodProviders); -// } - - // Loosen accuracy requirement - int accuracy = criteria.getAccuracy(); - while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { - accuracy = nextAccuracy(accuracy); - criteria.setAccuracy(accuracy); - goodProviders = getProviders(criteria, enabledOnly); - } - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); } - - // Remove bearing requirement - criteria.setBearingRequired(false); - goodProviders = getProviders(criteria, enabledOnly); - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); - } - - // Remove speed requirement - criteria.setSpeedRequired(false); - goodProviders = getProviders(criteria, enabledOnly); - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); - } - - // Remove altitude requirement - criteria.setAltitudeRequired(false); - goodProviders = getProviders(criteria, enabledOnly); - if (!goodProviders.isEmpty()) { - return best(goodProviders).getName(); + try { + return mService.getBestProvider(criteria, enabledOnly); + } catch (RemoteException ex) { + Log.e(TAG, "getBestProvider: RemoteException", ex); } - return null; } @@ -658,7 +437,7 @@ public class LocationManager { if (listener == null) { throw new IllegalArgumentException("listener==null"); } - _requestLocationUpdates(provider, minTime, minDistance, listener, null); + _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, null); } /** @@ -701,10 +480,10 @@ public class LocationManager { * each location update * @param looper a Looper object whose message queue will be used to * implement the callback mechanism. + * If looper is null then the callbacks will be called on the main thread. * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if listener is null - * @throws IllegalArgumentException if looper is null * @throws SecurityException if no suitable permission is present for the provider. */ public void requestLocationUpdates(String provider, @@ -716,15 +495,72 @@ public class LocationManager { if (listener == null) { throw new IllegalArgumentException("listener==null"); } - if (looper == null) { - throw new IllegalArgumentException("looper==null"); + _requestLocationUpdates(provider, null, minTime, minDistance, false, listener, looper); + } + + /** + * Registers the current activity to be notified periodically based on + * the specified criteria. Periodically, the supplied LocationListener will + * be called with the current Location or with status updates. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * <p> In case the provider is disabled by the user, updates will stop, + * and the {@link LocationListener#onProviderDisabled(String)} + * method will be called. As soon as the provider is enabled again, + * the {@link LocationListener#onProviderEnabled(String)} method will + * be called and location updates will start again. + * + * <p> The frequency of notification may be controlled using the + * minTime and minDistance parameters. If minTime is greater than 0, + * the LocationManager could potentially rest for minTime milliseconds + * between location updates to conserve power. If minDistance is greater than 0, + * a location will only be broadcasted if the device moves by minDistance meters. + * To obtain notifications as frequently as possible, set both parameters to 0. + * + * <p> Background services should be careful about setting a sufficiently high + * minTime so that the device doesn't consume too much power by keeping the + * GPS or wireless radios on all the time. In particular, values under 60000ms + * are not recommended. + * + * <p> The supplied Looper is used to implement the callback mechanism. + * + * @param minTime the minimum time interval for notifications, in + * milliseconds. This field is only used as a hint to conserve power, and actual + * time between location updates may be greater or lesser than this value. + * @param minDistance the minimum distance interval for notifications, + * in meters + * @param criteria contains parameters for the location manager to choose the + * appropriate provider and parameters to compute the location + * @param listener a {#link LocationListener} whose + * {@link LocationListener#onLocationChanged} method will be called for + * each location update + * @param looper a Looper object whose message queue will be used to + * implement the callback mechanism. + * If looper is null then the callbacks will be called on the main thread. + * + * @throws IllegalArgumentException if criteria is null + * @throws IllegalArgumentException if listener is null + * @throws SecurityException if no suitable permission is present to access + * the location services. + * + * {@hide} + */ + public void requestLocationUpdates(long minTime, float minDistance, + Criteria criteria, LocationListener listener, Looper looper) { + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener==null"); } - _requestLocationUpdates(provider, minTime, minDistance, listener, looper); + _requestLocationUpdates(null, criteria, minTime, minDistance, false, listener, looper); } - private void _requestLocationUpdates(String provider, - long minTime, float minDistance, LocationListener listener, - Looper looper) { + private void _requestLocationUpdates(String provider, Criteria criteria, long minTime, + float minDistance, boolean singleShot, LocationListener listener, Looper looper) { if (minTime < 0L) { minTime = 0L; } @@ -739,7 +575,7 @@ public class LocationManager { transport = new ListenerTransport(listener, looper); } mListeners.put(listener, transport); - mService.requestLocationUpdates(provider, minTime, minDistance, transport); + mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport); } } catch (RemoteException ex) { Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex); @@ -785,7 +621,7 @@ public class LocationManager { * time between location updates may be greater or lesser than this value. * @param minDistance the minimum distance interval for notifications, * in meters - * @param intent a {#link PendingIntet} to be sent for each location update + * @param intent a {#link PendingIntent} to be sent for each location update * * @throws IllegalArgumentException if provider is null or doesn't exist * @throws IllegalArgumentException if intent is null @@ -799,11 +635,69 @@ public class LocationManager { if (intent == null) { throw new IllegalArgumentException("intent==null"); } - _requestLocationUpdates(provider, minTime, minDistance, intent); + _requestLocationUpdates(provider, null, minTime, minDistance, false, intent); } - private void _requestLocationUpdates(String provider, - long minTime, float minDistance, PendingIntent intent) { + /** + * Registers the current activity to be notified periodically based on + * the specified criteria. Periodically, the supplied PendingIntent will + * be broadcast with the current Location or with status updates. + * + * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * <p> The frequency of notification or new locations may be controlled using the + * minTime and minDistance parameters. If minTime is greater than 0, + * the LocationManager could potentially rest for minTime milliseconds + * between location updates to conserve power. If minDistance is greater than 0, + * a location will only be broadcast if the device moves by minDistance meters. + * To obtain notifications as frequently as possible, set both parameters to 0. + * + * <p> Background services should be careful about setting a sufficiently high + * minTime so that the device doesn't consume too much power by keeping the + * GPS or wireless radios on all the time. In particular, values under 60000ms + * are not recommended. + * + * <p> In case the provider is disabled by the user, updates will stop, + * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value + * of false. If the provider is re-enabled, an intent will be sent with an + * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will + * start again. + * + * <p> If the provider's status changes, an intent will be sent with an extra with key + * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated + * with the status update will be sent as well. + * + * @param minTime the minimum time interval for notifications, in + * milliseconds. This field is only used as a hint to conserve power, and actual + * time between location updates may be greater or lesser than this value. + * @param minDistance the minimum distance interval for notifications, + * in meters + * @param criteria contains parameters for the location manager to choose the + * appropriate provider and parameters to compute the location + * @param intent a {#link PendingIntent} to be sent for each location update + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if intent is null + * @throws SecurityException if no suitable permission is present for the provider. + * + * {@hide} + */ + public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria, PendingIntent intent) { + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); + } + if (intent == null) { + throw new IllegalArgumentException("intent==null"); + } + _requestLocationUpdates(null, criteria, minTime, minDistance, false, intent); + } + + private void _requestLocationUpdates(String provider, Criteria criteria, + long minTime, float minDistance, boolean singleShot, PendingIntent intent) { if (minTime < 0L) { minTime = 0L; } @@ -812,13 +706,158 @@ public class LocationManager { } try { - mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent); + mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent); } catch (RemoteException ex) { Log.e(TAG, "requestLocationUpdates: RemoteException", ex); } } /** + * Registers the current activity to be notified periodically by + * the named provider. Periodically, the supplied LocationListener will + * be called with the current Location or with status updates. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * <p> In case the provider is disabled by the user, updates will stop, + * and the {@link LocationListener#onProviderDisabled(String)} + * method will be called. As soon as the provider is enabled again, + * the {@link LocationListener#onProviderEnabled(String)} method will + * be called and location updates will start again. + * + * <p> The supplied Looper is used to implement the callback mechanism. + * + * @param provider the name of the provider with which to register + * @param listener a {#link LocationListener} whose + * {@link LocationListener#onLocationChanged} method will be called for + * each location update + * @param looper a Looper object whose message queue will be used to + * implement the callback mechanism. + * If looper is null then the callbacks will be called on the main thread. + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if listener is null + * @throws SecurityException if no suitable permission is present for the provider. + * + * {@hide} + */ + public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener==null"); + } + _requestLocationUpdates(provider, null, 0L, 0.0f, true, listener, looper); + } + + /** + * Registers the current activity to be notified periodically based on + * the specified criteria. Periodically, the supplied LocationListener will + * be called with the current Location or with status updates. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * <p> In case the provider is disabled by the user, updates will stop, + * and the {@link LocationListener#onProviderDisabled(String)} + * method will be called. As soon as the provider is enabled again, + * the {@link LocationListener#onProviderEnabled(String)} method will + * be called and location updates will start again. + * + * <p> The supplied Looper is used to implement the callback mechanism. + * + * @param criteria contains parameters for the location manager to choose the + * appropriate provider and parameters to compute the location + * @param listener a {#link LocationListener} whose + * {@link LocationListener#onLocationChanged} method will be called for + * each location update + * @param looper a Looper object whose message queue will be used to + * implement the callback mechanism. + * If looper is null then the callbacks will be called on the current thread. + * + * @throws IllegalArgumentException if criteria is null + * @throws IllegalArgumentException if listener is null + * @throws SecurityException if no suitable permission is present to access + * the location services. + * + * {@hide} + */ + public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) { + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener==null"); + } + _requestLocationUpdates(null, criteria, 0L, 0.0f, true, listener, looper); + } + + /** + * Registers the current activity to be notified periodically by + * the named provider. Periodically, the supplied PendingIntent will + * be broadcast with the current Location or with status updates. + * + * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * @param provider the name of the provider with which to register + * @param intent a {#link PendingIntent} to be sent for the location update + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if intent is null + * @throws SecurityException if no suitable permission is present for the provider. + * + * {@hide} + */ + public void requestSingleUpdate(String provider, PendingIntent intent) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + if (intent == null) { + throw new IllegalArgumentException("intent==null"); + } + _requestLocationUpdates(provider, null, 0L, 0.0f, true, intent); + } + + /** + * Registers the current activity to be notified periodically based on + * the specified criteria. Periodically, the supplied PendingIntent will + * be broadcast with the current Location or with status updates. + * + * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. + * + * <p> It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + * @param criteria contains parameters for the location manager to choose the + * appropriate provider and parameters to compute the location + * @param intent a {#link PendingIntent} to be sent for the location update + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if intent is null + * @throws SecurityException if no suitable permission is present for the provider. + * + * {@hide} + */ + public void requestSingleUpdate(Criteria criteria, PendingIntent intent) { + if (criteria == null) { + throw new IllegalArgumentException("criteria==null"); + } + if (intent == null) { + throw new IllegalArgumentException("intent==null"); + } + _requestLocationUpdates(null, criteria, 0L, 0.0f, true, intent); + } + + /** * Removes any current registration for location updates of the current activity * with the given LocationListener. Following this call, updates will no longer * occur for this listener. |
