diff options
author | Mike Lockwood <lockwood@android.com> | 2010-04-01 08:10:09 -0700 |
---|---|---|
committer | Mike Lockwood <lockwood@android.com> | 2010-05-21 11:47:19 -0400 |
commit | 03ca216ac19ea4e7afcb183c20c7c780f0d97756 (patch) | |
tree | 38e47efa7aeeff99fde78adb5f83446d2407eda0 /location/java | |
parent | 4979601f88154bdeda4cc5277940771ba6597c0f (diff) | |
download | frameworks_base-03ca216ac19ea4e7afcb183c20c7c780f0d97756.zip frameworks_base-03ca216ac19ea4e7afcb183c20c7c780f0d97756.tar.gz frameworks_base-03ca216ac19ea4e7afcb183c20c7c780f0d97756.tar.bz2 |
New Location Manager APIs for Criteria based requests and single shot mode.
Use MS-Assisted mode for single shot GPS fixes if it is supported.
Add finer grained control over accuracy to the android.location.Criteria class
and location criteria logic from LocationManager to LocationManagerService
Change-Id: I156b1f6c6a45d255c87ff917cf3e9726a6d7a75b
Signed-off-by: Mike Lockwood <lockwood@android.com>
Diffstat (limited to 'location/java')
7 files changed, 564 insertions, 310 deletions
diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java index 9d258d0..6210a38 100644 --- a/location/java/android/location/Criteria.java +++ b/location/java/android/location/Criteria.java @@ -57,9 +57,81 @@ public class Criteria implements Parcelable { */ public static final int ACCURACY_COARSE = 2; - private int mAccuracy = NO_REQUIREMENT; + /** + * A constant indicating a low location accuracy requirement + * - may be used for horizontal, altitude, speed or bearing accuracy. + * For horizontal and vertical position this corresponds to an accuracy + * greater than 500 meters. For speed and bearing, this corresponds + * to greater than 5 meters/second velocity and 10 degrees for bearing. + * {@hide} + */ + public static final int ACCURACY_LOW = 1; + + /** + * A constant indicating a medium accuracy requirement + * - may be used for horizontal, altitude, speed or bearing accuracy. + * For horizontal position this corresponds to an accuracy of between + * 100 and 500 meters, and between 200 and 500 meters for vertical accuracy. + * For speed and bearing, this corresponds to 1 meter/second to 5 meters/second + * velocity and and between 5 and 10 degrees for bearing. + * {@hide} + */ + public static final int ACCURACY_MEDIUM = 2; + + /** + * a constant indicating a high accuracy requirement + * - may be used for horizontal, altitude, speed or bearing accuracy. + * For horizontal and vertical position this corresponds to an accuracy + * less than 100 meters. For speed and bearing, this corresponds + * to less 1 meter/second velocity less than 5 degrees for bearing. + * {@hide} + */ + public static final int ACCURACY_HIGH = 3; + + /** + * a constant indicating the best accuracy that is available for any + * location provider available + * - may be used for horizontal, altitude, speed or bearing accuracy. + * {@hide} + */ + public static final int ACCURACY_BEST = 4; + + /** + * A constant indicating horizontal accuracy has the top priority + * {@hide} + */ + public static final int HORIZONTAL_ACCURACY_PRIORITY = 1; + + /** + * A constant indicating altitude accuracy has the top priority + * {@hide} + */ + public static final int VERTICAL_ACCURACY_PRIORITY = 2; + + /** + * A constant indicating speed accuracy has the top priority + * {@hide} + */ + public static final int SPEED_ACCURACY_PRIORITY = 3; + + /** + * A constant indicating bearing accuracy has the top priority + * {@hide} + */ + public static final int BEARING_ACCURACY_PRIORITY = 4; + + /** + * A constant indicating power requirement has the top priority + * {@hide} + */ + public static final int POWER_REQUIREMENT_PRIORITY = 5; + + private int mHorizontalAccuracy = NO_REQUIREMENT; + private int mVerticalAccuracy = NO_REQUIREMENT; + private int mSpeedAccuracy = NO_REQUIREMENT; + private int mBearingAccuracy = NO_REQUIREMENT; + private int mPriority = HORIZONTAL_ACCURACY_PRIORITY; private int mPowerRequirement = NO_REQUIREMENT; -// private int mPreferredResponseTime = NO_REQUIREMENT; private boolean mAltitudeRequired = false; private boolean mBearingRequired = false; private boolean mSpeedRequired = false; @@ -77,9 +149,12 @@ public class Criteria implements Parcelable { * Constructs a new Criteria object that is a copy of the given criteria. */ public Criteria(Criteria criteria) { - mAccuracy = criteria.mAccuracy; + mHorizontalAccuracy = criteria.mHorizontalAccuracy; + mVerticalAccuracy = criteria.mVerticalAccuracy; + mSpeedAccuracy = criteria.mSpeedAccuracy; + mBearingAccuracy = criteria.mBearingAccuracy; + mPriority = criteria.mPriority; mPowerRequirement = criteria.mPowerRequirement; -// mPreferredResponseTime = criteria.mPreferredResponseTime; mAltitudeRequired = criteria.mAltitudeRequired; mBearingRequired = criteria.mBearingRequired; mSpeedRequired = criteria.mSpeedRequired; @@ -87,19 +162,159 @@ public class Criteria implements Parcelable { } /** + * Indicates the desired horizontal accuracy (latitude and longitude). + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * More accurate location may consume more power and may take longer. + * + * @throws IllegalArgumentException if accuracy is not one of the supported constants + * {@hide} + */ + public void setHorizontalAccuracy(int accuracy) { + if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) { + throw new IllegalArgumentException("accuracy=" + accuracy); + } + mHorizontalAccuracy = accuracy; + } + + /** + * Returns a constant indicating the desired horizontal accuracy (latitude and longitude). + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * {@hide} + */ + public int getHorizontalAccuracy() { + return mHorizontalAccuracy; + } + + /** + * Indicates the desired vertical accuracy (altitude). + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * More accurate location may consume more power and may take longer. + * + * @throws IllegalArgumentException if accuracy is not one of the supported constants + * {@hide} + */ + public void setVerticalAccuracy(int accuracy) { + if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) { + throw new IllegalArgumentException("accuracy=" + accuracy); + } + mVerticalAccuracy = accuracy; + } + + /** + * Returns a constant indicating the desired vertical accuracy (altitude). + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * {@hide} + */ + public int getVerticalAccuracy() { + return mVerticalAccuracy; + } + + /** + * Indicates the desired speed accuracy. + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * More accurate location may consume more power and may take longer. + * + * @throws IllegalArgumentException if accuracy is not one of the supported constants + * {@hide} + */ + public void setSpeedAccuracy(int accuracy) { + if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) { + throw new IllegalArgumentException("accuracy=" + accuracy); + } + mSpeedAccuracy = accuracy; + } + + /** + * Returns a constant indicating the desired speed accuracy + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * {@hide} + */ + public int getSpeedAccuracy() { + return mSpeedAccuracy; + } + + /** + * Indicates the desired bearing accuracy. + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * More accurate location may consume more power and may take longer. + * + * @throws IllegalArgumentException if accuracy is not one of the supported constants + * {@hide} + */ + public void setBearingAccuracy(int accuracy) { + if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_BEST) { + throw new IllegalArgumentException("accuracy=" + accuracy); + } + mBearingAccuracy = accuracy; + } + + /** + * Returns a constant indicating the desired bearing accuracy. + * Accuracy may be {@link #ACCURACY_LOW}, {@link #ACCURACY_MEDIUM}, + * {@link #ACCURACY_HIGH}, {@link #ACCURACY_BEST}, + * {@hide} + */ + public int getBearingAccuracy() { + return mBearingAccuracy; + } + + /** + * Indicates the top priority to optimize for if the criteria parameters are + * found to be in conflict. + * Since a location provider might only be able to optimize for one requirement, + * the other requirements are considered good to have, but not guaranteed. + * This parameter does not override the priorities communicated through the + * preferred accuracy and power consumption parameters. + * If this parameter is not specified and conflicts occur, the location manager + * will use thefollowing default priority (high priority to low priority): + * {@link #HORIZONTAL_ACCURACY_PRIORITY}, {@link #POWER_REQUIREMENT_PRIORITY}, + * {@link #VERTICAL_ACCURACY_PRIORITY}, {@link #SPEED_ACCURACY_PRIORITY}, + * {@link #BEARING_ACCURACY_PRIORITY}. + * {@hide} + */ + public void setPreferredPriority(int priority) { + if (priority < HORIZONTAL_ACCURACY_PRIORITY || priority > POWER_REQUIREMENT_PRIORITY) { + throw new IllegalArgumentException("priority=" + priority); + } + mPriority = priority; + } + + /** + * Returns a constant indicating the top priority to optimize for if the + * criteria parameters are found to be in conflict. + * The value can be {@link #HORIZONTAL_ACCURACY_PRIORITY}, + * {@link #VERTICAL_ACCURACY_PRIORITY}, {@link #SPEED_ACCURACY_PRIORITY}, + * {@link #BEARING_ACCURACY_PRIORITY} or {@link #POWER_REQUIREMENT_PRIORITY}. + * {@hide} + */ + public int getPriority() { + return mPriority; + } + + /** * Indicates the desired accuracy for latitude and longitude. Accuracy * may be {@link #ACCURACY_FINE} if desired location * is fine, else it can be {@link #ACCURACY_COARSE}. - * More accurate location usually consumes more power and may take - * longer. + * More accurate location may consume more power and may take longer. * - * @throws IllegalArgumentException if accuracy is negative + * @throws IllegalArgumentException if accuracy is not one of the supported constants */ public void setAccuracy(int accuracy) { - if (accuracy < NO_REQUIREMENT && accuracy > ACCURACY_COARSE) { + if (accuracy < NO_REQUIREMENT || accuracy > ACCURACY_COARSE) { throw new IllegalArgumentException("accuracy=" + accuracy); } - mAccuracy = accuracy; + if (accuracy == ACCURACY_FINE) { + mHorizontalAccuracy = ACCURACY_BEST; + } else { + mHorizontalAccuracy = ACCURACY_LOW; + } } /** @@ -108,7 +323,11 @@ public class Criteria implements Parcelable { * is fine, else it can be {@link #ACCURACY_COARSE}. */ public int getAccuracy() { - return mAccuracy; + if (mHorizontalAccuracy >= ACCURACY_HIGH) { + return ACCURACY_FINE; + } else { + return ACCURACY_COARSE; + } } /** @@ -131,20 +350,6 @@ public class Criteria implements Parcelable { return mPowerRequirement; } -// /** -// * Indicates the preferred response time of the provider, in milliseconds. -// */ -// public void setPreferredResponseTime(int time) { -// mPreferredResponseTime = time; -// } -// -// /** -// * Returns the preferred response time of the provider, in milliseconds. -// */ -// public int getPreferredResponseTime() { -// return mPreferredResponseTime; -// } - /** * Indicates whether the provider is allowed to incur monetary cost. */ @@ -211,9 +416,12 @@ public class Criteria implements Parcelable { new Parcelable.Creator<Criteria>() { public Criteria createFromParcel(Parcel in) { Criteria c = new Criteria(); - c.mAccuracy = in.readInt(); + c.mHorizontalAccuracy = in.readInt(); + c.mVerticalAccuracy = in.readInt(); + c.mSpeedAccuracy = in.readInt(); + c.mBearingAccuracy = in.readInt(); + c.mPriority = in.readInt(); c.mPowerRequirement = in.readInt(); -// c.mPreferredResponseTime = in.readInt(); c.mAltitudeRequired = in.readInt() != 0; c.mBearingRequired = in.readInt() != 0; c.mSpeedRequired = in.readInt() != 0; @@ -231,9 +439,12 @@ public class Criteria implements Parcelable { } public void writeToParcel(Parcel parcel, int flags) { - parcel.writeInt(mAccuracy); + parcel.writeInt(mHorizontalAccuracy); + parcel.writeInt(mVerticalAccuracy); + parcel.writeInt(mSpeedAccuracy); + parcel.writeInt(mBearingAccuracy); + parcel.writeInt(mPriority); parcel.writeInt(mPowerRequirement); -// parcel.writeInt(mPreferredResponseTime); parcel.writeInt(mAltitudeRequired ? 1 : 0); parcel.writeInt(mBearingRequired ? 1 : 0); parcel.writeInt(mSpeedRequired ? 1 : 0); diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 2c0399e..a86f329 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -18,6 +18,7 @@ package android.location; import android.app.PendingIntent; import android.location.Address; +import android.location.Criteria; import android.location.GeocoderParams; import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; @@ -32,13 +33,15 @@ import android.os.Bundle; */ interface ILocationManager { - List getAllProviders(); - List getProviders(boolean enabledOnly); + List<String> getAllProviders(); + List<String> getProviders(in Criteria criteria, boolean enabledOnly); + String getBestProvider(in Criteria criteria, boolean enabledOnly); + boolean providerMeetsCriteria(String provider, in Criteria criteria); - void requestLocationUpdates(String provider, long minTime, float minDistance, - in ILocationListener listener); - void requestLocationUpdatesPI(String provider, long minTime, float minDistance, - in PendingIntent intent); + void requestLocationUpdates(String provider, in Criteria criteria, long minTime, float minDistance, + boolean singleShot, in ILocationListener listener); + void requestLocationUpdatesPI(String provider, in Criteria criteria, long minTime, float minDistance, + boolean singleShot, in PendingIntent intent); void removeUpdates(in ILocationListener listener); void removeUpdatesPI(in PendingIntent intent); diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl index 97b283c..2b9782a 100644 --- a/location/java/android/location/ILocationProvider.aidl +++ b/location/java/android/location/ILocationProvider.aidl @@ -16,6 +16,7 @@ package android.location; +import android.location.Criteria; import android.location.Location; import android.net.NetworkInfo; import android.os.Bundle; @@ -34,6 +35,7 @@ interface ILocationProvider { boolean supportsSpeed(); boolean supportsBearing(); int getPowerRequirement(); + boolean meetsCriteria(in Criteria criteria); int getAccuracy(); void enable(); void disable(); 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. diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java index bb3e2a5..8c16580 100644 --- a/location/java/android/location/LocationProvider.java +++ b/location/java/android/location/LocationProvider.java @@ -16,6 +16,9 @@ package android.location; +import android.os.RemoteException; +import android.util.Log; + /** * An abstract superclass for location providers. A location provider * provides periodic reports on the geographical location of the @@ -36,7 +39,8 @@ public abstract class LocationProvider { // in the name of a LocationProvider. static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]"; - private String mName; + private final String mName; + private final ILocationManager mService; public static final int OUT_OF_SERVICE = 0; public static final int TEMPORARILY_UNAVAILABLE = 1; @@ -50,13 +54,13 @@ public abstract class LocationProvider { * * {@hide} */ - public LocationProvider(String name) { + public LocationProvider(String name, ILocationManager service) { if (name.matches(BAD_CHARS_REGEX)) { throw new IllegalArgumentException("name " + name + " contains an illegal character"); } - // Log.d(TAG, "Constructor: name = " + name); mName = name; + mService = service; } /** @@ -71,29 +75,12 @@ public abstract class LocationProvider { * false otherwise. */ public boolean meetsCriteria(Criteria criteria) { - // We do not want to match the special passive provider based on criteria. - if (LocationManager.PASSIVE_PROVIDER.equals(mName)) { - return false; - } - if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) && - (criteria.getAccuracy() < getAccuracy())) { - return false; - } - int criteriaPower = criteria.getPowerRequirement(); - if ((criteriaPower != Criteria.NO_REQUIREMENT) && - (criteriaPower < getPowerRequirement())) { - return false; - } - if (criteria.isAltitudeRequired() && !supportsAltitude()) { - return false; - } - if (criteria.isSpeedRequired() && !supportsSpeed()) { - return false; - } - if (criteria.isBearingRequired() && !supportsBearing()) { + try { + return mService.providerMeetsCriteria(mName, criteria); + } catch (RemoteException e) { + Log.e(TAG, "meetsCriteria: RemoteException", e); return false; } - return true; } /** diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java index 56cfb33..1b5675d 100644 --- a/location/java/android/location/provider/LocationProvider.java +++ b/location/java/android/location/provider/LocationProvider.java @@ -18,6 +18,7 @@ package android.location.provider; import android.content.Context; import android.net.NetworkInfo; +import android.location.Criteria; import android.location.ILocationManager; import android.location.ILocationProvider; import android.location.Location; @@ -75,6 +76,10 @@ public abstract class LocationProvider { return LocationProvider.this.onGetPowerRequirement(); } + public boolean meetsCriteria(Criteria criteria) { + return LocationProvider.this.onMeetsCriteria(criteria); + } + public int getAccuracy() { return LocationProvider.this.onGetAccuracy(); } @@ -226,6 +231,12 @@ public abstract class LocationProvider { public abstract int onGetPowerRequirement(); /** + * Returns true if this provider meets the given criteria, + * false otherwise. + */ + public abstract boolean onMeetsCriteria(Criteria criteria); + + /** * Returns a constant describing horizontal accuracy of this provider. * If the provider returns finer grain or exact location, * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the diff --git a/location/java/com/android/internal/location/DummyLocationProvider.java b/location/java/com/android/internal/location/DummyLocationProvider.java index ff5e27b..e7b5143 100644 --- a/location/java/com/android/internal/location/DummyLocationProvider.java +++ b/location/java/com/android/internal/location/DummyLocationProvider.java @@ -16,6 +16,7 @@ package com.android.internal.location; +import android.location.ILocationManager; import android.location.LocationProvider; /** @@ -41,8 +42,8 @@ public class DummyLocationProvider extends LocationProvider { int mPowerRequirement; int mAccuracy; - public DummyLocationProvider(String name) { - super(name); + public DummyLocationProvider(String name, ILocationManager service) { + super(name, service); } public void setRequiresNetwork(boolean requiresNetwork) { |