diff options
author | Nick Pelly <npelly@google.com> | 2012-07-16 12:18:23 -0700 |
---|---|---|
committer | Nick Pelly <npelly@google.com> | 2012-08-10 14:57:09 -0700 |
commit | 6fa9ad4afcd762aea519ff61811386c23d18ddb2 (patch) | |
tree | 5b027550205ada4b972f5cc3d8073819c07d9c75 /location/java/android/location/LocationRequest.java | |
parent | c47f80f1ae96e3c8b6a750d68cc12dfbbca97254 (diff) | |
download | frameworks_base-6fa9ad4afcd762aea519ff61811386c23d18ddb2.zip frameworks_base-6fa9ad4afcd762aea519ff61811386c23d18ddb2.tar.gz frameworks_base-6fa9ad4afcd762aea519ff61811386c23d18ddb2.tar.bz2 |
Location overhaul, major commit.
Themes: Fused Location, Geofencing, LocationRequest.
API changes
o Fused location is always returned when asking for location by Criteria.
o Fused location is never returned as a LocationProvider object, nor returned
as a provider String. This wouldn't make sense because the current API
design assumes that LocationProvider's have fixed properties (accuracy, power
etc).
o The fused location engine will tune itself based on the criteria passed
by applications.
o Deprecate LocationProvider. Apps should use fused location (via Criteria
class), instead of enumerating through LocationProvider objects. It is
also over-engineered: designed for a world with a plethora of location
providers that never materialized.
o The Criteria class is also over-engineered, with many methods that aren't
currently used, but for now we won't deprecate them since they may have
value in the future. It is now used to tune the fused location engine.
o Deprecate getBestProvider() and getProvider().
o Add getLastKnownLocation(Criteria), so we can return last known
fused locations.
o Apps with only ACCESS_COARSE_LOCATION _can_ now use the GPS, but the location
they receive will be fudged to a 1km radius. They can also use NETWORK
and fused locatoins, which are fudged in the same way if necessary.
o Totally deprecate Criteria, in favor of LocationRequest.
Criteria was designed to map QOS to a location provider. What we
really need is to map QOS to _locations_.
The death knell was the conflicting ACCURACY_ constants on
Criteria, with values 1, 2, 3, 1, 2. Yes not a typo.
o Totally deprecate LocationProvider.
o Deprecate test/mock provider support. They require a named provider,
which is a concept we are moving away from. We do not yet have a
replacement, but I think its ok to deprecate since you also
need to have 'allow mock locations' checked in developer settings.
They will continue to work.
o Deprecate event codes associated with provider status. The fused
provider is _always_ available.
o Introduce Geofence data object to provide an easier path fowards
for polygons etc.
Implementation changes
o Fused implementation: incoming (GPS and NLP) location fixes are given
a weight, that exponentially decays with respect to age and accuracy.
The half-life of age is ~60 seconds, and the half-life of accuracy is
~20 meters. The fixes are weighted and combined to output a fused
location.
o Move Fused Location impl into
frameworks/base/packages/FusedLocation
o Refactor Fused Location behind the IProvider AIDL interface. This allow us
to distribute newer versions of Fused Location in a new APK, at run-time.
o Introduce ServiceWatcher.java, to refactor code used for run-time upgrades of
Fused Location, and the NLP.
o Fused Location is by default run in the system server (but can be moved to
any process or pacakge, even at run-time).
o Plumb the Criteria requirements through to the Fused Location provider via
ILocation.sendExtraCommand(). I re-used this interface to avoid modifying the
ILocation interface, which would have broken run-time upgradability of the
NLP.
o Switch the geofence manager to using fused location.
o Clean up 'adb shell dumpsys location' output.
o Introduce config_locationProviderPackageNames and
config_overlay_locationProviderPackageNames to configure the default
and overlay package names for Geocoder, NLP and FLP.
o Lots of misc cleanup.
o Improve location fudging. Apply random vector then quantize.
o Hide internal POJO's from clients of com.android.location.provider.jar
(NLP and FLP). Introduce wrappers ProviderRequestUnbundled and
ProviderPropertiesUnbundled.
o Introduce ProviderProperties to collapse all the provider accuracy/
bearing/altitude/power plumbing (that is deprecated anyway).
o DELETE lots of code: DummyLocationProvider,
o Rename the (internal) LocationProvider to LocationProviderBase.
o Plumb pid, uid and packageName throughout
LocationManagerService#Receiver to support future features.
TODO: The FLP and Geofencer have a lot of room to be more intelligent
TODO: Documentation
TODO: test test test
Change-Id: Iacefd2f176ed40ce1e23b090a164792aa8819c55
Diffstat (limited to 'location/java/android/location/LocationRequest.java')
-rw-r--r-- | location/java/android/location/LocationRequest.java | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java new file mode 100644 index 0000000..3110196 --- /dev/null +++ b/location/java/android/location/LocationRequest.java @@ -0,0 +1,321 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; +import android.util.TimeUtils; + +public final class LocationRequest implements Parcelable { + // QOS control + public static final int ACCURACY_FINE = 100; // ~1 meter + public static final int ACCURACY_BLOCK = 102; // ~100 meters + public static final int ACCURACY_CITY = 104; // ~10 km + public static final int POWER_NONE = 200; + public static final int POWER_LOW = 201; + public static final int POWER_HIGH = 203; + + private int mQuality = POWER_LOW; + private long mFastestInterval = 6 * 1000; // 6 seconds + private long mInterval = 60 * 1000; // 1 minute + private long mExpireAt = Long.MAX_VALUE; // no expiry + 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 + + public static LocationRequest create() { + LocationRequest request = new LocationRequest(); + return request; + } + + /** @hide */ + public static LocationRequest createFromDeprecatedProvider(String provider, long minTime, + float minDistance, boolean singleShot) { + if (minTime < 0) minTime = 0; + if (minDistance < 0) minDistance = 0; + + int quality; + if (LocationManager.PASSIVE_PROVIDER.equals(provider)) { + quality = POWER_NONE; + } else if (LocationManager.GPS_PROVIDER.equals(provider)) { + quality = ACCURACY_FINE; + } else { + quality = POWER_LOW; + } + + LocationRequest request = new LocationRequest() + .setProvider(provider) + .setQuality(quality) + .setInterval(minTime) + .setFastestInterval(minTime) + .setSmallestDisplacement(minDistance); + if (singleShot) request.setNumUpdates(1); + return request; + } + + /** @hide */ + public static LocationRequest createFromDeprecatedCriteria(Criteria criteria, long minTime, + float minDistance, boolean singleShot) { + if (minTime < 0) minTime = 0; + if (minDistance < 0) minDistance = 0; + + int quality; + switch (criteria.getAccuracy()) { + case Criteria.ACCURACY_COARSE: + quality = ACCURACY_BLOCK; + break; + case Criteria.ACCURACY_FINE: + quality = ACCURACY_FINE; + break; + default: { + switch (criteria.getPowerRequirement()) { + case Criteria.POWER_HIGH: + quality = POWER_HIGH; + default: + quality = POWER_LOW; + } + } + } + + LocationRequest request = new LocationRequest() + .setQuality(quality) + .setInterval(minTime) + .setFastestInterval(minTime) + .setSmallestDisplacement(minDistance); + if (singleShot) request.setNumUpdates(1); + return request; + } + + /** @hide */ + public LocationRequest() { } + + public LocationRequest setQuality(int quality) { + checkQuality(quality); + mQuality = quality; + return this; + } + + public int getQuality() { + return mQuality; + } + + public LocationRequest setInterval(long millis) { + checkInterval(millis); + mInterval = millis; + return this; + } + + public long getInterval() { + return mInterval; + } + + public LocationRequest setFastestInterval(long millis) { + checkInterval(millis); + mFastestInterval = millis; + return this; + } + + public long getFastestInterval() { + return mFastestInterval; + } + + public LocationRequest setExpireIn(long millis) { + mExpireAt = millis + SystemClock.elapsedRealtime(); + if (mExpireAt < 0) mExpireAt = 0; + return this; + } + + public LocationRequest setExpireAt(long millis) { + mExpireAt = millis; + if (mExpireAt < 0) mExpireAt = 0; + return this; + } + + public long getExpireAt() { + return mExpireAt; + } + + public int getNumUpdates() { + return mNumUpdates; + } + + /** @hide */ + public void decrementNumUpdates() { + if (mNumUpdates != Integer.MAX_VALUE) { + mNumUpdates--; + } + if (mNumUpdates < 0) { + mNumUpdates = 0; + } + } + + public LocationRequest setNumUpdates(int numUpdates) { + if (numUpdates < 0) throw new IllegalArgumentException("invalid numUpdates: " + numUpdates); + mNumUpdates = numUpdates; + return this; + } + + /** @hide */ + public LocationRequest setProvider(String provider) { + checkProvider(provider); + mProvider = provider; + return this; + } + + /** @hide */ + public String getProvider() { + return mProvider; + } + + /** @hide */ + public LocationRequest setSmallestDisplacement(float meters) { + checkDisplacement(meters); + mSmallestDisplacement = meters; + return this; + } + + /** @hide */ + public float getSmallestDisplacement() { + return mSmallestDisplacement; + } + + /** @hide */ + public LocationRequest applyCoarsePermissionRestrictions() { + switch (mQuality) { + case ACCURACY_FINE: + mQuality = ACCURACY_BLOCK; + break; + } + // cap fastest interval to 6 seconds + if (mFastestInterval < 6 * 1000) mFastestInterval = 6 * 1000; + // cap requested interval to 1 minute + if (mInterval < 60 * 1000) mInterval = 60 * 1000; + return this; + } + + private static void checkInterval(long millis) { + if (millis < 0) { + throw new IllegalArgumentException("invalid interval: " + millis); + } + } + + private static void checkQuality(int quality) { + switch (quality) { + case ACCURACY_FINE: + case ACCURACY_BLOCK: + case ACCURACY_CITY: + case POWER_NONE: + case POWER_LOW: + case POWER_HIGH: + break; + default: + throw new IllegalArgumentException("invalid quality: " + quality); + } + } + + private static void checkDisplacement(float meters) { + if (meters < 0.0f) { + throw new IllegalArgumentException("invalid displacement: " + meters); + } + } + + private static void checkProvider(String name) { + if (name == null) { + throw new IllegalArgumentException("invalid provider: " + name); + } + } + + public static final Parcelable.Creator<LocationRequest> CREATOR = + new Parcelable.Creator<LocationRequest>() { + @Override + public LocationRequest createFromParcel(Parcel in) { + LocationRequest request = new LocationRequest(); + request.setQuality(in.readInt()); + request.setFastestInterval(in.readLong()); + request.setInterval(in.readLong()); + request.setExpireAt(in.readLong()); + request.setNumUpdates(in.readInt()); + request.setSmallestDisplacement(in.readFloat()); + String provider = in.readString(); + if (provider != null) request.setProvider(provider); + return request; + } + @Override + public LocationRequest[] newArray(int size) { + return new LocationRequest[size]; + } + }; + @Override + public int describeContents() { + return 0; + } + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mQuality); + parcel.writeLong(mFastestInterval); + parcel.writeLong(mInterval); + parcel.writeLong(mExpireAt); + parcel.writeInt(mNumUpdates); + parcel.writeFloat(mSmallestDisplacement); + parcel.writeString(mProvider); + } + + /** @hide */ + public static String qualityToString(int quality) { + switch (quality) { + case ACCURACY_FINE: + return "ACCURACY_FINE"; + case ACCURACY_BLOCK: + return "ACCURACY_BLOCK"; + case ACCURACY_CITY: + return "ACCURACY_CITY"; + case POWER_NONE: + return "POWER_NONE"; + case POWER_LOW: + return "POWER_LOW"; + case POWER_HIGH: + return "POWER_HIGH"; + default: + return "???"; + } + } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("Request[").append(qualityToString(mQuality)); + if (mProvider != null) s.append(' ').append(mProvider); + if (mQuality != POWER_NONE) { + s.append(" requested="); + TimeUtils.formatDuration(mInterval, s); + } + s.append(" fastest="); + TimeUtils.formatDuration(mFastestInterval, s); + if (mExpireAt != Long.MAX_VALUE) { + long expireIn = mExpireAt - SystemClock.elapsedRealtime(); + s.append(" expireIn="); + TimeUtils.formatDuration(expireIn, s); + } + if (mNumUpdates != Integer.MAX_VALUE){ + s.append(" num=").append(mNumUpdates); + } + s.append(']'); + return s.toString(); + } +} |