summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server
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 /services/java/com/android/server
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 'services/java/com/android/server')
-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
6 files changed, 405 insertions, 36 deletions
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) {
}