summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--location/java/android/location/Location.java42
-rw-r--r--location/java/android/location/LocationRequest.java2
-rw-r--r--packages/FusedLocation/src/com/android/location/fused/FusionEngine.java4
-rw-r--r--services/java/com/android/server/LocationManagerService.java111
-rw-r--r--services/java/com/android/server/location/LocationFudger.java20
-rw-r--r--services/java/com/android/server/location/PassiveProvider.java2
6 files changed, 127 insertions, 54 deletions
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 40cb1a8..f6bf76c 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -59,6 +59,16 @@ public class Location implements Parcelable {
*/
public static final int FORMAT_SECONDS = 2;
+ /**
+ * @hide
+ */
+ public static final String EXTRA_COARSE_LOCATION = "coarseLocation";
+
+ /**
+ * @hide
+ */
+ public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
+
private String mProvider;
private long mTime = 0;
private long mElapsedRealtimeNano = 0;
@@ -897,4 +907,36 @@ public class Location implements Parcelable {
parcel.writeFloat(mAccuracy);
parcel.writeBundle(mExtras);
}
+
+ /**
+ * Returns one of the optional extra {@link Location}s that can be attached
+ * to this Location.
+ *
+ * @param key the key associated with the desired extra Location
+ * @return the extra Location, or null if unavailable
+ * @hide
+ */
+ public Location getExtraLocation(String key) {
+ if (mExtras != null) {
+ Parcelable value = mExtras.getParcelable(key);
+ if (value instanceof Location) {
+ return (Location) value;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Attaches an extra {@link Location} to this Location.
+ *
+ * @param key the key associated with the Location extra
+ * @param location the Location to attach
+ * @hide
+ */
+ public void setExtraLocation(String key, Location value) {
+ if (mExtras == null) {
+ mExtras = new Bundle();
+ }
+ mExtras.putParcelable(key, value);
+ }
}
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index b1863b8..f4f7b09 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -144,7 +144,7 @@ public final class LocationRequest implements Parcelable {
private int mNumUpdates = Integer.MAX_VALUE; // no expiry
private float mSmallestDisplacement = 0.0f; // meters
- private String mProvider = null; // for deprecated API's that explicitly request a provider
+ private String mProvider = LocationManager.FUSED_PROVIDER; // for deprecated APIs that explicitly request a provider
/**
* Create a location request with default parameters.
diff --git a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
index 1c22c7a..b83521a 100644
--- a/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
+++ b/packages/FusedLocation/src/com/android/location/fused/FusionEngine.java
@@ -302,6 +302,10 @@ public class FusionEngine implements LocationListener {
0.0, 360.0));
}
+ if (mNetworkLocation != null) {
+ fused.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, mNetworkLocation);
+ }
+
mFusedLocation = fused;
mCallback.reportLocation(mFusedLocation);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 197f6ab..840d432 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -900,25 +900,41 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return receiver;
}
+ private boolean isProviderAllowedByCoarsePermission(String provider) {
+ if (LocationManager.FUSED_PROVIDER.equals(provider)) {
+ return true;
+ }
+ if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+ return true;
+ }
+ if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
+ return true;
+ }
+ return false;
+ }
+
private String checkPermissionAndRequest(LocationRequest request) {
String perm = checkPermission();
if (ACCESS_COARSE_LOCATION.equals(perm)) {
- switch (request.getQuality()) {
- case LocationRequest.ACCURACY_FINE:
- request.setQuality(LocationRequest.ACCURACY_BLOCK);
- break;
- case LocationRequest.POWER_HIGH:
- request.setQuality(LocationRequest.POWER_LOW);
- break;
- }
- // throttle
- if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
- request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
- }
- if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
- request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
- }
+ if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
+ throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
+ }
+ switch (request.getQuality()) {
+ case LocationRequest.ACCURACY_FINE:
+ request.setQuality(LocationRequest.ACCURACY_BLOCK);
+ break;
+ case LocationRequest.POWER_HIGH:
+ request.setQuality(LocationRequest.POWER_LOW);
+ break;
+ }
+ // throttle
+ if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+ request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
+ }
+ if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+ request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
+ }
}
// make getFastestInterval() the minimum of interval and fastest interval
if (request.getFastestInterval() > request.getInterval()) {
@@ -990,7 +1006,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// use the fused provider
if (request == null) request = DEFAULT_LOCATION_REQUEST;
String name = request.getProvider();
- if (name == null) name = LocationManager.FUSED_PROVIDER;
+ if (name == null) {
+ throw new IllegalArgumentException("provider name must not be null");
+ }
LocationProviderInterface provider = mProvidersByName.get(name);
if (provider == null) {
throw new IllegalArgumentException("provider doesn't exisit: " + provider);
@@ -1094,12 +1112,19 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (!isAllowedBySettingsLocked(name)) return null;
Location location = mLastLocation.get(name);
+ if (location == null) {
+ return null;
+ }
if (ACCESS_FINE_LOCATION.equals(perm)) {
return location;
} else {
- return mLocationFudger.getOrCreate(location);
+ Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation != null) {
+ return mLocationFudger.getOrCreate(noGPSLocation);
+ }
}
}
+ return null;
}
@Override
@@ -1329,17 +1354,29 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) return;
- // Add the coarse location as an extra
- Location coarse = mLocationFudger.getOrCreate(location);
-
// Update last known locations
+ Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ Location lastNoGPSLocation = null;
Location lastLocation = mLastLocation.get(provider);
if (lastLocation == null) {
lastLocation = new Location(provider);
mLastLocation.put(provider, lastLocation);
+ } else {
+ lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
+ if (noGPSLocation == null && lastNoGPSLocation != null) {
+ // New location has no no-GPS location: adopt last no-GPS location. This is set
+ // directly into location because we do not want to notify COARSE clients.
+ location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
+ }
}
lastLocation.set(location);
+ // Fetch coarse location
+ Location coarseLocation = null;
+ if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
+ coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
+ }
+
// Fetch latest status update time
long newStatusUpdateTime = p.getStatusUpdateTime();
@@ -1361,29 +1398,31 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
continue;
}
+ Location notifyLocation = null;
if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
- location = lastLocation; // use fine location
+ notifyLocation = lastLocation; // use fine location
} else {
- location = coarse; // use coarse location
- }
-
- Location lastLoc = r.mLastFixBroadcast;
- if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
- if (lastLoc == null) {
- lastLoc = new Location(location);
- r.mLastFixBroadcast = lastLoc;
- } else {
- lastLoc.set(location);
- }
- if (!receiver.callLocationChangedLocked(location)) {
- Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
- receiverDead = true;
+ notifyLocation = coarseLocation; // use coarse location if available
+ }
+ if (notifyLocation != null) {
+ Location lastLoc = r.mLastFixBroadcast;
+ if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
+ if (lastLoc == null) {
+ lastLoc = new Location(notifyLocation);
+ r.mLastFixBroadcast = lastLoc;
+ } else {
+ lastLoc.set(notifyLocation);
+ }
+ if (!receiver.callLocationChangedLocked(notifyLocation)) {
+ Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
+ receiverDead = true;
+ }
}
}
long prevStatusUpdateTime = r.mLastStatusBroadcast;
if ((newStatusUpdateTime > prevStatusUpdateTime) &&
- (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
+ (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
r.mLastStatusBroadcast = newStatusUpdateTime;
if (!receiver.callStatusChangedLocked(provider, status, extras)) {
diff --git a/services/java/com/android/server/location/LocationFudger.java b/services/java/com/android/server/location/LocationFudger.java
index 84fd255..2a68743 100644
--- a/services/java/com/android/server/location/LocationFudger.java
+++ b/services/java/com/android/server/location/LocationFudger.java
@@ -22,6 +22,7 @@ import java.security.SecureRandom;
import android.content.Context;
import android.database.ContentObserver;
import android.location.Location;
+import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
@@ -40,8 +41,6 @@ public class LocationFudger {
private static final boolean D = false;
private static final String TAG = "LocationFudge";
- private static final String EXTRA_COARSE_LOCATION = "coarseLocation";
-
/**
* Default coarse accuracy in meters.
*/
@@ -168,18 +167,10 @@ public class LocationFudger {
*/
public Location getOrCreate(Location location) {
synchronized (mLock) {
- Bundle extras = location.getExtras();
- if (extras == null) {
- return addCoarseLocationExtraLocked(location);
- }
- Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
- if (parcel == null) {
- return addCoarseLocationExtraLocked(location);
- }
- if (!(parcel instanceof Location)) {
+ Location coarse = location.getExtraLocation(Location.EXTRA_COARSE_LOCATION);
+ if (coarse == null) {
return addCoarseLocationExtraLocked(location);
}
- Location coarse = (Location) parcel;
if (coarse.getAccuracy() < mAccuracyInMeters) {
return addCoarseLocationExtraLocked(location);
}
@@ -188,11 +179,8 @@ public class LocationFudger {
}
private Location addCoarseLocationExtraLocked(Location location) {
- Bundle extras = location.getExtras();
- if (extras == null) extras = new Bundle();
Location coarse = createCoarseLocked(location);
- extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
- location.setExtras(extras);
+ location.setExtraLocation(Location.EXTRA_COARSE_LOCATION, coarse);
return coarse;
}
diff --git a/services/java/com/android/server/location/PassiveProvider.java b/services/java/com/android/server/location/PassiveProvider.java
index 0ce21b7..71bae07 100644
--- a/services/java/com/android/server/location/PassiveProvider.java
+++ b/services/java/com/android/server/location/PassiveProvider.java
@@ -114,6 +114,6 @@ public class PassiveProvider implements LocationProviderInterface {
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("mReportLocaiton=" + mReportLocation);
+ pw.println("mReportLocation=" + mReportLocation);
}
}