summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--services/java/com/android/server/LocationManagerService.java299
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java61
-rw-r--r--services/java/com/android/server/location/LocationProviderInterface.java4
-rw-r--r--services/java/com/android/server/location/LocationProviderProxy.java40
-rw-r--r--services/java/com/android/server/location/MockProvider.java27
-rw-r--r--services/java/com/android/server/location/PassiveProvider.java10
13 files changed, 969 insertions, 346 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) {
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 33b0e81..74249f3 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -30,6 +30,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.database.Cursor;
import android.location.Address;
+import android.location.Criteria;
import android.location.GeocoderParams;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
@@ -68,6 +69,8 @@ import com.android.server.location.PassiveProvider;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -610,10 +613,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return out;
}
- public List<String> getProviders(boolean enabledOnly) {
+ public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
try {
synchronized (mLock) {
- return _getProvidersLocked(enabledOnly);
+ return _getProvidersLocked(criteria, enabledOnly);
}
} catch (SecurityException se) {
throw se;
@@ -623,7 +626,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- private List<String> _getProvidersLocked(boolean enabledOnly) {
+ private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
if (LOCAL_LOGV) {
Slog.v(TAG, "getProviders");
}
@@ -635,12 +638,225 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (enabledOnly && !isAllowedBySettingsLocked(name)) {
continue;
}
+ if (criteria != null && !p.meetsCriteria(criteria)) {
+ continue;
+ }
out.add(name);
}
}
return out;
}
+ /**
+ * 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 class LpPowerComparator implements Comparator<LocationProviderInterface> {
+ public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+ // Smaller is better
+ return (l1.getPowerRequirement() - l2.getPowerRequirement());
+ }
+
+ public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+ return (l1.getPowerRequirement() == l2.getPowerRequirement());
+ }
+ }
+
+ private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
+ public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+ // Smaller is better
+ return (l1.getAccuracy() - l2.getAccuracy());
+ }
+
+ public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+ return (l1.getAccuracy() == l2.getAccuracy());
+ }
+ }
+
+ private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
+
+ private static final int ALTITUDE_SCORE = 4;
+ private static final int BEARING_SCORE = 4;
+ private static final int SPEED_SCORE = 4;
+
+ private int score(LocationProviderInterface p) {
+ return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
+ (p.supportsBearing() ? BEARING_SCORE : 0) +
+ (p.supportsSpeed() ? SPEED_SCORE : 0);
+ }
+
+ public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
+ return (score(l2) - score(l1)); // Bigger is better
+ }
+
+ public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
+ return (score(l1) == score(l2));
+ }
+ }
+
+ private LocationProviderInterface best(List<String> providerNames) {
+ ArrayList<LocationProviderInterface> providers;
+ synchronized (mLock) {
+ providers = new ArrayList<LocationProviderInterface>(mProviders.size());
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ providers.add(mProviders.get(i));
+ }
+ }
+
+ 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;
+
+ ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
+ idx = 0;
+ size = providers.size();
+ while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
+ tmp.add(providers.get(idx));
+ idx++;
+ }
+
+ // 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);
+ }
+
+ ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
+ idx = 0;
+ size = tmp.size();
+ while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
+ tmp2.add(tmp.get(idx));
+ idx++;
+ }
+
+ // Finally, sort by capability "score"
+ Collections.sort(tmp2, new LpCapabilityComparator());
+ return tmp2.get(0);
+ }
+
+ /**
+ * Returns the name of the provider that best meets the given criteria. Only providers
+ * that are permitted to be accessed by the calling activity will be
+ * returned. If several providers meet the criteria, the one with the best
+ * accuracy is returned. If no provider meets the criteria,
+ * the criteria are loosened in the following sequence:
+ *
+ * <ul>
+ * <li> power requirement
+ * <li> accuracy
+ * <li> bearing
+ * <li> speed
+ * <li> altitude
+ * </ul>
+ *
+ * <p> Note that the requirement on monetary cost is not removed
+ * in this process.
+ *
+ * @param criteria the criteria that need to be matched
+ * @param enabledOnly if true then only a provider that is currently enabled is returned
+ * @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 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();
+ }
+
+ // 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();
+ }
+
+ return null;
+ }
+
+ public boolean providerMeetsCriteria(String provider, Criteria criteria) {
+ LocationProviderInterface p = mProvidersByName.get(provider);
+ if (p == null) {
+ throw new IllegalArgumentException("provider=" + provider);
+ }
+ return p.meetsCriteria(criteria);
+ }
+
private void updateProvidersLocked() {
for (int i = mProviders.size() - 1; i >= 0; i--) {
LocationProviderInterface p = mProviders.get(i);
@@ -717,6 +933,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
final Receiver mReceiver;
final long mMinTime;
final float mMinDistance;
+ final boolean mSingleShot;
final int mUid;
Location mLastFixBroadcast;
long mLastStatusBroadcast;
@@ -724,12 +941,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
/**
* Note: must be constructed with lock held.
*/
- UpdateRecord(String provider, long minTime, float minDistance,
+ UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
Receiver receiver, int uid) {
mProvider = provider;
mReceiver = receiver;
mMinTime = minTime;
mMinDistance = minDistance;
+ mSingleShot = singleShot;
mUid = uid;
ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
@@ -764,6 +982,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
pw.println(prefix + this);
pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
+ pw.println(prefix + "mSingleShot=" + mSingleShot);
pw.println(prefix + "mUid=" + mUid);
pw.println(prefix + "mLastFixBroadcast:");
if (mLastFixBroadcast != null) {
@@ -819,12 +1038,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return false;
}
- public void requestLocationUpdates(String provider,
- long minTime, float minDistance, ILocationListener listener) {
-
+ public void requestLocationUpdates(String provider, Criteria criteria,
+ long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
+ if (criteria != null) {
+ // FIXME - should we consider using multiple providers simultaneously
+ // rather than only the best one?
+ // Should we do anything different for single shot fixes?
+ provider = getBestProvider(criteria, true);
+ if (provider == null) {
+ throw new IllegalArgumentException("no providers found for criteria");
+ }
+ }
try {
synchronized (mLock) {
- requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
+ requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
+ getReceiver(listener));
}
} catch (SecurityException se) {
throw se;
@@ -835,11 +1063,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- public void requestLocationUpdatesPI(String provider,
- long minTime, float minDistance, PendingIntent intent) {
+ public void requestLocationUpdatesPI(String provider, Criteria criteria,
+ long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
+ if (criteria != null) {
+ // FIXME - should we consider using multiple providers simultaneously
+ // rather than only the best one?
+ // Should we do anything different for single shot fixes?
+ provider = getBestProvider(criteria, true);
+ if (provider == null) {
+ throw new IllegalArgumentException("no providers found for criteria");
+ }
+ }
try {
synchronized (mLock) {
- requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
+ requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
+ getReceiver(intent));
}
} catch (SecurityException se) {
throw se;
@@ -850,8 +1088,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
- private void requestLocationUpdatesLocked(String provider,
- long minTime, float minDistance, Receiver receiver) {
+ private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
+ boolean singleShot, Receiver receiver) {
if (LOCAL_LOGV) {
Slog.v(TAG, "_requestLocationUpdates: listener = " + receiver);
}
@@ -868,7 +1106,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
boolean newUid = !providerHasListener(provider, callingUid, null);
long identity = Binder.clearCallingIdentity();
try {
- UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
+ UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
+ receiver, callingUid);
UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
if (oldRecord != null) {
oldRecord.disposeLocked();
@@ -882,7 +1121,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (isProviderEnabled) {
long minTimeForProvider = getMinTimeLocked(provider);
p.setMinTime(minTimeForProvider);
- p.enableLocationTracking(true);
+ // try requesting single shot if singleShot is true, and fall back to
+ // regular location tracking if requestSingleShotFix() is not supported
+ if (!singleShot || !p.requestSingleShotFix()) {
+ p.enableLocationTracking(true);
+ }
} else {
// Notify the listener that updates are currently disabled
receiver.callProviderEnabledLocked(provider, false);
@@ -1288,7 +1531,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
for (int i = mProviders.size() - 1; i >= 0; i--) {
LocationProviderInterface provider = mProviders.get(i);
- requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
+ requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f,
+ false, mProximityReceiver);
}
}
}
@@ -1486,6 +1730,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
for (int i=0; i<N; i++) {
UpdateRecord r = records.get(i);
Receiver receiver = r.mReceiver;
+ boolean receiverDead = false;
Location lastLoc = r.mLastFixBroadcast;
if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
@@ -1497,10 +1742,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
if (!receiver.callLocationChangedLocked(location)) {
Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<Receiver>();
- }
- deadReceivers.add(receiver);
+ receiverDead = true;
}
}
@@ -1510,13 +1752,18 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
r.mLastStatusBroadcast = newStatusUpdateTime;
if (!receiver.callStatusChangedLocked(provider, status, extras)) {
+ receiverDead = true;
Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
- if (deadReceivers == null) {
- deadReceivers = new ArrayList<Receiver>();
- }
- if (!deadReceivers.contains(receiver)) {
- deadReceivers.add(receiver);
- }
+ }
+ }
+
+ // remove receiver if it is dead or we just processed a single shot request
+ if (receiverDead || r.mSingleShot) {
+ if (deadReceivers == null) {
+ deadReceivers = new ArrayList<Receiver>();
+ }
+ if (!deadReceivers.contains(receiver)) {
+ deadReceivers.add(receiver);
}
}
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 19c9018..6fe02c2 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -150,6 +150,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static final int UPDATE_LOCATION = 7;
private static final int ADD_LISTENER = 8;
private static final int REMOVE_LISTENER = 9;
+ private static final int REQUEST_SINGLE_SHOT = 10;
private static final String PROPERTIES_FILE = "/etc/gps.conf";
@@ -190,6 +191,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
// true if we started navigation
private boolean mStarted;
+ // true if single shot request is in progress
+ private boolean mSingleShot;
+
// capabilities of the GPS engine
private int mEngineCapabilities;
@@ -318,7 +322,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (action.equals(ALARM_WAKEUP)) {
if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
- startNavigating();
+ startNavigating(false);
} else if (action.equals(ALARM_TIMEOUT)) {
if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
hibernate();
@@ -599,6 +603,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
/**
+ * Returns true if this provider meets the given criteria,
+ * false otherwise.
+ */
+ public boolean meetsCriteria(Criteria criteria) {
+ return (criteria.getPowerRequirement() != Criteria.POWER_LOW);
+ }
+
+ /**
* Returns the horizontal accuracy of this provider
*
* @return the accuracy of location from this provider, as one
@@ -707,6 +719,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
public void enableLocationTracking(boolean enable) {
+ // FIXME - should set a flag here to avoid race conditions with single shot request
synchronized (mHandler) {
sendMessage(ENABLE_TRACKING, (enable ? 1 : 0), null);
}
@@ -716,7 +729,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (enable) {
mTTFF = 0;
mLastFixTime = 0;
- startNavigating();
+ startNavigating(false);
} else {
if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
mAlarmManager.cancel(mWakeupIntent);
@@ -726,6 +739,25 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
+ public boolean requestSingleShotFix() {
+ if (mStarted) {
+ // cannot do single shot if already navigating
+ return false;
+ }
+ synchronized (mHandler) {
+ mHandler.removeMessages(REQUEST_SINGLE_SHOT);
+ Message m = Message.obtain(mHandler, REQUEST_SINGLE_SHOT);
+ mHandler.sendMessage(m);
+ }
+ return true;
+ }
+
+ private void handleRequestSingleShot() {
+ mTTFF = 0;
+ mLastFixTime = 0;
+ startNavigating(true);
+ }
+
public void setMinTime(long minTime) {
if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
@@ -875,16 +907,20 @@ public class GpsLocationProvider implements LocationProviderInterface {
return false;
}
- private void startNavigating() {
+ private void startNavigating(boolean singleShot) {
if (!mStarted) {
if (DEBUG) Log.d(TAG, "startNavigating");
mStarted = true;
- if (hasCapability(GPS_CAPABILITY_MSB) &&
- Settings.Secure.getInt(mContext.getContentResolver(),
+ mSingleShot = singleShot;
+ mPositionMode = GPS_POSITION_MODE_STANDALONE;
+
+ if (Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
- mPositionMode = GPS_POSITION_MODE_MS_BASED;
- } else {
- mPositionMode = GPS_POSITION_MODE_STANDALONE;
+ if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
+ mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
+ } else if (hasCapability(GPS_CAPABILITY_MSA)) {
+ mPositionMode = GPS_POSITION_MODE_MS_BASED;
+ }
}
int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
@@ -918,6 +954,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
if (DEBUG) Log.d(TAG, "stopNavigating");
if (mStarted) {
mStarted = false;
+ mSingleShot = false;
native_stop();
mTTFF = 0;
mLastFixTime = 0;
@@ -1008,6 +1045,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
}
+ if (mSingleShot) {
+ stopNavigating();
+ }
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
// we want to time out if we do not receive a fix
// within the time out and we are requesting infrequent fixes
@@ -1022,7 +1062,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
updateStatus(LocationProvider.AVAILABLE, mSvCount);
}
- if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval > 1000) {
+ if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && mFixInterval > 1000) {
if (DEBUG) Log.d(TAG, "got fix, hibernating");
hibernate();
}
@@ -1369,6 +1409,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
case ENABLE_TRACKING:
handleEnableLocationTracking(msg.arg1 == 1);
break;
+ case REQUEST_SINGLE_SHOT:
+ handleRequestSingleShot();
+ break;
case UPDATE_NETWORK_STATE:
handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
break;
diff --git a/services/java/com/android/server/location/LocationProviderInterface.java b/services/java/com/android/server/location/LocationProviderInterface.java
index a472143..084ab81 100644
--- a/services/java/com/android/server/location/LocationProviderInterface.java
+++ b/services/java/com/android/server/location/LocationProviderInterface.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.location.Criteria;
import android.location.Location;
import android.net.NetworkInfo;
import android.os.Bundle;
@@ -35,6 +36,7 @@ public interface LocationProviderInterface {
boolean supportsSpeed();
boolean supportsBearing();
int getPowerRequirement();
+ boolean meetsCriteria(Criteria criteria);
int getAccuracy();
boolean isEnabled();
void enable();
@@ -42,6 +44,8 @@ public interface LocationProviderInterface {
int getStatus(Bundle extras);
long getStatusUpdateTime();
void enableLocationTracking(boolean enable);
+ /* returns false if single shot is not supported */
+ boolean requestSingleShotFix();
String getInternalState();
void setMinTime(long minTime);
void updateNetworkState(int state, NetworkInfo info);
diff --git a/services/java/com/android/server/location/LocationProviderProxy.java b/services/java/com/android/server/location/LocationProviderProxy.java
index 3e118f9..24d7737 100644
--- a/services/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/java/com/android/server/location/LocationProviderProxy.java
@@ -20,6 +20,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.location.Criteria;
import android.location.ILocationProvider;
import android.location.Location;
import android.net.NetworkInfo;
@@ -97,7 +98,7 @@ public class LocationProviderProxy implements LocationProviderInterface {
if (mCachedAttributes == null) {
try {
- mCachedAttributes = new DummyLocationProvider(mName);
+ mCachedAttributes = new DummyLocationProvider(mName, null);
mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
mCachedAttributes.setRequiresCell(provider.requiresCell());
@@ -199,6 +200,39 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
}
+ public boolean meetsCriteria(Criteria criteria) {
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.meetsCriteria(criteria);
+ } catch (RemoteException e) {
+ }
+ }
+ // default implementation if we lost connection to the provider
+ 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()) {
+ return false;
+ }
+ return true;
+ }
+
public int getAccuracy() {
if (mCachedAttributes != null) {
return mCachedAttributes.getAccuracy();
@@ -297,6 +331,10 @@ public class LocationProviderProxy implements LocationProviderInterface {
}
}
+ public boolean requestSingleShotFix() {
+ return false;
+ }
+
public long getMinTime() {
return mMinTime;
}
diff --git a/services/java/com/android/server/location/MockProvider.java b/services/java/com/android/server/location/MockProvider.java
index e3f3346..01b34b7 100644
--- a/services/java/com/android/server/location/MockProvider.java
+++ b/services/java/com/android/server/location/MockProvider.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.location.Criteria;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationProvider;
@@ -138,6 +139,28 @@ public class MockProvider implements LocationProviderInterface {
return mSupportsSpeed;
}
+ public boolean meetsCriteria(Criteria criteria) {
+ if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) &&
+ (criteria.getAccuracy() < mAccuracy)) {
+ return false;
+ }
+ int criteriaPower = criteria.getPowerRequirement();
+ if ((criteriaPower != Criteria.NO_REQUIREMENT) &&
+ (criteriaPower < mPowerRequirement)) {
+ return false;
+ }
+ if (criteria.isAltitudeRequired() && !mSupportsAltitude) {
+ return false;
+ }
+ if (criteria.isSpeedRequired() && !mSupportsSpeed) {
+ return false;
+ }
+ if (criteria.isBearingRequired() && !mSupportsBearing) {
+ return false;
+ }
+ return true;
+ }
+
public void setLocation(Location l) {
mLocation.set(l);
mHasLocation = true;
@@ -174,6 +197,10 @@ public class MockProvider implements LocationProviderInterface {
public void enableLocationTracking(boolean enable) {
}
+ public boolean requestSingleShotFix() {
+ return false;
+ }
+
public void setMinTime(long minTime) {
}
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 5ed1558..7fc93f8 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -16,6 +16,7 @@
package com.android.server.location;
+import android.location.Criteria;
import android.location.ILocationManager;
import android.location.Location;
import android.location.LocationManager;
@@ -79,6 +80,11 @@ public class PassiveProvider implements LocationProviderInterface {
return -1;
}
+ public boolean meetsCriteria(Criteria criteria) {
+ // We do not want to match the special passive provider based on criteria.
+ return false;
+ }
+
public int getAccuracy() {
return -1;
}
@@ -113,6 +119,10 @@ public class PassiveProvider implements LocationProviderInterface {
mTracking = enable;
}
+ public boolean requestSingleShotFix() {
+ return false;
+ }
+
public void setMinTime(long minTime) {
}