summaryrefslogtreecommitdiffstats
path: root/location/java
diff options
context:
space:
mode:
authorMike Lockwood <lockwood@android.com>2010-04-01 08:10:09 -0700
committerMike Lockwood <lockwood@android.com>2010-05-21 11:47:19 -0400
commit03ca216ac19ea4e7afcb183c20c7c780f0d97756 (patch)
tree38e47efa7aeeff99fde78adb5f83446d2407eda0 /location/java
parent4979601f88154bdeda4cc5277940771ba6597c0f (diff)
downloadframeworks_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')
-rw-r--r--location/java/android/location/Criteria.java267
-rw-r--r--location/java/android/location/ILocationManager.aidl15
-rw-r--r--location/java/android/location/ILocationProvider.aidl2
-rw-r--r--location/java/android/location/LocationManager.java539
-rw-r--r--location/java/android/location/LocationProvider.java35
-rw-r--r--location/java/android/location/provider/LocationProvider.java11
-rw-r--r--location/java/com/android/internal/location/DummyLocationProvider.java5
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) {