* commit 'b6c703fda4995ccd702d4af65e12309d71732594': Location overhaul, major commit.
This commit is contained in:
@@ -197,8 +197,8 @@ LOCAL_SRC_FILES += \
|
||||
location/java/android/location/IGpsStatusProvider.aidl \
|
||||
location/java/android/location/ILocationListener.aidl \
|
||||
location/java/android/location/ILocationManager.aidl \
|
||||
location/java/android/location/ILocationProvider.aidl \
|
||||
location/java/android/location/INetInitiatedListener.aidl \
|
||||
location/java/com/android/internal/location/ILocationProvider.aidl \
|
||||
media/java/android/media/IAudioService.aidl \
|
||||
media/java/android/media/IAudioFocusDispatcher.aidl \
|
||||
media/java/android/media/IAudioRoutesObserver.aidl \
|
||||
@@ -306,7 +306,11 @@ aidl_files := \
|
||||
frameworks/base/graphics/java/android/graphics/Rect.aidl \
|
||||
frameworks/base/graphics/java/android/graphics/Region.aidl \
|
||||
frameworks/base/location/java/android/location/Criteria.aidl \
|
||||
frameworks/base/location/java/android/location/Geofence.aidl \
|
||||
frameworks/base/location/java/android/location/Location.aidl \
|
||||
frameworks/base/location/java/android/location/LocationRequest.aidl \
|
||||
frameworks/base/location/java/com/android/internal/location/ProviderProperties.aidl \
|
||||
frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \
|
||||
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
|
||||
frameworks/base/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
|
||||
frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl \
|
||||
|
||||
128
api/current.txt
128
api/current.txt
@@ -10451,7 +10451,7 @@ package android.location {
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public class Criteria implements android.os.Parcelable {
|
||||
public deprecated class Criteria implements android.os.Parcelable {
|
||||
ctor public Criteria();
|
||||
ctor public Criteria(android.location.Criteria);
|
||||
method public int describeContents();
|
||||
@@ -10497,6 +10497,13 @@ package android.location {
|
||||
method public static boolean isPresent();
|
||||
}
|
||||
|
||||
public final class Geofence implements android.os.Parcelable {
|
||||
method public static android.location.Geofence createCircle(double, double, float);
|
||||
method public int describeContents();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
}
|
||||
|
||||
public final class GpsSatellite {
|
||||
method public float getAzimuth();
|
||||
method public float getElevation();
|
||||
@@ -10534,7 +10541,7 @@ package android.location {
|
||||
method public int describeContents();
|
||||
method public static void distanceBetween(double, double, double, double, float[]);
|
||||
method public float distanceTo(android.location.Location);
|
||||
method public void dump(android.util.Printer, java.lang.String);
|
||||
method public deprecated void dump(android.util.Printer, java.lang.String);
|
||||
method public float getAccuracy();
|
||||
method public double getAltitude();
|
||||
method public float getBearing();
|
||||
@@ -10582,65 +10589,96 @@ package android.location {
|
||||
public class LocationManager {
|
||||
method public boolean addGpsStatusListener(android.location.GpsStatus.Listener);
|
||||
method public boolean addNmeaListener(android.location.GpsStatus.NmeaListener);
|
||||
method public void addProximityAlert(double, double, float, long, android.app.PendingIntent);
|
||||
method public void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
|
||||
method public void clearTestProviderEnabled(java.lang.String);
|
||||
method public void clearTestProviderLocation(java.lang.String);
|
||||
method public void clearTestProviderStatus(java.lang.String);
|
||||
method public java.util.List<java.lang.String> getAllProviders();
|
||||
method public java.lang.String getBestProvider(android.location.Criteria, boolean);
|
||||
method public deprecated void addProximityAlert(double, double, float, long, android.app.PendingIntent);
|
||||
method public deprecated void addTestProvider(java.lang.String, boolean, boolean, boolean, boolean, boolean, boolean, boolean, int, int);
|
||||
method public deprecated void clearTestProviderEnabled(java.lang.String);
|
||||
method public deprecated void clearTestProviderLocation(java.lang.String);
|
||||
method public deprecated void clearTestProviderStatus(java.lang.String);
|
||||
method public deprecated java.util.List<java.lang.String> getAllProviders();
|
||||
method public deprecated java.lang.String getBestProvider(android.location.Criteria, boolean);
|
||||
method public android.location.GpsStatus getGpsStatus(android.location.GpsStatus);
|
||||
method public android.location.Location getLastKnownLocation(java.lang.String);
|
||||
method public android.location.LocationProvider getProvider(java.lang.String);
|
||||
method public java.util.List<java.lang.String> getProviders(boolean);
|
||||
method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
|
||||
method public boolean isProviderEnabled(java.lang.String);
|
||||
method public deprecated android.location.Location getLastKnownLocation(java.lang.String);
|
||||
method public deprecated android.location.Location getLastKnownLocation(android.location.Criteria);
|
||||
method public android.location.Location getLastLocation(android.location.LocationRequest);
|
||||
method public deprecated android.location.LocationProvider getProvider(java.lang.String);
|
||||
method public deprecated java.util.List<java.lang.String> getProviders(boolean);
|
||||
method public deprecated java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
|
||||
method public deprecated boolean isProviderEnabled(java.lang.String);
|
||||
method public void removeAllGeofences(android.app.PendingIntent);
|
||||
method public void removeGeofence(android.location.Geofence, android.app.PendingIntent);
|
||||
method public void removeGpsStatusListener(android.location.GpsStatus.Listener);
|
||||
method public void removeNmeaListener(android.location.GpsStatus.NmeaListener);
|
||||
method public void removeProximityAlert(android.app.PendingIntent);
|
||||
method public void removeTestProvider(java.lang.String);
|
||||
method public deprecated void removeProximityAlert(android.app.PendingIntent);
|
||||
method public deprecated void removeTestProvider(java.lang.String);
|
||||
method public void removeUpdates(android.location.LocationListener);
|
||||
method public void removeUpdates(android.app.PendingIntent);
|
||||
method public void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener);
|
||||
method public void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener, android.os.Looper);
|
||||
method public void requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper);
|
||||
method public void requestLocationUpdates(java.lang.String, long, float, android.app.PendingIntent);
|
||||
method public void requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent);
|
||||
method public void requestSingleUpdate(java.lang.String, android.location.LocationListener, android.os.Looper);
|
||||
method public void requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper);
|
||||
method public void requestSingleUpdate(java.lang.String, android.app.PendingIntent);
|
||||
method public void requestSingleUpdate(android.location.Criteria, android.app.PendingIntent);
|
||||
method public boolean sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle);
|
||||
method public void setTestProviderEnabled(java.lang.String, boolean);
|
||||
method public void setTestProviderLocation(java.lang.String, android.location.Location);
|
||||
method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
|
||||
field public static final java.lang.String GPS_PROVIDER = "gps";
|
||||
method public void requestGeofence(android.location.LocationRequest, android.location.Geofence, android.app.PendingIntent);
|
||||
method public deprecated void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener);
|
||||
method public deprecated void requestLocationUpdates(java.lang.String, long, float, android.location.LocationListener, android.os.Looper);
|
||||
method public deprecated void requestLocationUpdates(long, float, android.location.Criteria, android.location.LocationListener, android.os.Looper);
|
||||
method public deprecated void requestLocationUpdates(java.lang.String, long, float, android.app.PendingIntent);
|
||||
method public deprecated void requestLocationUpdates(long, float, android.location.Criteria, android.app.PendingIntent);
|
||||
method public void requestLocationUpdates(android.location.LocationRequest, android.location.LocationListener, android.os.Looper);
|
||||
method public void requestLocationUpdates(android.location.LocationRequest, android.app.PendingIntent);
|
||||
method public deprecated void requestSingleUpdate(java.lang.String, android.location.LocationListener, android.os.Looper);
|
||||
method public deprecated void requestSingleUpdate(android.location.Criteria, android.location.LocationListener, android.os.Looper);
|
||||
method public deprecated void requestSingleUpdate(java.lang.String, android.app.PendingIntent);
|
||||
method public deprecated void requestSingleUpdate(android.location.Criteria, android.app.PendingIntent);
|
||||
method public deprecated boolean sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle);
|
||||
method public deprecated void setTestProviderEnabled(java.lang.String, boolean);
|
||||
method public deprecated void setTestProviderLocation(java.lang.String, android.location.Location);
|
||||
method public deprecated void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
|
||||
field public static final deprecated java.lang.String GPS_PROVIDER = "gps";
|
||||
field public static final java.lang.String KEY_LOCATION_CHANGED = "location";
|
||||
field public static final java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
|
||||
field public static final deprecated java.lang.String KEY_PROVIDER_ENABLED = "providerEnabled";
|
||||
field public static final java.lang.String KEY_PROXIMITY_ENTERING = "entering";
|
||||
field public static final java.lang.String KEY_STATUS_CHANGED = "status";
|
||||
field public static final java.lang.String NETWORK_PROVIDER = "network";
|
||||
field public static final java.lang.String PASSIVE_PROVIDER = "passive";
|
||||
field public static final java.lang.String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
|
||||
field public static final deprecated java.lang.String KEY_STATUS_CHANGED = "status";
|
||||
field public static final deprecated java.lang.String NETWORK_PROVIDER = "network";
|
||||
field public static final deprecated java.lang.String PASSIVE_PROVIDER = "passive";
|
||||
field public static final deprecated java.lang.String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED";
|
||||
}
|
||||
|
||||
public abstract class LocationProvider {
|
||||
method public abstract int getAccuracy();
|
||||
public deprecated class LocationProvider {
|
||||
method public int getAccuracy();
|
||||
method public java.lang.String getName();
|
||||
method public abstract int getPowerRequirement();
|
||||
method public abstract boolean hasMonetaryCost();
|
||||
method public int getPowerRequirement();
|
||||
method public boolean hasMonetaryCost();
|
||||
method public boolean meetsCriteria(android.location.Criteria);
|
||||
method public abstract boolean requiresCell();
|
||||
method public abstract boolean requiresNetwork();
|
||||
method public abstract boolean requiresSatellite();
|
||||
method public abstract boolean supportsAltitude();
|
||||
method public abstract boolean supportsBearing();
|
||||
method public abstract boolean supportsSpeed();
|
||||
method public boolean requiresCell();
|
||||
method public boolean requiresNetwork();
|
||||
method public boolean requiresSatellite();
|
||||
method public boolean supportsAltitude();
|
||||
method public boolean supportsBearing();
|
||||
method public boolean supportsSpeed();
|
||||
field public static final int AVAILABLE = 2; // 0x2
|
||||
field public static final int OUT_OF_SERVICE = 0; // 0x0
|
||||
field public static final int TEMPORARILY_UNAVAILABLE = 1; // 0x1
|
||||
}
|
||||
|
||||
public final class LocationRequest implements android.os.Parcelable {
|
||||
method public static android.location.LocationRequest create();
|
||||
method public int describeContents();
|
||||
method public long getExpireAt();
|
||||
method public long getFastestInterval();
|
||||
method public long getInterval();
|
||||
method public int getNumUpdates();
|
||||
method public int getQuality();
|
||||
method public android.location.LocationRequest setExpireAt(long);
|
||||
method public android.location.LocationRequest setExpireIn(long);
|
||||
method public android.location.LocationRequest setFastestInterval(long);
|
||||
method public android.location.LocationRequest setInterval(long);
|
||||
method public android.location.LocationRequest setNumUpdates(int);
|
||||
method public android.location.LocationRequest setQuality(int);
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final int ACCURACY_BLOCK = 102; // 0x66
|
||||
field public static final int ACCURACY_CITY = 104; // 0x68
|
||||
field public static final int ACCURACY_FINE = 100; // 0x64
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int POWER_HIGH = 203; // 0xcb
|
||||
field public static final int POWER_LOW = 201; // 0xc9
|
||||
field public static final int POWER_NONE = 200; // 0xc8
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
package android.media {
|
||||
|
||||
@@ -592,11 +592,30 @@
|
||||
<!-- True if WallpaperService is enabled -->
|
||||
<bool name="config_enableWallpaperService">true</bool>
|
||||
|
||||
<!-- Package name providing network location support. -->
|
||||
<string name="config_networkLocationProviderPackageName" translatable="false">@null</string>
|
||||
<!-- Package name(s) containing location provider support.
|
||||
These packages can contain services implementing location providers,
|
||||
such as the Geocode Provider, Network Location Provider, and
|
||||
Fused Location Provider. They will each be searched for
|
||||
service components implementing these providers.
|
||||
It is strongly recommended that the packages explicitly named
|
||||
below are on the system image, so that they will not map to
|
||||
a 3rd party application.
|
||||
The location framework also has support for installation
|
||||
of new location providers at run-time. The new package does not
|
||||
have to be explicitly listed here, however it must have a signature
|
||||
that matches the signature of at least one package on this list.
|
||||
Platforms should overlay additional packages in
|
||||
config_overlay_locationProviderPackageNames, instead of overlaying
|
||||
this config, if they only want to append packages and not replace
|
||||
the entire array.
|
||||
-->
|
||||
<string-array name="config_locationProviderPackageNames" translatable="false">
|
||||
<item>com.android.location.fused</item>
|
||||
</string-array>
|
||||
|
||||
<!-- Package name providing geocoder API support. -->
|
||||
<string name="config_geocodeProviderPackageName" translatable="false">@null</string>
|
||||
<!-- Pacakge name(s) supplied by overlay, and appended to
|
||||
config_locationProviderPackageNames. -->
|
||||
<string-array name="config_overlay_locationProviderPackageNames" translatable="false" />
|
||||
|
||||
<!-- Boolean indicating if current platform supports bluetooth SCO for off call
|
||||
use cases -->
|
||||
|
||||
@@ -1337,6 +1337,8 @@
|
||||
<java-symbol type="array" name="config_serialPorts" />
|
||||
<java-symbol type="array" name="radioAttributes" />
|
||||
<java-symbol type="array" name="config_oemUsbModeOverride" />
|
||||
<java-symbol type="array" name="config_locationProviderPackageNames" />
|
||||
<java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
|
||||
<java-symbol type="bool" name="config_animateScreenLights" />
|
||||
<java-symbol type="bool" name="config_automatic_brightness_available" />
|
||||
<java-symbol type="bool" name="config_sf_limitedAlpha" />
|
||||
@@ -1415,8 +1417,6 @@
|
||||
<java-symbol type="string" name="car_mode_disable_notification_title" />
|
||||
<java-symbol type="string" name="chooser_wallpaper" />
|
||||
<java-symbol type="string" name="config_datause_iface" />
|
||||
<java-symbol type="string" name="config_geocodeProviderPackageName" />
|
||||
<java-symbol type="string" name="config_networkLocationProviderPackageName" />
|
||||
<java-symbol type="string" name="config_wimaxManagerClassname" />
|
||||
<java-symbol type="string" name="config_wimaxNativeLibLocation" />
|
||||
<java-symbol type="string" name="config_wimaxServiceClassname" />
|
||||
|
||||
@@ -24,7 +24,9 @@ import android.os.Parcelable;
|
||||
* location provider. Providers maybe ordered according to accuracy,
|
||||
* power usage, ability to report altitude, speed,
|
||||
* and bearing, and monetary cost.
|
||||
* @deprecated {@link LocationRequest} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public class Criteria implements Parcelable {
|
||||
/**
|
||||
* A constant indicating that the application does not choose to
|
||||
@@ -326,6 +328,7 @@ public class Criteria implements Parcelable {
|
||||
|
||||
public static final Parcelable.Creator<Criteria> CREATOR =
|
||||
new Parcelable.Creator<Criteria>() {
|
||||
@Override
|
||||
public Criteria createFromParcel(Parcel in) {
|
||||
Criteria c = new Criteria();
|
||||
c.mHorizontalAccuracy = in.readInt();
|
||||
@@ -340,15 +343,18 @@ public class Criteria implements Parcelable {
|
||||
return c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Criteria[] newArray(int size) {
|
||||
return new Criteria[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeInt(mHorizontalAccuracy);
|
||||
parcel.writeInt(mVerticalAccuracy);
|
||||
@@ -360,4 +366,43 @@ public class Criteria implements Parcelable {
|
||||
parcel.writeInt(mSpeedRequired ? 1 : 0);
|
||||
parcel.writeInt(mCostAllowed ? 1 : 0);
|
||||
}
|
||||
|
||||
private static String powerToString(int power) {
|
||||
switch (power) {
|
||||
case NO_REQUIREMENT:
|
||||
return "NO_REQ";
|
||||
case POWER_LOW:
|
||||
return "LOW";
|
||||
case POWER_MEDIUM:
|
||||
return "MEDIUM";
|
||||
case POWER_HIGH:
|
||||
return "HIGH";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
private static String accuracyToString(int accuracy) {
|
||||
switch (accuracy) {
|
||||
case NO_REQUIREMENT:
|
||||
return "---";
|
||||
case ACCURACY_HIGH:
|
||||
return "HIGH";
|
||||
case ACCURACY_MEDIUM:
|
||||
return "MEDIUM";
|
||||
case ACCURACY_LOW:
|
||||
return "LOW";
|
||||
default:
|
||||
return "???";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("Criteria[power=").append(powerToString(mPowerRequirement));
|
||||
s.append(" acc=").append(accuracyToString(mHorizontalAccuracy));
|
||||
s.append(']');
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
|
||||
19
location/java/android/location/Geofence.aidl
Normal file
19
location/java/android/location/Geofence.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
parcelable Geofence;
|
||||
174
location/java/android/location/Geofence.java
Normal file
174
location/java/android/location/Geofence.java
Normal file
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Represents a Geofence
|
||||
*/
|
||||
public final class Geofence implements Parcelable {
|
||||
/** @hide */
|
||||
public static final int TYPE_HORIZONTAL_CIRCLE = 1;
|
||||
|
||||
private final int mType;
|
||||
private final double mLatitude;
|
||||
private final double mLongitude;
|
||||
private final float mRadius;
|
||||
|
||||
/**
|
||||
* Create a horizontal, circular geofence.
|
||||
* @param latitude latitude in degrees
|
||||
* @param longitude longitude in degrees
|
||||
* @param radius radius in meters
|
||||
* @return a new geofence
|
||||
* @throws IllegalArgumentException if any parameters are out of range
|
||||
*/
|
||||
public static Geofence createCircle(double latitude, double longitude, float radius) {
|
||||
return new Geofence(latitude, longitude, radius);
|
||||
}
|
||||
|
||||
private Geofence(double latitude, double longitude, float radius) {
|
||||
checkRadius(radius);
|
||||
checkLatLong(latitude, longitude);
|
||||
mType = TYPE_HORIZONTAL_CIRCLE;
|
||||
mLatitude = latitude;
|
||||
mLongitude = longitude;
|
||||
mRadius = radius;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public double getLatitude() {
|
||||
return mLatitude;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public double getLongitude() {
|
||||
return mLongitude;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public float getRadius() {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
private static void checkRadius(float radius) {
|
||||
if (radius <= 0) {
|
||||
throw new IllegalArgumentException("invalid radius: " + radius);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkLatLong(double latitude, double longitude) {
|
||||
if (latitude > 90.0 || latitude < -90.0) {
|
||||
throw new IllegalArgumentException("invalid latitude: " + latitude);
|
||||
}
|
||||
if (longitude > 180.0 || longitude < -180.0) {
|
||||
throw new IllegalArgumentException("invalid longitude: " + longitude);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkType(int type) {
|
||||
if (type != TYPE_HORIZONTAL_CIRCLE) {
|
||||
throw new IllegalArgumentException("invalid type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Geofence> CREATOR = new Parcelable.Creator<Geofence>() {
|
||||
@Override
|
||||
public Geofence createFromParcel(Parcel in) {
|
||||
int type = in.readInt();
|
||||
double latitude = in.readDouble();
|
||||
double longitude = in.readDouble();
|
||||
float radius = in.readFloat();
|
||||
checkType(type);
|
||||
return Geofence.createCircle(latitude, longitude, radius);
|
||||
}
|
||||
@Override
|
||||
public Geofence[] newArray(int size) {
|
||||
return new Geofence[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeInt(mType);
|
||||
parcel.writeDouble(mLatitude);
|
||||
parcel.writeDouble(mLongitude);
|
||||
parcel.writeFloat(mRadius);
|
||||
}
|
||||
|
||||
private static String typeToString(int type) {
|
||||
switch (type) {
|
||||
case TYPE_HORIZONTAL_CIRCLE:
|
||||
return "CIRCLE";
|
||||
default:
|
||||
checkType(type);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("Geofence[%s %.6f, %.6f %.0fm]",
|
||||
typeToString(mType), mLatitude, mLongitude, mRadius);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(mLatitude);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(mLongitude);
|
||||
result = prime * result + (int) (temp ^ (temp >>> 32));
|
||||
result = prime * result + Float.floatToIntBits(mRadius);
|
||||
result = prime * result + mType;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (!(obj instanceof Geofence))
|
||||
return false;
|
||||
Geofence other = (Geofence) obj;
|
||||
if (mRadius != other.mRadius)
|
||||
return false;
|
||||
if (mLatitude != other.mLatitude)
|
||||
return false;
|
||||
if (mLongitude != other.mLongitude)
|
||||
return false;
|
||||
if (mType != other.mType)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -20,53 +20,36 @@ import android.app.PendingIntent;
|
||||
import android.location.Address;
|
||||
import android.location.Criteria;
|
||||
import android.location.GeocoderParams;
|
||||
import android.location.Geofence;
|
||||
import android.location.IGeocodeProvider;
|
||||
import android.location.IGpsStatusListener;
|
||||
import android.location.ILocationListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationRequest;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
|
||||
/**
|
||||
* System private API for talking with the location service.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
interface ILocationManager
|
||||
{
|
||||
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(in LocationRequest request, in ILocationListener listener,
|
||||
in PendingIntent intent, String packageName);
|
||||
void removeUpdates(in ILocationListener listener, in PendingIntent intent, String packageName);
|
||||
|
||||
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);
|
||||
void requestGeofence(in LocationRequest request, in Geofence geofence,
|
||||
in PendingIntent intent, String packageName);
|
||||
void removeGeofence(in Geofence fence, in PendingIntent intent, String packageName);
|
||||
|
||||
Location getLastLocation(in LocationRequest request);
|
||||
|
||||
boolean addGpsStatusListener(IGpsStatusListener listener);
|
||||
void removeGpsStatusListener(IGpsStatusListener listener);
|
||||
|
||||
// for reporting callback completion
|
||||
void locationCallbackFinished(ILocationListener listener);
|
||||
|
||||
boolean sendExtraCommand(String provider, String command, inout Bundle extras);
|
||||
|
||||
void addProximityAlert(double latitude, double longitude, float distance,
|
||||
long expiration, in PendingIntent intent, in String packageName);
|
||||
void removeProximityAlert(in PendingIntent intent);
|
||||
|
||||
Bundle getProviderInfo(String provider);
|
||||
boolean isProviderEnabled(String provider);
|
||||
|
||||
Location getLastKnownLocation(String provider);
|
||||
|
||||
// Used by location providers to tell the location manager when it has a new location.
|
||||
// Passive is true if the location is coming from the passive provider, in which case
|
||||
// it need not be shared with other providers.
|
||||
void reportLocation(in Location location, boolean passive);
|
||||
|
||||
boolean geocoderIsPresent();
|
||||
String getFromLocation(double latitude, double longitude, int maxResults,
|
||||
in GeocoderParams params, out List<Address> addrs);
|
||||
@@ -75,9 +58,17 @@ interface ILocationManager
|
||||
double upperRightLatitude, double upperRightLongitude, int maxResults,
|
||||
in GeocoderParams params, out List<Address> addrs);
|
||||
|
||||
void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
|
||||
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
|
||||
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy);
|
||||
boolean sendNiResponse(int notifId, int userResponse);
|
||||
|
||||
// --- deprecated ---
|
||||
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);
|
||||
ProviderProperties getProviderProperties(String provider);
|
||||
boolean isProviderEnabled(String provider);
|
||||
|
||||
void addTestProvider(String name, in ProviderProperties properties);
|
||||
void removeTestProvider(String provider);
|
||||
void setTestProviderLocation(String provider, in Location loc);
|
||||
void clearTestProviderLocation(String provider);
|
||||
@@ -86,6 +77,17 @@ interface ILocationManager
|
||||
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime);
|
||||
void clearTestProviderStatus(String provider);
|
||||
|
||||
// for NI support
|
||||
boolean sendNiResponse(int notifId, int userResponse);
|
||||
boolean sendExtraCommand(String provider, String command, inout Bundle extras);
|
||||
|
||||
// --- internal ---
|
||||
|
||||
// Used by location providers to tell the location manager when it has a new location.
|
||||
// Passive is true if the location is coming from the passive provider, in which case
|
||||
// it need not be shared with other providers.
|
||||
void reportLocation(in Location location, boolean passive);
|
||||
|
||||
// for reporting callback completion
|
||||
void locationCallbackFinished(ILocationListener listener);
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Printer;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.StringTokenizer;
|
||||
@@ -84,17 +85,6 @@ public class Location implements Parcelable {
|
||||
// Scratchpad
|
||||
private float[] mResults = new float[2];
|
||||
|
||||
public void dump(Printer pw, String prefix) {
|
||||
pw.println(prefix + "mProvider=" + mProvider + " mTime=" + mTime);
|
||||
pw.println(prefix + "mElapsedRealtimeNano=" + mElapsedRealtimeNano);
|
||||
pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
|
||||
pw.println(prefix + "mHasAltitude=" + mHasAltitude + " mAltitude=" + mAltitude);
|
||||
pw.println(prefix + "mHasSpeed=" + mHasSpeed + " mSpeed=" + mSpeed);
|
||||
pw.println(prefix + "mHasBearing=" + mHasBearing + " mBearing=" + mBearing);
|
||||
pw.println(prefix + "mHasAccuracy=" + mHasAccuracy + " mAccuracy=" + mAccuracy);
|
||||
pw.println(prefix + "mExtras=" + mExtras);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new Location. By default, time, latitude,
|
||||
* longitude, and numSatellites are 0; hasAltitude, hasSpeed, and
|
||||
@@ -766,25 +756,46 @@ public class Location implements Parcelable {
|
||||
mExtras = (extras == null) ? null : new Bundle(extras);
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "Location[mProvider=" + mProvider +
|
||||
",mTime=" + mTime +
|
||||
",mElapsedRealtimeNano=" + mElapsedRealtimeNano +
|
||||
",mLatitude=" + mLatitude +
|
||||
",mLongitude=" + mLongitude +
|
||||
",mHasAltitude=" + mHasAltitude +
|
||||
",mAltitude=" + mAltitude +
|
||||
",mHasSpeed=" + mHasSpeed +
|
||||
",mSpeed=" + mSpeed +
|
||||
",mHasBearing=" + mHasBearing +
|
||||
",mBearing=" + mBearing +
|
||||
",mHasAccuracy=" + mHasAccuracy +
|
||||
",mAccuracy=" + mAccuracy +
|
||||
",mExtras=" + mExtras + "]";
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("Location[");
|
||||
s.append(mProvider);
|
||||
s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
|
||||
if (mHasAccuracy) s.append(String.format(" acc=%.0f", mAccuracy));
|
||||
else s.append(" acc=???");
|
||||
if (mTime == 0) {
|
||||
s.append(" t=?!?");
|
||||
}
|
||||
if (mElapsedRealtimeNano == 0) {
|
||||
s.append(" et=?!?");
|
||||
} else {
|
||||
long age = SystemClock.elapsedRealtimeNano() - mElapsedRealtimeNano;
|
||||
s.append(" age=");
|
||||
TimeUtils.formatDuration(age / 1000000L, s);
|
||||
}
|
||||
if (mHasAltitude) s.append(" alt=").append(mAltitude);
|
||||
if (mHasSpeed) s.append(" vel=").append(mSpeed);
|
||||
if (mHasBearing) s.append(" bear=").append(mBearing);
|
||||
|
||||
if (mExtras != null) {
|
||||
s.append(" {").append(mExtras).append('}');
|
||||
}
|
||||
s.append(']');
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #toString} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void dump(Printer pw, String prefix) {
|
||||
pw.println(prefix + toString());
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<Location> CREATOR =
|
||||
new Parcelable.Creator<Location>() {
|
||||
@Override
|
||||
public Location createFromParcel(Parcel in) {
|
||||
String provider = in.readString();
|
||||
Location l = new Location(provider);
|
||||
@@ -804,15 +815,18 @@ public class Location implements Parcelable {
|
||||
return l;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location[] newArray(int size) {
|
||||
return new Location[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeString(mProvider);
|
||||
parcel.writeLong(mTime);
|
||||
@@ -828,5 +842,5 @@ public class Location implements Parcelable {
|
||||
parcel.writeInt(mHasAccuracy ? 1 : 0);
|
||||
parcel.writeFloat(mAccuracy);
|
||||
parcel.writeBundle(mExtras);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,15 +25,15 @@ import android.os.Looper;
|
||||
import android.os.RemoteException;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.DummyLocationProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
|
||||
/**
|
||||
* This class provides access to the system location services. These
|
||||
* services allow applications to obtain periodic updates of the
|
||||
@@ -71,7 +71,9 @@ public class LocationManager {
|
||||
*
|
||||
* Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION
|
||||
* or android.permission.ACCESS_FINE_LOCATION.
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String NETWORK_PROVIDER = "network";
|
||||
|
||||
/**
|
||||
@@ -87,7 +89,9 @@ public class LocationManager {
|
||||
* <ul>
|
||||
* <li> satellites - the number of satellites used to derive the fix
|
||||
* </ul>
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String GPS_PROVIDER = "gps";
|
||||
|
||||
/**
|
||||
@@ -100,9 +104,21 @@ public class LocationManager {
|
||||
*
|
||||
* Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS
|
||||
* is not enabled this provider might only return coarse fixes.
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String PASSIVE_PROVIDER = "passive";
|
||||
|
||||
/**
|
||||
* Name of the Fused location provider.<p>
|
||||
* This provider combines inputs for all possible location sources
|
||||
* to provide the best possible Location fix.<p>
|
||||
*
|
||||
* Requires the permission android.permission.ACCESS_FINE_LOCATION.
|
||||
* @hide
|
||||
*/
|
||||
public static final String FUSED_PROVIDER = "fused";
|
||||
|
||||
/**
|
||||
* Key used for the Bundle extra holding a boolean indicating whether
|
||||
* a proximity alert is entering (true) or exiting (false)..
|
||||
@@ -112,13 +128,17 @@ public class LocationManager {
|
||||
/**
|
||||
* Key used for a Bundle extra holding an Integer status value
|
||||
* when a status change is broadcast using a PendingIntent.
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String KEY_STATUS_CHANGED = "status";
|
||||
|
||||
/**
|
||||
* Key used for a Bundle extra holding an Boolean status value
|
||||
* when a provider enabled/disabled event is broadcast using a PendingIntent.
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
|
||||
|
||||
/**
|
||||
@@ -141,7 +161,9 @@ public class LocationManager {
|
||||
/**
|
||||
* Broadcast intent action when the configured location providers
|
||||
* change.
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final String PROVIDERS_CHANGED_ACTION =
|
||||
"android.location.PROVIDERS_CHANGED";
|
||||
|
||||
@@ -274,19 +296,8 @@ public class LocationManager {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
private LocationProvider createProvider(String name, Bundle info) {
|
||||
DummyLocationProvider provider =
|
||||
new DummyLocationProvider(name, mService);
|
||||
provider.setRequiresNetwork(info.getBoolean("network"));
|
||||
provider.setRequiresSatellite(info.getBoolean("satellite"));
|
||||
provider.setRequiresCell(info.getBoolean("cell"));
|
||||
provider.setHasMonetaryCost(info.getBoolean("cost"));
|
||||
provider.setSupportsAltitude(info.getBoolean("altitude"));
|
||||
provider.setSupportsSpeed(info.getBoolean("speed"));
|
||||
provider.setSupportsBearing(info.getBoolean("bearing"));
|
||||
provider.setPowerRequirement(info.getInt("power"));
|
||||
provider.setAccuracy(info.getInt("accuracy"));
|
||||
return provider;
|
||||
private LocationProvider createProvider(String name, ProviderProperties properties) {
|
||||
return new LocationProvider(name, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,15 +306,14 @@ public class LocationManager {
|
||||
* accessed by the calling activity or are currently disabled.
|
||||
*
|
||||
* @return list of Strings containing names of the providers
|
||||
* @deprecated use the {@link Criteria} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getAllProviders() {
|
||||
if (false) {
|
||||
Log.d(TAG, "getAllProviders");
|
||||
}
|
||||
try {
|
||||
return mService.getAllProviders();
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getAllProviders: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -315,12 +325,16 @@ public class LocationManager {
|
||||
* @param enabledOnly if true then only the providers which are currently
|
||||
* enabled are returned.
|
||||
* @return list of Strings containing names of the providers
|
||||
* @deprecated The {@link LocationProvider} class is deprecated. So
|
||||
* use the {@link Criteria} class to request location instead of
|
||||
* enumerating providers.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getProviders(boolean enabledOnly) {
|
||||
try {
|
||||
return mService.getProviders(null, enabledOnly);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getProviders: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -332,22 +346,24 @@ public class LocationManager {
|
||||
* @param name the provider name
|
||||
* @return a LocationProvider, or null
|
||||
*
|
||||
* @throws IllegalArgumentException if name is null
|
||||
* @throws IllegalArgumentException if name is null or does not exisit
|
||||
* @throws SecurityException if the caller is not permitted to access the
|
||||
* given provider.
|
||||
* @deprecated The {@link LocationProvider} class is deprecated. So
|
||||
* use the {@link Criteria} class to request location instead of
|
||||
* enumerating providers.
|
||||
*/
|
||||
@Deprecated
|
||||
public LocationProvider getProvider(String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("name==null");
|
||||
}
|
||||
checkProvider(name);
|
||||
try {
|
||||
Bundle info = mService.getProviderInfo(name);
|
||||
if (info == null) {
|
||||
ProviderProperties properties = mService.getProviderProperties(name);
|
||||
if (properties == null) {
|
||||
return null;
|
||||
}
|
||||
return createProvider(name, info);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getProvider: RemoteException", ex);
|
||||
return createProvider(name, properties);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -361,15 +377,17 @@ public class LocationManager {
|
||||
* @param enabledOnly if true then only the providers which are currently
|
||||
* enabled are returned.
|
||||
* @return list of Strings containing names of the providers
|
||||
* @deprecated The {@link LocationProvider} class is deprecated. So
|
||||
* use the {@link Criteria} class to request location instead of
|
||||
* enumerating providers.
|
||||
*/
|
||||
@Deprecated
|
||||
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
|
||||
if (criteria == null) {
|
||||
throw new IllegalArgumentException("criteria==null");
|
||||
}
|
||||
checkCriteria(criteria);
|
||||
try {
|
||||
return mService.getProviders(criteria, enabledOnly);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getProviders: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -395,15 +413,15 @@ public class LocationManager {
|
||||
* @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
|
||||
* @deprecated using an explicit provider doesn't allow fused location
|
||||
*/
|
||||
@Deprecated
|
||||
public String getBestProvider(Criteria criteria, boolean enabledOnly) {
|
||||
if (criteria == null) {
|
||||
throw new IllegalArgumentException("criteria==null");
|
||||
}
|
||||
checkCriteria(criteria);
|
||||
try {
|
||||
return mService.getBestProvider(criteria, enabledOnly);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getBestProvider: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -480,16 +498,17 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if listener is null
|
||||
* @throws RuntimeException if the calling thread has no Looper
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
public void requestLocationUpdates(String provider,
|
||||
long minTime, float minDistance, LocationListener listener) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("provider==null");
|
||||
}
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener==null");
|
||||
}
|
||||
_requestLocationUpdates(provider, null, minTime, minDistance, false, listener, null);
|
||||
@Deprecated
|
||||
public void requestLocationUpdates(String provider, long minTime, float minDistance,
|
||||
LocationListener listener) {
|
||||
checkProvider(provider);
|
||||
checkListener(listener);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, minTime, minDistance, false);
|
||||
requestLocationUpdates(request, listener, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,17 +583,17 @@ public class LocationManager {
|
||||
* @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.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
public void requestLocationUpdates(String provider,
|
||||
long minTime, float minDistance, LocationListener listener,
|
||||
Looper looper) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("provider==null");
|
||||
}
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener==null");
|
||||
}
|
||||
_requestLocationUpdates(provider, null, minTime, minDistance, false, listener, looper);
|
||||
@Deprecated
|
||||
public void requestLocationUpdates(String provider, long minTime, float minDistance,
|
||||
LocationListener listener, Looper looper) {
|
||||
checkProvider(provider);
|
||||
checkListener(listener);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, minTime, minDistance, false);
|
||||
requestLocationUpdates(request, listener, looper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -639,39 +658,17 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if criteria is null
|
||||
* @throws IllegalArgumentException if listener is null
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
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(null, criteria, minTime, minDistance, false, listener, looper);
|
||||
}
|
||||
@Deprecated
|
||||
public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
|
||||
LocationListener listener, Looper looper) {
|
||||
checkCriteria(criteria);
|
||||
checkListener(listener);
|
||||
|
||||
private void _requestLocationUpdates(String provider, Criteria criteria, long minTime,
|
||||
float minDistance, boolean singleShot, LocationListener listener, Looper looper) {
|
||||
if (minTime < 0L) {
|
||||
minTime = 0L;
|
||||
}
|
||||
if (minDistance < 0.0f) {
|
||||
minDistance = 0.0f;
|
||||
}
|
||||
|
||||
try {
|
||||
synchronized (mListeners) {
|
||||
ListenerTransport transport = mListeners.get(listener);
|
||||
if (transport == null) {
|
||||
transport = new ListenerTransport(listener, looper);
|
||||
}
|
||||
mListeners.put(listener, transport);
|
||||
mService.requestLocationUpdates(provider, criteria, minTime, minDistance, singleShot, transport);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
|
||||
}
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
|
||||
criteria, minTime, minDistance, false);
|
||||
requestLocationUpdates(request, listener, looper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -749,16 +746,17 @@ public class LocationManager {
|
||||
* on this device
|
||||
* @throws IllegalArgumentException if intent is null
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
public void requestLocationUpdates(String provider,
|
||||
long minTime, float minDistance, PendingIntent intent) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("provider==null");
|
||||
}
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("intent==null");
|
||||
}
|
||||
_requestLocationUpdates(provider, null, minTime, minDistance, false, intent);
|
||||
@Deprecated
|
||||
public void requestLocationUpdates(String provider, long minTime, float minDistance,
|
||||
PendingIntent intent) {
|
||||
checkProvider(provider);
|
||||
checkPendingIntent(intent);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, minTime, minDistance, false);
|
||||
requestLocationUpdates(request, null, null, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -825,32 +823,17 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if criteria is null
|
||||
* @throws IllegalArgumentException if intent is null
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
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);
|
||||
}
|
||||
checkCriteria(criteria);
|
||||
checkPendingIntent(intent);
|
||||
|
||||
private void _requestLocationUpdates(String provider, Criteria criteria,
|
||||
long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
|
||||
if (minTime < 0L) {
|
||||
minTime = 0L;
|
||||
}
|
||||
if (minDistance < 0.0f) {
|
||||
minDistance = 0.0f;
|
||||
}
|
||||
|
||||
try {
|
||||
mService.requestLocationUpdatesPI(provider, criteria, minTime, minDistance, singleShot, intent);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
|
||||
}
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
|
||||
criteria, minTime, minDistance, false);
|
||||
requestLocationUpdates(request, null, null, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -879,15 +862,16 @@ public class LocationManager {
|
||||
* @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
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
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);
|
||||
checkProvider(provider);
|
||||
checkListener(listener);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, 0, 0, true);
|
||||
requestLocationUpdates(request, listener, looper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -918,15 +902,16 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if listener is null
|
||||
* @throws SecurityException if no suitable permission is present to access
|
||||
* the location services
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
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);
|
||||
checkCriteria(criteria);
|
||||
checkListener(listener);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
|
||||
criteria, 0, 0, true);
|
||||
requestLocationUpdates(request, listener, looper, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -951,15 +936,16 @@ public class LocationManager {
|
||||
* @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
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
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);
|
||||
checkProvider(provider);
|
||||
checkPendingIntent(intent);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, 0, 0, true);
|
||||
requestLocationUpdates(request, null, null, intent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -986,15 +972,54 @@ public class LocationManager {
|
||||
* @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
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
|
||||
if (criteria == null) {
|
||||
throw new IllegalArgumentException("criteria==null");
|
||||
checkCriteria(criteria);
|
||||
checkPendingIntent(intent);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
|
||||
criteria, 0, 0, true);
|
||||
requestLocationUpdates(request, null, null, intent);
|
||||
}
|
||||
|
||||
public void requestLocationUpdates(LocationRequest request, LocationListener listener,
|
||||
Looper looper) {
|
||||
checkListener(listener);
|
||||
requestLocationUpdates(request, listener, looper, null);
|
||||
}
|
||||
|
||||
public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
|
||||
checkPendingIntent(intent);
|
||||
requestLocationUpdates(request, null, null, intent);
|
||||
}
|
||||
|
||||
private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
|
||||
if (listener == null) return null;
|
||||
synchronized (mListeners) {
|
||||
ListenerTransport transport = mListeners.get(listener);
|
||||
if (transport == null) {
|
||||
transport = new ListenerTransport(listener, looper);
|
||||
}
|
||||
mListeners.put(listener, transport);
|
||||
return transport;
|
||||
}
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("intent==null");
|
||||
}
|
||||
_requestLocationUpdates(null, criteria, 0L, 0.0f, true, intent);
|
||||
}
|
||||
|
||||
private void requestLocationUpdates(LocationRequest request, LocationListener listener,
|
||||
Looper looper, PendingIntent intent) {
|
||||
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
// wrap the listener class
|
||||
ListenerTransport transport = wrapListener(listener, looper);
|
||||
|
||||
try {
|
||||
mService.requestLocationUpdates(request, transport, intent, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1006,19 +1031,19 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if listener is null
|
||||
*/
|
||||
public void removeUpdates(LocationListener listener) {
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("listener==null");
|
||||
}
|
||||
if (false) {
|
||||
Log.d(TAG, "removeUpdates: listener = " + listener);
|
||||
checkListener(listener);
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
ListenerTransport transport;
|
||||
synchronized (mListeners) {
|
||||
transport = mListeners.remove(listener);
|
||||
}
|
||||
if (transport == null) return;
|
||||
|
||||
try {
|
||||
ListenerTransport transport = mListeners.remove(listener);
|
||||
if (transport != null) {
|
||||
mService.removeUpdates(transport);
|
||||
}
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "removeUpdates: DeadObjectException", ex);
|
||||
mService.removeUpdates(transport, null, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,16 +1056,13 @@ public class LocationManager {
|
||||
* @throws IllegalArgumentException if intent is null
|
||||
*/
|
||||
public void removeUpdates(PendingIntent intent) {
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("intent==null");
|
||||
}
|
||||
if (false) {
|
||||
Log.d(TAG, "removeUpdates: intent = " + intent);
|
||||
}
|
||||
checkPendingIntent(intent);
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
mService.removeUpdatesPI(intent);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "removeUpdates: RemoteException", ex);
|
||||
mService.removeUpdates(null, intent, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1086,20 +1108,31 @@ public class LocationManager {
|
||||
*
|
||||
* @throws SecurityException if no permission exists for the required
|
||||
* providers.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
public void addProximityAlert(double latitude, double longitude,
|
||||
float radius, long expiration, PendingIntent intent) {
|
||||
if (false) {
|
||||
Log.d(TAG, "addProximityAlert: latitude = " + latitude +
|
||||
", longitude = " + longitude + ", radius = " + radius +
|
||||
", expiration = " + expiration +
|
||||
", intent = " + intent);
|
||||
}
|
||||
@Deprecated
|
||||
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
|
||||
PendingIntent intent) {
|
||||
checkPendingIntent(intent);
|
||||
if (expiration < 0) expiration = Long.MAX_VALUE;
|
||||
|
||||
Geofence fence = Geofence.createCircle(latitude, longitude, radius);
|
||||
LocationRequest request = new LocationRequest().setExpireIn(expiration);
|
||||
try {
|
||||
mService.addProximityAlert(latitude, longitude, radius, expiration, intent,
|
||||
mContext.getPackageName());
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "addProximityAlert: RemoteException", ex);
|
||||
mService.requestGeofence(request, fence, intent, mContext.getPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void requestGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
|
||||
checkPendingIntent(intent);
|
||||
checkGeofence(fence);
|
||||
|
||||
try {
|
||||
mService.requestGeofence(request, fence, intent, mContext.getPackageName());
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1108,15 +1141,40 @@ public class LocationManager {
|
||||
*
|
||||
* @param intent the PendingIntent that no longer needs to be notified of
|
||||
* proximity alerts
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void removeProximityAlert(PendingIntent intent) {
|
||||
if (false) {
|
||||
Log.d(TAG, "removeProximityAlert: intent = " + intent);
|
||||
}
|
||||
checkPendingIntent(intent);
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
mService.removeProximityAlert(intent);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "removeProximityAlert: RemoteException", ex);
|
||||
mService.removeGeofence(null, intent, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeGeofence(Geofence fence, PendingIntent intent) {
|
||||
checkPendingIntent(intent);
|
||||
checkGeofence(fence);
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
mService.removeGeofence(fence, intent, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllGeofences(PendingIntent intent) {
|
||||
checkPendingIntent(intent);
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
try {
|
||||
mService.removeGeofence(null, intent, packageName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1130,19 +1188,30 @@ public class LocationManager {
|
||||
*
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @throws IllegalArgumentException if provider is null
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isProviderEnabled(String provider) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("provider==null");
|
||||
}
|
||||
checkProvider(provider);
|
||||
|
||||
try {
|
||||
return mService.isProviderEnabled(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "isProviderEnabled: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Location getLastLocation(LocationRequest request) {
|
||||
try {
|
||||
return mService.getLastLocation(request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Location indicating the data from the last known
|
||||
* location fix obtained from the given provider. This can be done
|
||||
@@ -1157,15 +1226,49 @@ public class LocationManager {
|
||||
*
|
||||
* @throws SecurityException if no suitable permission is present for the provider.
|
||||
* @throws IllegalArgumentException if provider is null or doesn't exist
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Location getLastKnownLocation(String provider) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("provider==null");
|
||||
}
|
||||
checkProvider(provider);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedProvider(
|
||||
provider, 0, 0, true);
|
||||
|
||||
try {
|
||||
return mService.getLastKnownLocation(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
|
||||
return mService.getLastLocation(request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last know Location that satisfies the given
|
||||
* criteria. This can be done without starting the provider.
|
||||
* Note that this location could
|
||||
* be out-of-date, for example if the device was turned off and
|
||||
* moved to another location.
|
||||
*
|
||||
* <p> If no location is found that satisfies the criteria, null is returned
|
||||
*
|
||||
* @param criteria location criteria
|
||||
* @return the last known location that satisfies criteria, or null
|
||||
*
|
||||
* @throws SecurityException if no suitable permission is present
|
||||
* @throws IllegalArgumentException if criteria is null
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public Location getLastKnownLocation(Criteria criteria) {
|
||||
checkCriteria(criteria);
|
||||
|
||||
LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
|
||||
criteria, 0, 0, true);
|
||||
try {
|
||||
return mService.getLastLocation(request);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1190,16 +1293,23 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled
|
||||
* @throws IllegalArgumentException if a provider with the given name already exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
|
||||
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
|
||||
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
|
||||
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
|
||||
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
|
||||
ProviderProperties properties = new ProviderProperties(requiresNetwork,
|
||||
requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
|
||||
supportsBearing, powerRequirement, accuracy);
|
||||
if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
|
||||
throw new IllegalArgumentException("provider name contains illegal character: " + name);
|
||||
}
|
||||
|
||||
try {
|
||||
mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell,
|
||||
hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement,
|
||||
accuracy);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "addTestProvider: RemoteException", ex);
|
||||
mService.addTestProvider(name, properties);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1212,12 +1322,14 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void removeTestProvider(String provider) {
|
||||
try {
|
||||
mService.removeTestProvider(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "removeTestProvider: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1236,23 +1348,27 @@ public class LocationManager {
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @throws IllegalArgumentException if the location is incomplete
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTestProviderLocation(String provider, Location loc) {
|
||||
if (!loc.isComplete()) {
|
||||
IllegalArgumentException e = new IllegalArgumentException(
|
||||
"Incomplete location object, missing timestamp or accuracy? " + loc);
|
||||
if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
// for backwards compatibility, allow mock locations that are incomplete
|
||||
Log.w(TAG, "Incomplete Location object", new Throwable());
|
||||
// just log on old platform (for backwards compatibility)
|
||||
Log.w(TAG, e);
|
||||
loc.makeComplete();
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Location object not complete. Missing timestamps or accuracy?");
|
||||
// really throw it!
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
mService.setTestProviderLocation(provider, loc);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "setTestProviderLocation: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1265,12 +1381,14 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearTestProviderLocation(String provider) {
|
||||
try {
|
||||
mService.clearTestProviderLocation(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "clearTestProviderLocation: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1285,12 +1403,14 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTestProviderEnabled(String provider, boolean enabled) {
|
||||
try {
|
||||
mService.setTestProviderEnabled(provider, enabled);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "setTestProviderEnabled: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,14 +1423,15 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearTestProviderEnabled(String provider) {
|
||||
try {
|
||||
mService.clearTestProviderEnabled(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1326,12 +1447,14 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
|
||||
try {
|
||||
mService.setTestProviderStatus(provider, status, extras, updateTime);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "setTestProviderStatus: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1344,12 +1467,14 @@ public class LocationManager {
|
||||
* or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
|
||||
* Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
|
||||
* @throws IllegalArgumentException if no provider with the given name exists
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void clearTestProviderStatus(String provider) {
|
||||
try {
|
||||
mService.clearTestProviderStatus(provider);
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "clearTestProviderStatus: RemoteException", ex);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1587,7 +1712,9 @@ public class LocationManager {
|
||||
* The provider may optionally fill the extras Bundle with results from the command.
|
||||
*
|
||||
* @return true if the command succeeds.
|
||||
* @deprecated use the {@link LocationRequest} class instead
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean sendExtraCommand(String provider, String command, Bundle extras) {
|
||||
try {
|
||||
return mService.sendExtraCommand(provider, command, extras);
|
||||
@@ -1612,4 +1739,41 @@ public class LocationManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkProvider(String provider) {
|
||||
if (provider == null) {
|
||||
throw new IllegalArgumentException("invalid provider: " + provider);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkCriteria(Criteria criteria) {
|
||||
if (criteria == null) {
|
||||
throw new IllegalArgumentException("invalid criteria: " + criteria);
|
||||
}
|
||||
}
|
||||
private static void checkListener(LocationListener listener) {
|
||||
if (listener == null) {
|
||||
throw new IllegalArgumentException("invalid listener: " + listener);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPendingIntent(PendingIntent intent) {
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("invalid pending intent: " + intent);
|
||||
}
|
||||
if (!intent.isTargetedToPackage()) {
|
||||
IllegalArgumentException e = new IllegalArgumentException(
|
||||
"pending intent msut be targeted to package");
|
||||
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
|
||||
throw e;
|
||||
} else {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkGeofence(Geofence fence) {
|
||||
if (fence == null) {
|
||||
throw new IllegalArgumentException("invalid geofence: " + fence);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
package android.location;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
|
||||
/**
|
||||
* An abstract superclass for location providers. A location provider
|
||||
@@ -32,35 +32,40 @@ import android.util.Log;
|
||||
* characteristics or monetary costs to the user. The {@link
|
||||
* Criteria} class allows providers to be selected based on
|
||||
* user-specified criteria.
|
||||
*
|
||||
* @deprecated Use the {@link Criteria} class to request location instead of
|
||||
* enumerating providers.
|
||||
*/
|
||||
public abstract class LocationProvider {
|
||||
private static final String TAG = "LocationProvider";
|
||||
// A regular expression matching characters that may not appear
|
||||
// in the name of a LocationProvider.
|
||||
static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]";
|
||||
|
||||
private final String mName;
|
||||
private final ILocationManager mService;
|
||||
|
||||
@Deprecated
|
||||
public class LocationProvider {
|
||||
public static final int OUT_OF_SERVICE = 0;
|
||||
public static final int TEMPORARILY_UNAVAILABLE = 1;
|
||||
public static final int AVAILABLE = 2;
|
||||
|
||||
/**
|
||||
* A regular expression matching characters that may not appear
|
||||
* in the name of a LocationProvider
|
||||
* @hide
|
||||
*/
|
||||
public static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]";
|
||||
|
||||
private final String mName;
|
||||
private final ProviderProperties mProperties;
|
||||
|
||||
/**
|
||||
* Constructs a LocationProvider with the given name. Provider names must
|
||||
* consist only of the characters [a-zA-Z0-9].
|
||||
*
|
||||
* @throws IllegalArgumentException if name contains an illegal character
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
public LocationProvider(String name, ILocationManager service) {
|
||||
public LocationProvider(String name, ProviderProperties properties) {
|
||||
if (name.matches(BAD_CHARS_REGEX)) {
|
||||
throw new IllegalArgumentException("name " + name +
|
||||
" contains an illegal character");
|
||||
throw new IllegalArgumentException("provider name contains illegal character: " + name);
|
||||
}
|
||||
mName = name;
|
||||
mService = service;
|
||||
mProperties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -75,40 +80,81 @@ public abstract class LocationProvider {
|
||||
* false otherwise.
|
||||
*/
|
||||
public boolean meetsCriteria(Criteria criteria) {
|
||||
try {
|
||||
return mService.providerMeetsCriteria(mName, criteria);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "meetsCriteria: RemoteException", e);
|
||||
return propertiesMeetCriteria(mName, mProperties, criteria);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static boolean propertiesMeetCriteria(String name, ProviderProperties properties,
|
||||
Criteria criteria) {
|
||||
if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
|
||||
// passive provider never matches
|
||||
return false;
|
||||
}
|
||||
if (properties == null) {
|
||||
// unfortunately this can happen for provider in remote services
|
||||
// that have not finished binding yet
|
||||
return false;
|
||||
}
|
||||
|
||||
if (criteria.getAccuracy() != Criteria.NO_REQUIREMENT &&
|
||||
criteria.getAccuracy() < properties.mAccuracy) {
|
||||
return false;
|
||||
}
|
||||
if (criteria.getPowerRequirement() != Criteria.NO_REQUIREMENT &&
|
||||
criteria.getPowerRequirement() < properties.mPowerRequirement) {
|
||||
return false;
|
||||
}
|
||||
if (criteria.isAltitudeRequired() && !properties.mSupportsAltitude) {
|
||||
return false;
|
||||
}
|
||||
if (criteria.isSpeedRequired() && !properties.mSupportsSpeed) {
|
||||
return false;
|
||||
}
|
||||
if (criteria.isBearingRequired() && !properties.mSupportsBearing) {
|
||||
return false;
|
||||
}
|
||||
if (!criteria.isCostAllowed() && properties.mHasMonetaryCost) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
public abstract boolean requiresNetwork();
|
||||
public boolean requiresNetwork() {
|
||||
return mProperties.mRequiresNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
public abstract boolean requiresSatellite();
|
||||
public boolean requiresSatellite() {
|
||||
return mProperties.mRequiresSatellite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
public abstract boolean requiresCell();
|
||||
public boolean requiresCell() {
|
||||
return mProperties.mRequiresCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information.
|
||||
*/
|
||||
public abstract boolean hasMonetaryCost();
|
||||
public boolean hasMonetaryCost() {
|
||||
return mProperties.mHasMonetaryCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide altitude
|
||||
@@ -116,7 +162,9 @@ public abstract class LocationProvider {
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean supportsAltitude();
|
||||
public boolean supportsAltitude() {
|
||||
return mProperties.mSupportsAltitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide speed
|
||||
@@ -124,7 +172,9 @@ public abstract class LocationProvider {
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean supportsSpeed();
|
||||
public boolean supportsSpeed() {
|
||||
return mProperties.mSupportsSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide bearing
|
||||
@@ -132,7 +182,9 @@ public abstract class LocationProvider {
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean supportsBearing();
|
||||
public boolean supportsBearing() {
|
||||
return mProperties.mSupportsBearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the power requirement for this provider.
|
||||
@@ -140,7 +192,9 @@ public abstract class LocationProvider {
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_REQUIREMENT_*.
|
||||
*/
|
||||
public abstract int getPowerRequirement();
|
||||
public int getPowerRequirement() {
|
||||
return mProperties.mPowerRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constant describing horizontal accuracy of this provider.
|
||||
@@ -149,5 +203,7 @@ public abstract class LocationProvider {
|
||||
* location is only approximate then {@link Criteria#ACCURACY_COARSE}
|
||||
* is returned.
|
||||
*/
|
||||
public abstract int getAccuracy();
|
||||
public int getAccuracy() {
|
||||
return mProperties.mAccuracy;
|
||||
}
|
||||
}
|
||||
|
||||
19
location/java/android/location/LocationRequest.aidl
Normal file
19
location/java/android/location/LocationRequest.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
parcelable LocationRequest;
|
||||
321
location/java/android/location/LocationRequest.java
Normal file
321
location/java/android/location/LocationRequest.java
Normal file
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2007 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 com.android.internal.location;
|
||||
|
||||
import android.location.ILocationManager;
|
||||
import android.location.LocationProvider;
|
||||
|
||||
/**
|
||||
* A stub implementation of LocationProvider used by LocationManager.
|
||||
* A DummyLocationProvider may be queried to determine the properties
|
||||
* of the provider whcih it shadows, but does not actually provide location
|
||||
* data.
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public class DummyLocationProvider extends LocationProvider {
|
||||
|
||||
private static final String TAG = "DummyLocationProvider";
|
||||
|
||||
String mName;
|
||||
boolean mRequiresNetwork;
|
||||
boolean mRequiresSatellite;
|
||||
boolean mRequiresCell;
|
||||
boolean mHasMonetaryCost;
|
||||
boolean mSupportsAltitude;
|
||||
boolean mSupportsSpeed;
|
||||
boolean mSupportsBearing;
|
||||
int mPowerRequirement;
|
||||
int mAccuracy;
|
||||
|
||||
public DummyLocationProvider(String name, ILocationManager service) {
|
||||
super(name, service);
|
||||
}
|
||||
|
||||
public void setRequiresNetwork(boolean requiresNetwork) {
|
||||
mRequiresNetwork = requiresNetwork;
|
||||
}
|
||||
|
||||
public void setRequiresSatellite(boolean requiresSatellite) {
|
||||
mRequiresSatellite = requiresSatellite;
|
||||
}
|
||||
|
||||
public void setRequiresCell(boolean requiresCell) {
|
||||
mRequiresCell = requiresCell;
|
||||
}
|
||||
|
||||
public void setHasMonetaryCost(boolean hasMonetaryCost) {
|
||||
mHasMonetaryCost = hasMonetaryCost;
|
||||
}
|
||||
|
||||
public void setSupportsAltitude(boolean supportsAltitude) {
|
||||
mSupportsAltitude = supportsAltitude;
|
||||
}
|
||||
|
||||
public void setSupportsSpeed(boolean supportsSpeed) {
|
||||
mSupportsSpeed = supportsSpeed;
|
||||
}
|
||||
|
||||
public void setSupportsBearing(boolean supportsBearing) {
|
||||
mSupportsBearing = supportsBearing;
|
||||
}
|
||||
|
||||
public void setPowerRequirement(int powerRequirement) {
|
||||
mPowerRequirement = powerRequirement;
|
||||
}
|
||||
|
||||
public void setAccuracy(int accuracy) {
|
||||
mAccuracy = accuracy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresNetwork() {
|
||||
return mRequiresNetwork;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresSatellite() {
|
||||
return mRequiresSatellite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean requiresCell() {
|
||||
return mRequiresCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasMonetaryCost() {
|
||||
return mHasMonetaryCost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide altitude
|
||||
* information, false otherwise. A provider that reports altitude
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsAltitude() {
|
||||
return mSupportsAltitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide speed
|
||||
* information, false otherwise. A provider that reports speed
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsSpeed() {
|
||||
return mSupportsSpeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide bearing
|
||||
* information, false otherwise. A provider that reports bearing
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsBearing() {
|
||||
return mSupportsBearing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the power requirement for this provider.
|
||||
*
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_REQUIREMENT_*.
|
||||
*/
|
||||
@Override
|
||||
public int getPowerRequirement() {
|
||||
return mPowerRequirement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a constant describing the horizontal accuracy returned
|
||||
* by this provider.
|
||||
*
|
||||
* @return the horizontal accuracy for this provider, as one of the
|
||||
* constants Criteria.ACCURACY_*.
|
||||
*/
|
||||
@Override
|
||||
public int getAccuracy() {
|
||||
return mAccuracy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,40 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.location;
|
||||
package com.android.internal.location;
|
||||
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
/**
|
||||
* Binder interface for services that implement location providers.
|
||||
*
|
||||
* {@hide}
|
||||
* <p>Use {@link LocationProviderBase} as a helper to implement this
|
||||
* interface.
|
||||
* @hide
|
||||
*/
|
||||
interface ILocationProvider {
|
||||
boolean requiresNetwork();
|
||||
boolean requiresSatellite();
|
||||
boolean requiresCell();
|
||||
boolean hasMonetaryCost();
|
||||
boolean supportsAltitude();
|
||||
boolean supportsSpeed();
|
||||
boolean supportsBearing();
|
||||
int getPowerRequirement();
|
||||
boolean meetsCriteria(in Criteria criteria);
|
||||
int getAccuracy();
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void setRequest(in ProviderRequest request, in WorkSource ws);
|
||||
|
||||
// --- deprecated (but still supported) ---
|
||||
ProviderProperties getProperties();
|
||||
int getStatus(out Bundle extras);
|
||||
long getStatusUpdateTime();
|
||||
String getInternalState();
|
||||
void enableLocationTracking(boolean enable);
|
||||
void setMinTime(long minTime, in WorkSource ws);
|
||||
void updateNetworkState(int state, in NetworkInfo info);
|
||||
void updateLocation(in Location location);
|
||||
boolean sendExtraCommand(String command, inout Bundle extras);
|
||||
void addListener(int uid);
|
||||
void removeListener(int uid);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 com.android.internal.location;
|
||||
|
||||
parcelable ProviderProperties;
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* 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 com.android.internal.location;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
/**
|
||||
* A Parcelable containing (legacy) location provider properties.
|
||||
* This object is just used inside the framework and system services.
|
||||
* @hide
|
||||
*/
|
||||
public final class ProviderProperties implements Parcelable {
|
||||
/**
|
||||
* True if provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
public final boolean mRequiresNetwork;
|
||||
|
||||
/**
|
||||
* True if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
public final boolean mRequiresSatellite;
|
||||
|
||||
/**
|
||||
* True if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
public final boolean mRequiresCell;
|
||||
|
||||
/**
|
||||
* True if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information. Cell (network) usage
|
||||
* is not considered monetary cost.
|
||||
*/
|
||||
public final boolean mHasMonetaryCost;
|
||||
|
||||
/**
|
||||
* True if the provider is able to provide altitude
|
||||
* information, false otherwise. A provider that reports altitude
|
||||
* under most circumstances but may occasionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public final boolean mSupportsAltitude;
|
||||
|
||||
/**
|
||||
* True if the provider is able to provide speed
|
||||
* information, false otherwise. A provider that reports speed
|
||||
* under most circumstances but may occasionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public final boolean mSupportsSpeed;
|
||||
|
||||
/**
|
||||
* True if the provider is able to provide bearing
|
||||
* information, false otherwise. A provider that reports bearing
|
||||
* under most circumstances but may occasionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public final boolean mSupportsBearing;
|
||||
|
||||
/**
|
||||
* Power requirement for this provider.
|
||||
*
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_*.
|
||||
*/
|
||||
public final int mPowerRequirement;
|
||||
|
||||
/**
|
||||
* Constant describing the horizontal accuracy returned
|
||||
* by this provider.
|
||||
*
|
||||
* @return the horizontal accuracy for this provider, as one of the
|
||||
* constants Criteria.ACCURACY_COARSE or Criteria.ACCURACY_FINE
|
||||
*/
|
||||
public final int mAccuracy;
|
||||
|
||||
public ProviderProperties(boolean mRequiresNetwork,
|
||||
boolean mRequiresSatellite, boolean mRequiresCell, boolean mHasMonetaryCost,
|
||||
boolean mSupportsAltitude, boolean mSupportsSpeed, boolean mSupportsBearing,
|
||||
int mPowerRequirement, int mAccuracy) {
|
||||
this.mRequiresNetwork = mRequiresNetwork;
|
||||
this.mRequiresSatellite = mRequiresSatellite;
|
||||
this.mRequiresCell = mRequiresCell;
|
||||
this.mHasMonetaryCost = mHasMonetaryCost;
|
||||
this.mSupportsAltitude = mSupportsAltitude;
|
||||
this.mSupportsSpeed = mSupportsSpeed;
|
||||
this.mSupportsBearing = mSupportsBearing;
|
||||
this.mPowerRequirement = mPowerRequirement;
|
||||
this.mAccuracy = mAccuracy;
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ProviderProperties> CREATOR =
|
||||
new Parcelable.Creator<ProviderProperties>() {
|
||||
@Override
|
||||
public ProviderProperties createFromParcel(Parcel in) {
|
||||
boolean requiresNetwork = in.readInt() == 1;
|
||||
boolean requiresSatellite = in.readInt() == 1;
|
||||
boolean requiresCell = in.readInt() == 1;
|
||||
boolean hasMonetaryCost = in.readInt() == 1;
|
||||
boolean supportsAltitude = in.readInt() == 1;
|
||||
boolean supportsSpeed = in.readInt() == 1;
|
||||
boolean supportsBearing = in.readInt() == 1;
|
||||
int powerRequirement = in.readInt();
|
||||
int accuracy = in.readInt();
|
||||
return new ProviderProperties(requiresNetwork, requiresSatellite,
|
||||
requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing,
|
||||
powerRequirement, accuracy);
|
||||
}
|
||||
@Override
|
||||
public ProviderProperties[] newArray(int size) {
|
||||
return new ProviderProperties[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeInt(mRequiresNetwork ? 1 : 0);
|
||||
parcel.writeInt(mRequiresSatellite ? 1 : 0);
|
||||
parcel.writeInt(mRequiresCell ? 1 : 0);
|
||||
parcel.writeInt(mHasMonetaryCost ? 1 : 0);
|
||||
parcel.writeInt(mSupportsAltitude ? 1 : 0);
|
||||
parcel.writeInt(mSupportsSpeed ? 1 : 0);
|
||||
parcel.writeInt(mSupportsSpeed ? 1 : 0);
|
||||
parcel.writeInt(mPowerRequirement);
|
||||
parcel.writeInt(mAccuracy);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 com.android.internal.location;
|
||||
|
||||
parcelable ProviderRequest;
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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 com.android.internal.location;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.location.LocationRequest;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
/** @hide */
|
||||
public final class ProviderRequest implements Parcelable {
|
||||
/** Location reporting is requested (true) */
|
||||
public boolean reportLocation = false;
|
||||
|
||||
/** The smallest requested interval */
|
||||
public long interval = Long.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* A more detailed set of requests.
|
||||
* <p>Location Providers can optionally use this to
|
||||
* fine tune location updates, for example when there
|
||||
* is a high power slow interval request and a
|
||||
* low power fast interval request.
|
||||
*/
|
||||
public List<LocationRequest> locationRequests = null;
|
||||
|
||||
public ProviderRequest() {
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ProviderRequest> CREATOR =
|
||||
new Parcelable.Creator<ProviderRequest>() {
|
||||
@Override
|
||||
public ProviderRequest createFromParcel(Parcel in) {
|
||||
ProviderRequest request = new ProviderRequest();
|
||||
request.reportLocation = in.readInt() == 1;
|
||||
request.interval = in.readLong();
|
||||
int count = in.readInt();
|
||||
request.locationRequests = new ArrayList<LocationRequest>(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
request.locationRequests.add(LocationRequest.CREATOR.createFromParcel(in));
|
||||
}
|
||||
return request;
|
||||
}
|
||||
@Override
|
||||
public ProviderRequest[] newArray(int size) {
|
||||
return new ProviderRequest[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel parcel, int flags) {
|
||||
parcel.writeInt(reportLocation ? 1 : 0);
|
||||
parcel.writeLong(interval);
|
||||
parcel.writeParcelableArray(locationRequests.toArray(
|
||||
new LocationRequest[locationRequests.size()]), 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("ProviderRequest[");
|
||||
if (reportLocation) {
|
||||
s.append("ON");
|
||||
s.append(" interval=");
|
||||
TimeUtils.formatDuration(interval, s);
|
||||
} else {
|
||||
s.append("OFF");
|
||||
}
|
||||
s.append(']');
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,8 @@ LOCAL_MODULE:= com.android.location.provider
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-subdir-java-files)
|
||||
$(call all-subdir-java-files) \
|
||||
$(call all-aidl-files-under, java)
|
||||
|
||||
include $(BUILD_JAVA_LIBRARY)
|
||||
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.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;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* An abstract superclass for location providers that are implemented
|
||||
* outside of the core android platform.
|
||||
* Location providers can be implemented as services and return the result of
|
||||
* {@link LocationProvider#getBinder()} in its getBinder() method.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract class LocationProvider {
|
||||
|
||||
private static final String TAG = "LocationProvider";
|
||||
|
||||
private ILocationManager mLocationManager;
|
||||
|
||||
private ILocationProvider.Stub mProvider = new ILocationProvider.Stub() {
|
||||
|
||||
public boolean requiresNetwork() {
|
||||
return LocationProvider.this.onRequiresNetwork();
|
||||
}
|
||||
|
||||
public boolean requiresSatellite() {
|
||||
return LocationProvider.this.onRequiresSatellite();
|
||||
}
|
||||
|
||||
public boolean requiresCell() {
|
||||
return LocationProvider.this.onRequiresCell();
|
||||
}
|
||||
|
||||
public boolean hasMonetaryCost() {
|
||||
return LocationProvider.this.onHasMonetaryCost();
|
||||
}
|
||||
|
||||
public boolean supportsAltitude() {
|
||||
return LocationProvider.this.onSupportsAltitude();
|
||||
}
|
||||
|
||||
public boolean supportsSpeed() {
|
||||
return LocationProvider.this.onSupportsSpeed();
|
||||
}
|
||||
|
||||
public boolean supportsBearing() {
|
||||
return LocationProvider.this.onSupportsBearing();
|
||||
}
|
||||
|
||||
public int getPowerRequirement() {
|
||||
return LocationProvider.this.onGetPowerRequirement();
|
||||
}
|
||||
|
||||
public boolean meetsCriteria(Criteria criteria) {
|
||||
return LocationProvider.this.onMeetsCriteria(criteria);
|
||||
}
|
||||
|
||||
public int getAccuracy() {
|
||||
return LocationProvider.this.onGetAccuracy();
|
||||
}
|
||||
|
||||
public void enable() {
|
||||
LocationProvider.this.onEnable();
|
||||
}
|
||||
|
||||
public void disable() {
|
||||
LocationProvider.this.onDisable();
|
||||
}
|
||||
|
||||
public int getStatus(Bundle extras) {
|
||||
return LocationProvider.this.onGetStatus(extras);
|
||||
}
|
||||
|
||||
public long getStatusUpdateTime() {
|
||||
return LocationProvider.this.onGetStatusUpdateTime();
|
||||
}
|
||||
|
||||
public String getInternalState() {
|
||||
return LocationProvider.this.onGetInternalState();
|
||||
}
|
||||
|
||||
public void enableLocationTracking(boolean enable) {
|
||||
LocationProvider.this.onEnableLocationTracking(enable);
|
||||
}
|
||||
|
||||
public void setMinTime(long minTime, WorkSource ws) {
|
||||
LocationProvider.this.onSetMinTime(minTime, ws);
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state, NetworkInfo info) {
|
||||
LocationProvider.this.onUpdateNetworkState(state, info);
|
||||
}
|
||||
|
||||
public void updateLocation(Location location) {
|
||||
LocationProvider.this.onUpdateLocation(location);
|
||||
}
|
||||
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return LocationProvider.this.onSendExtraCommand(command, extras);
|
||||
}
|
||||
|
||||
public void addListener(int uid) {
|
||||
LocationProvider.this.onAddListener(uid, new WorkSource(uid));
|
||||
}
|
||||
|
||||
public void removeListener(int uid) {
|
||||
LocationProvider.this.onRemoveListener(uid, new WorkSource(uid));
|
||||
}
|
||||
};
|
||||
|
||||
public LocationProvider() {
|
||||
IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
|
||||
mLocationManager = ILocationManager.Stub.asInterface(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
/* package */ ILocationProvider getInterface() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Binder interface for the location provider.
|
||||
* This is intended to be used for the onBind() method of
|
||||
* a service that implements a location provider service.
|
||||
*
|
||||
* @return the IBinder instance for the provider
|
||||
*/
|
||||
public IBinder getBinder() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the location provider to report new locations.
|
||||
*
|
||||
* @param location new Location to report
|
||||
*
|
||||
* Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
|
||||
*/
|
||||
public void reportLocation(Location location) {
|
||||
try {
|
||||
mLocationManager.reportLocation(location, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException in reportLocation: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
public abstract boolean onRequiresNetwork();
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
public abstract boolean onRequiresSatellite();
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
public abstract boolean onRequiresCell();
|
||||
|
||||
/**
|
||||
* Returns true if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information.
|
||||
*/
|
||||
public abstract boolean onHasMonetaryCost();
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide altitude
|
||||
* information, false otherwise. A provider that reports altitude
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean onSupportsAltitude();
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide speed
|
||||
* information, false otherwise. A provider that reports speed
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean onSupportsSpeed();
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide bearing
|
||||
* information, false otherwise. A provider that reports bearing
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public abstract boolean onSupportsBearing();
|
||||
|
||||
/**
|
||||
* Returns the power requirement for this provider.
|
||||
*
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_REQUIREMENT_*.
|
||||
*/
|
||||
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
|
||||
* location is only approximate then {@link Criteria#ACCURACY_COARSE}
|
||||
* is returned.
|
||||
*/
|
||||
public abstract int onGetAccuracy();
|
||||
|
||||
/**
|
||||
* Enables the location provider
|
||||
*/
|
||||
public abstract void onEnable();
|
||||
|
||||
/**
|
||||
* Disables the location provider
|
||||
*/
|
||||
public abstract void onDisable();
|
||||
|
||||
/**
|
||||
* Returns a information on the status of this provider.
|
||||
* {@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
|
||||
* out of service, and this is not expected to change in the near
|
||||
* future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if
|
||||
* the provider is temporarily unavailable but is expected to be
|
||||
* available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned
|
||||
* if the provider is currently available.
|
||||
*
|
||||
* <p> If extras is non-null, additional status information may be
|
||||
* added to it in the form of provider-specific key/value pairs.
|
||||
*/
|
||||
public abstract int onGetStatus(Bundle extras);
|
||||
|
||||
/**
|
||||
* Returns the time at which the status was last updated. It is the
|
||||
* responsibility of the provider to appropriately set this value using
|
||||
* {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
|
||||
* there is a status update that it wishes to broadcast to all its
|
||||
* listeners. The provider should be careful not to broadcast
|
||||
* the same status again.
|
||||
*
|
||||
* @return time of last status update in millis since last reboot
|
||||
*/
|
||||
public abstract long onGetStatusUpdateTime();
|
||||
|
||||
/**
|
||||
* Returns debugging information about the location provider.
|
||||
*
|
||||
* @return string describing the internal state of the location provider, or null.
|
||||
*/
|
||||
public abstract String onGetInternalState();
|
||||
|
||||
/**
|
||||
* Notifies the location provider that clients are listening for locations.
|
||||
* Called with enable set to true when the first client is added and
|
||||
* called with enable set to false when the last client is removed.
|
||||
* This allows the provider to prepare for receiving locations,
|
||||
* and to shut down when no clients are remaining.
|
||||
*
|
||||
* @param enable true if location tracking should be enabled.
|
||||
*/
|
||||
public abstract void onEnableLocationTracking(boolean enable);
|
||||
|
||||
/**
|
||||
* Notifies the location provider of the smallest minimum time between updates amongst
|
||||
* all clients that are listening for locations. This allows the provider to reduce
|
||||
* the frequency of updates to match the requested frequency.
|
||||
*
|
||||
* @param minTime the smallest minTime value over all listeners for this provider.
|
||||
* @param ws the source this work is coming from.
|
||||
*/
|
||||
public abstract void onSetMinTime(long minTime, WorkSource ws);
|
||||
|
||||
/**
|
||||
* Updates the network state for the given provider. This function must
|
||||
* be overwritten if {@link android.location.LocationProvider#requiresNetwork} returns true.
|
||||
* The state is {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} (disconnected)
|
||||
* OR {@link android.location.LocationProvider#AVAILABLE} (connected or connecting).
|
||||
*
|
||||
* @param state data state
|
||||
*/
|
||||
public abstract void onUpdateNetworkState(int state, NetworkInfo info);
|
||||
|
||||
/**
|
||||
* Informs the provider when a new location has been computed by a different
|
||||
* location provider. This is intended to be used as aiding data for the
|
||||
* receiving provider.
|
||||
*
|
||||
* @param location new location from other location provider
|
||||
*/
|
||||
public abstract void onUpdateLocation(Location location);
|
||||
|
||||
/**
|
||||
* Implements addditional location provider specific additional commands.
|
||||
*
|
||||
* @param command name of the command to send to the provider.
|
||||
* @param extras optional arguments for the command (or null).
|
||||
* The provider may optionally fill the extras Bundle with results from the command.
|
||||
*
|
||||
* @return true if the command succeeds.
|
||||
*/
|
||||
public abstract boolean onSendExtraCommand(String command, Bundle extras);
|
||||
|
||||
/**
|
||||
* Notifies the location provider when a new client is listening for locations.
|
||||
*
|
||||
* @param uid user ID of the new client.
|
||||
* @param ws a WorkSource representation of the client.
|
||||
*/
|
||||
public abstract void onAddListener(int uid, WorkSource ws);
|
||||
|
||||
/**
|
||||
* Notifies the location provider when a client is no longer listening for locations.
|
||||
*
|
||||
* @param uid user ID of the client no longer listening.
|
||||
* @param ws a WorkSource representation of the client.
|
||||
*/
|
||||
public abstract void onRemoveListener(int uid, WorkSource ws);
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.android.location.provider;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.ILocationProvider;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
|
||||
/**
|
||||
* Base class for location providers implemented as services.
|
||||
* @hide
|
||||
*/
|
||||
public abstract class LocationProviderBase {
|
||||
private final String TAG;
|
||||
|
||||
protected final ILocationManager mLocationManager;
|
||||
private final ProviderProperties mProperties;
|
||||
private final IBinder mBinder;
|
||||
|
||||
private final class Service extends ILocationProvider.Stub {
|
||||
@Override
|
||||
public void enable() {
|
||||
onEnable();
|
||||
}
|
||||
@Override
|
||||
public void disable() {
|
||||
onDisable();
|
||||
}
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource ws) {
|
||||
onSetRequest(new ProviderRequestUnbundled(request), ws);
|
||||
}
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
return onGetStatus(extras);
|
||||
}
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return onGetStatusUpdateTime();
|
||||
}
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return onSendExtraCommand(command, extras);
|
||||
}
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, String[] args) {
|
||||
PrintWriter pw = new PrintWriter(new FileOutputStream(fd));
|
||||
onDump(fd, pw, args);
|
||||
pw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public LocationProviderBase(String tag, ProviderPropertiesUnbundled properties) {
|
||||
TAG = tag;
|
||||
IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
|
||||
mLocationManager = ILocationManager.Stub.asInterface(b);
|
||||
mProperties = properties.getProviderProperties();
|
||||
mBinder = new Service();
|
||||
}
|
||||
|
||||
public IBinder getBinder() {
|
||||
return mBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by the location provider to report new locations.
|
||||
*
|
||||
* @param location new Location to report
|
||||
*
|
||||
* Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
|
||||
*/
|
||||
public final void reportLocation(Location location) {
|
||||
try {
|
||||
mLocationManager.reportLocation(location, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException", e);
|
||||
} catch (Exception e) {
|
||||
// never crash provider, might be running in a system process
|
||||
Log.e(TAG, "Exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the location provider.
|
||||
* <p>The provider may initialize resources, but does
|
||||
* not yet need to report locations.
|
||||
*/
|
||||
public abstract void onEnable();
|
||||
|
||||
/**
|
||||
* Disable the location provider.
|
||||
* <p>The provider must release resources, and stop
|
||||
* performing work. It may no longer report locations.
|
||||
*/
|
||||
public abstract void onDisable();
|
||||
|
||||
/**
|
||||
* Set the {@link ProviderRequest} requirements for this provider.
|
||||
* <p>Each call to this method overrides all previous requests.
|
||||
* <p>This method might trigger the provider to start returning
|
||||
* locations, or to stop returning locations, depending on the
|
||||
* parameters in the request.
|
||||
*/
|
||||
public abstract void onSetRequest(ProviderRequestUnbundled request, WorkSource source);
|
||||
|
||||
/**
|
||||
* Dump debug information.
|
||||
*/
|
||||
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a information on the status of this provider.
|
||||
* <p>{@link android.location.LocationProvider#OUT_OF_SERVICE} is returned if the provider is
|
||||
* out of service, and this is not expected to change in the near
|
||||
* future; {@link android.location.LocationProvider#TEMPORARILY_UNAVAILABLE} is returned if
|
||||
* the provider is temporarily unavailable but is expected to be
|
||||
* available shortly; and {@link android.location.LocationProvider#AVAILABLE} is returned
|
||||
* if the provider is currently available.
|
||||
*
|
||||
* <p>If extras is non-null, additional status information may be
|
||||
* added to it in the form of provider-specific key/value pairs.
|
||||
*/
|
||||
public abstract int onGetStatus(Bundle extras);
|
||||
|
||||
/**
|
||||
* Returns the time at which the status was last updated. It is the
|
||||
* responsibility of the provider to appropriately set this value using
|
||||
* {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()}.
|
||||
* there is a status update that it wishes to broadcast to all its
|
||||
* listeners. The provider should be careful not to broadcast
|
||||
* the same status again.
|
||||
*
|
||||
* @return time of last status update in millis since last reboot
|
||||
*/
|
||||
public abstract long onGetStatusUpdateTime();
|
||||
|
||||
/**
|
||||
* Implements addditional location provider specific additional commands.
|
||||
*
|
||||
* @param command name of the command to send to the provider.
|
||||
* @param extras optional arguments for the command (or null).
|
||||
* The provider may optionally fill the extras Bundle with results from the command.
|
||||
*
|
||||
* @return true if the command succeeds.
|
||||
*/
|
||||
public boolean onSendExtraCommand(String command, Bundle extras) {
|
||||
// default implementation
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 com.android.location.provider;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
|
||||
/**
|
||||
* This class is a public API for unbundled providers,
|
||||
* that hides the (hidden framework) ProviderProperties.
|
||||
* <p>Do _not_ remove public methods on this class.
|
||||
*/
|
||||
public final class ProviderPropertiesUnbundled {
|
||||
private final ProviderProperties mProperties;
|
||||
|
||||
public static ProviderPropertiesUnbundled create(boolean requiresNetwork,
|
||||
boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost,
|
||||
boolean supportsAltitude, boolean supportsSpeed, boolean supportsBearing,
|
||||
int powerRequirement, int accuracy) {
|
||||
return new ProviderPropertiesUnbundled(new ProviderProperties(requiresNetwork,
|
||||
requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
|
||||
supportsBearing, powerRequirement, accuracy));
|
||||
}
|
||||
|
||||
private ProviderPropertiesUnbundled(ProviderProperties properties) {
|
||||
mProperties = properties;
|
||||
}
|
||||
|
||||
public ProviderProperties getProviderProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mProperties.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 com.android.location.provider;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.location.LocationRequest;
|
||||
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
/**
|
||||
* This class is a public API for unbundled providers,
|
||||
* that hides the (hidden framework) ProviderRequest.
|
||||
* <p>Do _not_ remove public methods on this class.
|
||||
*/
|
||||
public final class ProviderRequestUnbundled {
|
||||
private final ProviderRequest mRequest;
|
||||
|
||||
public ProviderRequestUnbundled(ProviderRequest request) {
|
||||
mRequest = request;
|
||||
}
|
||||
|
||||
public boolean getReportLocation() {
|
||||
return mRequest.reportLocation;
|
||||
}
|
||||
|
||||
public long getInterval() {
|
||||
return mRequest.interval;
|
||||
}
|
||||
|
||||
public List<LocationRequest> getLocationRequests() {
|
||||
return mRequest.locationRequests;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mRequest.toString();
|
||||
}
|
||||
}
|
||||
27
packages/FusedLocation/Android.mk
Normal file
27
packages/FusedLocation/Android.mk
Normal file
@@ -0,0 +1,27 @@
|
||||
# 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.
|
||||
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := com.android.location.provider
|
||||
|
||||
LOCAL_PACKAGE_NAME := FusedLocation
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
45
packages/FusedLocation/AndroidManifest.xml
Normal file
45
packages/FusedLocation/AndroidManifest.xml
Normal file
@@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (c) 2012 Google Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
-->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.android.location.fused"
|
||||
coreApp="true">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
|
||||
|
||||
<application
|
||||
android:label="@string/app_label"
|
||||
android:process="system">
|
||||
|
||||
<uses-library android:name="com.android.location.provider" />
|
||||
|
||||
<!-- Fused Location Service that LocationManagerService binds to.
|
||||
LocationManagerService will bind to the service with the highest
|
||||
version. -->
|
||||
<service android:name="com.android.location.fused.FusedLocationService"
|
||||
android:exported="true"
|
||||
android:permission="android.permission.WRITE_SECURE_SETTINGS" >
|
||||
<intent-filter>
|
||||
<action android:name="com.android.location.service.FusedLocationProvider" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="version" android:value="1" />
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
||||
0
packages/FusedLocation/MODULE_LICENSE_APACHE2
Normal file
0
packages/FusedLocation/MODULE_LICENSE_APACHE2
Normal file
190
packages/FusedLocation/NOTICE
Normal file
190
packages/FusedLocation/NOTICE
Normal file
@@ -0,0 +1,190 @@
|
||||
|
||||
Copyright (c) 2005-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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
5
packages/FusedLocation/res/values/strings.xml
Normal file
5
packages/FusedLocation/res/values/strings.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Name of the application. [CHAR LIMIT=35] -->
|
||||
<string name="app_label">Fused Location</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 com.android.location.fused;
|
||||
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import com.android.location.provider.LocationProviderBase;
|
||||
import com.android.location.provider.ProviderPropertiesUnbundled;
|
||||
import com.android.location.provider.ProviderRequestUnbundled;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Criteria;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Message;
|
||||
import android.os.WorkSource;
|
||||
|
||||
public class FusedLocationProvider extends LocationProviderBase implements FusionEngine.Callback {
|
||||
private static final String TAG = "FusedLocationProvider";
|
||||
|
||||
private static ProviderPropertiesUnbundled PROPERTIES = ProviderPropertiesUnbundled.create(
|
||||
false, false, false, false, true, true, true, Criteria.POWER_LOW,
|
||||
Criteria.ACCURACY_FINE);
|
||||
|
||||
private static final int MSG_ENABLE = 1;
|
||||
private static final int MSG_DISABLE = 2;
|
||||
private static final int MSG_SET_REQUEST = 3;
|
||||
|
||||
private final Context mContext;
|
||||
private final FusionEngine mEngine;
|
||||
|
||||
private static class RequestWrapper {
|
||||
public ProviderRequestUnbundled request;
|
||||
public WorkSource source;
|
||||
public RequestWrapper(ProviderRequestUnbundled request, WorkSource source) {
|
||||
this.request = request;
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
public FusedLocationProvider(Context context) {
|
||||
super(TAG, PROPERTIES);
|
||||
mContext = context;
|
||||
mEngine = new FusionEngine(context, Looper.myLooper());
|
||||
}
|
||||
|
||||
/**
|
||||
* For serializing requests to mEngine.
|
||||
*/
|
||||
private Handler mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case MSG_ENABLE:
|
||||
mEngine.init(FusedLocationProvider.this);
|
||||
break;
|
||||
case MSG_DISABLE:
|
||||
mEngine.deinit();
|
||||
break;
|
||||
case MSG_SET_REQUEST:
|
||||
{
|
||||
RequestWrapper wrapper = (RequestWrapper) msg.obj;
|
||||
mEngine.setRequirements(wrapper.request, wrapper.source);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
mHandler.sendEmptyMessage(MSG_ENABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
mHandler.sendEmptyMessage(MSG_DISABLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetRequest(ProviderRequestUnbundled request, WorkSource source) {
|
||||
mHandler.obtainMessage(MSG_SET_REQUEST, new RequestWrapper(request, source));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
// perform synchronously
|
||||
mEngine.dump(fd, pw, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onGetStatus(Bundle extras) {
|
||||
return LocationProvider.AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long onGetStatusUpdateTime() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 com.android.location.fused;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
|
||||
public class FusedLocationService extends Service {
|
||||
private FusedLocationProvider mProvider;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (mProvider == null) {
|
||||
mProvider = new FusedLocationProvider(getApplicationContext());
|
||||
}
|
||||
return mProvider.getBinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onUnbind(Intent intent) {
|
||||
// make sure to stop performing work
|
||||
if (mProvider != null) {
|
||||
mProvider.onDisable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
mProvider = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* 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 com.android.location.fused;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.android.location.provider.ProviderRequestUnbundled;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationRequest;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
public class FusionEngine implements LocationListener {
|
||||
public interface Callback {
|
||||
public void reportLocation(Location location);
|
||||
}
|
||||
|
||||
private static final String TAG = "FusedLocation";
|
||||
private static final String NETWORK = LocationManager.NETWORK_PROVIDER;
|
||||
private static final String GPS = LocationManager.GPS_PROVIDER;
|
||||
|
||||
// threshold below which a location is considered stale enough
|
||||
// that we shouldn't use its bearing, altitude, speed etc
|
||||
private static final double WEIGHT_THRESHOLD = 0.5;
|
||||
// accuracy in meters at which a Location's weight is halved (compared to 0 accuracy)
|
||||
private static final double ACCURACY_HALFLIFE_M = 20.0;
|
||||
// age in seconds at which a Location's weight is halved (compared to 0 age)
|
||||
private static final double AGE_HALFLIFE_S = 60.0;
|
||||
|
||||
private static final double ACCURACY_DECAY_CONSTANT_M = Math.log(2) / ACCURACY_HALFLIFE_M;
|
||||
private static final double AGE_DECAY_CONSTANT_S = Math.log(2) / AGE_HALFLIFE_S;
|
||||
|
||||
private final Context mContext;
|
||||
private final LocationManager mLocationManager;
|
||||
private final Looper mLooper;
|
||||
|
||||
// all fields are only used on mLooper thread. except for in dump() which is not thread-safe
|
||||
private Callback mCallback;
|
||||
private Location mFusedLocation;
|
||||
private Location mGpsLocation;
|
||||
private Location mNetworkLocation;
|
||||
private double mNetworkWeight;
|
||||
private double mGpsWeight;
|
||||
|
||||
private boolean mEnabled;
|
||||
private ProviderRequestUnbundled mRequest;
|
||||
|
||||
private final HashMap<String, ProviderStats> mStats = new HashMap<String, ProviderStats>();
|
||||
|
||||
public FusionEngine(Context context, Looper looper) {
|
||||
mContext = context;
|
||||
mLocationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
mNetworkLocation = new Location("");
|
||||
mNetworkLocation.setAccuracy(Float.MAX_VALUE);
|
||||
mGpsLocation = new Location("");
|
||||
mGpsLocation.setAccuracy(Float.MAX_VALUE);
|
||||
mLooper = looper;
|
||||
|
||||
mStats.put(GPS, new ProviderStats());
|
||||
mStats.get(GPS).available = mLocationManager.isProviderEnabled(GPS);
|
||||
mStats.put(NETWORK, new ProviderStats());
|
||||
mStats.get(NETWORK).available = mLocationManager.isProviderEnabled(NETWORK);
|
||||
}
|
||||
|
||||
public void init(Callback callback) {
|
||||
Log.i(TAG, "engine started (" + mContext.getPackageName() + ")");
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to stop doing any work, and release all resources
|
||||
* This can happen when a better fusion engine is installed
|
||||
* in a different package, and this one is no longer needed.
|
||||
* Called on mLooper thread
|
||||
*/
|
||||
public void deinit() {
|
||||
mRequest = null;
|
||||
disable();
|
||||
Log.i(TAG, "engine stopped (" + mContext.getPackageName() + ")");
|
||||
}
|
||||
|
||||
private boolean isAvailable() {
|
||||
return mStats.get(GPS).available || mStats.get(NETWORK).available;
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void enable() {
|
||||
mEnabled = true;
|
||||
updateRequirements();
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void disable() {
|
||||
mEnabled = false;
|
||||
updateRequirements();
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
public void setRequirements(ProviderRequestUnbundled request, WorkSource source) {
|
||||
mRequest = request;
|
||||
mEnabled = true;
|
||||
updateRequirements();
|
||||
}
|
||||
|
||||
private static class ProviderStats {
|
||||
public boolean available;
|
||||
public boolean requested;
|
||||
public long requestTime;
|
||||
public long minTime;
|
||||
public long lastRequestTtff;
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(available ? "AVAILABLE" : "UNAVAILABLE");
|
||||
s.append(requested ? " REQUESTED" : " ---");
|
||||
return s.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private void enableProvider(String name, long minTime) {
|
||||
ProviderStats stats = mStats.get(name);
|
||||
|
||||
if (!stats.requested) {
|
||||
stats.requestTime = SystemClock.elapsedRealtime();
|
||||
stats.requested = true;
|
||||
stats.minTime = minTime;
|
||||
mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
|
||||
} else if (stats.minTime != minTime) {
|
||||
stats.minTime = minTime;
|
||||
mLocationManager.requestLocationUpdates(name, minTime, 0, this, mLooper);
|
||||
}
|
||||
}
|
||||
|
||||
private void disableProvider(String name) {
|
||||
ProviderStats stats = mStats.get(name);
|
||||
|
||||
if (stats.requested) {
|
||||
stats.requested = false;
|
||||
mLocationManager.removeUpdates(this); //TODO GLOBAL
|
||||
}
|
||||
}
|
||||
|
||||
private void updateRequirements() {
|
||||
if (mEnabled == false || mRequest == null) {
|
||||
mRequest = null;
|
||||
disableProvider(NETWORK);
|
||||
disableProvider(GPS);
|
||||
return;
|
||||
}
|
||||
|
||||
ProviderStats gpsStats = mStats.get(GPS);
|
||||
ProviderStats networkStats = mStats.get(NETWORK);
|
||||
|
||||
long networkInterval = Long.MAX_VALUE;
|
||||
long gpsInterval = Long.MAX_VALUE;
|
||||
for (LocationRequest request : mRequest.getLocationRequests()) {
|
||||
switch (request.getQuality()) {
|
||||
case LocationRequest.ACCURACY_FINE:
|
||||
case LocationRequest.POWER_HIGH:
|
||||
if (request.getInterval() < gpsInterval) {
|
||||
gpsInterval = request.getInterval();
|
||||
}
|
||||
if (request.getInterval() < networkInterval) {
|
||||
networkInterval = request.getInterval();
|
||||
}
|
||||
break;
|
||||
case LocationRequest.ACCURACY_BLOCK:
|
||||
case LocationRequest.ACCURACY_CITY:
|
||||
case LocationRequest.POWER_LOW:
|
||||
if (request.getInterval() < networkInterval) {
|
||||
networkInterval = request.getInterval();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (gpsInterval < Long.MAX_VALUE) {
|
||||
enableProvider(GPS, gpsInterval);
|
||||
} else {
|
||||
disableProvider(GPS);
|
||||
}
|
||||
if (networkInterval < Long.MAX_VALUE) {
|
||||
enableProvider(NETWORK, networkInterval);
|
||||
} else {
|
||||
disableProvider(NETWORK);
|
||||
}
|
||||
}
|
||||
|
||||
private static double weighAccuracy(Location loc) {
|
||||
double accuracy = loc.getAccuracy();
|
||||
return Math.exp(-accuracy * ACCURACY_DECAY_CONSTANT_M);
|
||||
}
|
||||
|
||||
private static double weighAge(Location loc) {
|
||||
long ageSeconds = SystemClock.elapsedRealtimeNano() - loc.getElapsedRealtimeNano();
|
||||
ageSeconds /= 1000000000L;
|
||||
if (ageSeconds < 0) ageSeconds = 0;
|
||||
return Math.exp(-ageSeconds * AGE_DECAY_CONSTANT_S);
|
||||
}
|
||||
|
||||
private double weigh(double gps, double network) {
|
||||
return (gps * mGpsWeight) + (network * mNetworkWeight);
|
||||
}
|
||||
|
||||
private double weigh(double gps, double network, double wrapMin, double wrapMax) {
|
||||
// apply aliasing
|
||||
double wrapWidth = wrapMax - wrapMin;
|
||||
if (gps - network > wrapWidth / 2) network += wrapWidth;
|
||||
else if (network - gps > wrapWidth / 2) gps += wrapWidth;
|
||||
|
||||
double result = weigh(gps, network);
|
||||
|
||||
// remove aliasing
|
||||
if (result > wrapMax) result -= wrapWidth;
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateFusedLocation() {
|
||||
// naive fusion
|
||||
mNetworkWeight = weighAccuracy(mNetworkLocation) * weighAge(mNetworkLocation);
|
||||
mGpsWeight = weighAccuracy(mGpsLocation) * weighAge(mGpsLocation);
|
||||
// scale mNetworkWeight and mGpsWeight so that they add to 1
|
||||
double totalWeight = mNetworkWeight + mGpsWeight;
|
||||
mNetworkWeight /= totalWeight;
|
||||
mGpsWeight /= totalWeight;
|
||||
|
||||
Location fused = new Location(LocationManager.FUSED_PROVIDER);
|
||||
// fuse lat/long
|
||||
// assumes the two locations are close enough that earth curvature doesn't matter
|
||||
fused.setLatitude(weigh(mGpsLocation.getLatitude(), mNetworkLocation.getLatitude()));
|
||||
fused.setLongitude(weigh(mGpsLocation.getLongitude(), mNetworkLocation.getLongitude(),
|
||||
-180.0, 180.0));
|
||||
|
||||
// fused accuracy
|
||||
//TODO: use some real math instead of this crude fusion
|
||||
// one suggestion is to fuse in a quadratic manner, eg
|
||||
// sqrt(weigh(gpsAcc^2, netAcc^2)).
|
||||
// another direction to explore is to consider the difference in the 2
|
||||
// locations. If the component locations overlap, the fused accuracy is
|
||||
// better than the component accuracies. If they are far apart,
|
||||
// the fused accuracy is much worse.
|
||||
fused.setAccuracy((float)weigh(mGpsLocation.getAccuracy(), mNetworkLocation.getAccuracy()));
|
||||
|
||||
// fused time - now
|
||||
fused.setTime(System.currentTimeMillis());
|
||||
fused.setElapsedRealtimeNano(SystemClock.elapsedRealtimeNano());
|
||||
|
||||
// fuse altitude
|
||||
if (mGpsLocation.hasAltitude() && !mNetworkLocation.hasAltitude() &&
|
||||
mGpsWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setAltitude(mGpsLocation.getAltitude()); // use GPS
|
||||
} else if (!mGpsLocation.hasAltitude() && mNetworkLocation.hasAltitude() &&
|
||||
mNetworkWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setAltitude(mNetworkLocation.getAltitude()); // use Network
|
||||
} else if (mGpsLocation.hasAltitude() && mNetworkLocation.hasAltitude()) {
|
||||
fused.setAltitude(weigh(mGpsLocation.getAltitude(), mNetworkLocation.getAltitude()));
|
||||
}
|
||||
|
||||
// fuse speed
|
||||
if (mGpsLocation.hasSpeed() && !mNetworkLocation.hasSpeed() &&
|
||||
mGpsWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setSpeed(mGpsLocation.getSpeed()); // use GPS if its not too old
|
||||
} else if (!mGpsLocation.hasSpeed() && mNetworkLocation.hasSpeed() &&
|
||||
mNetworkWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setSpeed(mNetworkLocation.getSpeed()); // use Network
|
||||
} else if (mGpsLocation.hasSpeed() && mNetworkLocation.hasSpeed()) {
|
||||
fused.setSpeed((float)weigh(mGpsLocation.getSpeed(), mNetworkLocation.getSpeed()));
|
||||
}
|
||||
|
||||
// fuse bearing
|
||||
if (mGpsLocation.hasBearing() && !mNetworkLocation.hasBearing() &&
|
||||
mGpsWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setBearing(mGpsLocation.getBearing()); // use GPS if its not too old
|
||||
} else if (!mGpsLocation.hasBearing() && mNetworkLocation.hasBearing() &&
|
||||
mNetworkWeight > WEIGHT_THRESHOLD) {
|
||||
fused.setBearing(mNetworkLocation.getBearing()); // use Network
|
||||
} else if (mGpsLocation.hasBearing() && mNetworkLocation.hasBearing()) {
|
||||
fused.setBearing((float)weigh(mGpsLocation.getBearing(), mNetworkLocation.getBearing(),
|
||||
0.0, 360.0));
|
||||
}
|
||||
|
||||
mFusedLocation = fused;
|
||||
|
||||
mCallback.reportLocation(mFusedLocation);
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
if (GPS.equals(location.getProvider())) {
|
||||
mGpsLocation = location;
|
||||
updateFusedLocation();
|
||||
} else if (NETWORK.equals(location.getProvider())) {
|
||||
mNetworkLocation = location;
|
||||
updateFusedLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) { }
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
ProviderStats stats = mStats.get(provider);
|
||||
if (stats == null) return;
|
||||
|
||||
stats.available = true;
|
||||
}
|
||||
|
||||
/** Called on mLooper thread */
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
ProviderStats stats = mStats.get(provider);
|
||||
if (stats == null) return;
|
||||
|
||||
stats.available = false;
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("mEnabled=" + mEnabled).append(' ').append(mRequest).append('\n');
|
||||
s.append("fused=").append(mFusedLocation).append('\n');
|
||||
s.append(String.format("gps %.3f %s\n", mGpsWeight, mGpsLocation));
|
||||
s.append(" ").append(mStats.get(GPS)).append('\n');
|
||||
s.append(String.format("net %.3f %s\n", mNetworkWeight, mNetworkLocation));
|
||||
s.append(" ").append(mStats.get(NETWORK)).append('\n');
|
||||
pw.append(s);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
274
services/java/com/android/server/ServiceWatcher.java
Normal file
274
services/java/com/android/server/ServiceWatcher.java
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* 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 com.android.server;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.Signature;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Find the best Service, and bind to it.
|
||||
* Handles run-time package changes.
|
||||
*/
|
||||
public class ServiceWatcher implements ServiceConnection {
|
||||
private static final boolean D = false;
|
||||
private static final String EXTRA_VERSION = "version";
|
||||
|
||||
private final String mTag;
|
||||
private final Context mContext;
|
||||
private final PackageManager mPm;
|
||||
private final List<HashSet<Signature>> mSignatureSets;
|
||||
private final String mAction;
|
||||
private final Runnable mNewServiceWork;
|
||||
private final Handler mHandler;
|
||||
|
||||
private Object mLock = new Object();
|
||||
|
||||
// all fields below synchronized on mLock
|
||||
private IBinder mBinder; // connected service
|
||||
private String mPackageName; // current best package
|
||||
private int mVersion; // current best version
|
||||
|
||||
public ServiceWatcher(Context context, String logTag, String action,
|
||||
List<String> initialPackageNames, Runnable newServiceWork, Handler handler) {
|
||||
mContext = context;
|
||||
mTag = logTag;
|
||||
mAction = action;
|
||||
mPm = mContext.getPackageManager();
|
||||
mNewServiceWork = newServiceWork;
|
||||
mHandler = handler;
|
||||
|
||||
mSignatureSets = new ArrayList<HashSet<Signature>>();
|
||||
for (int i=0; i < initialPackageNames.size(); i++) {
|
||||
String pkg = initialPackageNames.get(i);
|
||||
HashSet<Signature> set = new HashSet<Signature>();
|
||||
try {
|
||||
Signature[] sigs =
|
||||
mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
|
||||
set.addAll(Arrays.asList(sigs));
|
||||
mSignatureSets.add(set);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(logTag, pkg + " not found");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean start() {
|
||||
if (!bindBestPackage(null)) return false;
|
||||
|
||||
mPackageMonitor.register(mContext, null, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches and binds to the best package, or do nothing
|
||||
* if the best package is already bound.
|
||||
* Only checks the named package, or checks all packages if it
|
||||
* is null.
|
||||
* Return true if a new package was found to bind to.
|
||||
*/
|
||||
private boolean bindBestPackage(String justCheckThisPackage) {
|
||||
Intent intent = new Intent(mAction);
|
||||
if (justCheckThisPackage != null) {
|
||||
intent.setPackage(justCheckThisPackage);
|
||||
}
|
||||
List<ResolveInfo> rInfos = mPm.queryIntentServices(new Intent(mAction),
|
||||
PackageManager.GET_META_DATA);
|
||||
int bestVersion = Integer.MIN_VALUE;
|
||||
String bestPackage = null;
|
||||
for (ResolveInfo rInfo : rInfos) {
|
||||
String packageName = rInfo.serviceInfo.packageName;
|
||||
|
||||
// check signature
|
||||
try {
|
||||
PackageInfo pInfo;
|
||||
pInfo = mPm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
|
||||
if (!isSignatureMatch(pInfo.signatures)) {
|
||||
Log.w(mTag, packageName + " resolves service " + mAction +
|
||||
", but has wrong signature, ignoring");
|
||||
continue;
|
||||
}
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.wtf(mTag, e);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check version
|
||||
int version = 0;
|
||||
if (rInfo.serviceInfo.metaData != null) {
|
||||
version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0);
|
||||
}
|
||||
if (version > mVersion) {
|
||||
bestVersion = version;
|
||||
bestPackage = packageName;
|
||||
}
|
||||
}
|
||||
|
||||
if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s",
|
||||
(justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
|
||||
rInfos.size(),
|
||||
(bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
|
||||
|
||||
if (bestPackage != null) {
|
||||
bindToPackage(bestPackage, bestVersion);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void unbind() {
|
||||
String pkg;
|
||||
synchronized (mLock) {
|
||||
pkg = mPackageName;
|
||||
mPackageName = null;
|
||||
mVersion = Integer.MIN_VALUE;
|
||||
}
|
||||
if (pkg != null) {
|
||||
if (D) Log.d(mTag, "unbinding " + pkg);
|
||||
mContext.unbindService(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindToPackage(String packageName, int version) {
|
||||
unbind();
|
||||
Intent intent = new Intent(mAction);
|
||||
intent.setPackage(packageName);
|
||||
synchronized (mLock) {
|
||||
mPackageName = packageName;
|
||||
mVersion = version;
|
||||
}
|
||||
if (D) Log.d(mTag, "binding " + packageName + " (version " + version + ")");
|
||||
mContext.bindService(intent, this, Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
|
||||
| Context.BIND_ALLOW_OOM_MANAGEMENT);
|
||||
}
|
||||
|
||||
private boolean isSignatureMatch(Signature[] signatures) {
|
||||
if (signatures == null) return false;
|
||||
|
||||
// build hashset of input to test against
|
||||
HashSet<Signature> inputSet = new HashSet<Signature>();
|
||||
for (Signature s : signatures) {
|
||||
inputSet.add(s);
|
||||
}
|
||||
|
||||
// test input against each of the signature sets
|
||||
for (HashSet<Signature> referenceSet : mSignatureSets) {
|
||||
if (referenceSet.equals(inputSet)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
||||
/**
|
||||
* Called when package has been reinstalled
|
||||
*/
|
||||
@Override
|
||||
public void onPackageUpdateFinished(String packageName, int uid) {
|
||||
if (packageName.equals(mPackageName)) {
|
||||
// package updated, make sure to rebind
|
||||
unbind();
|
||||
}
|
||||
// check the updated package in case it is better
|
||||
bindBestPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, int uid) {
|
||||
if (packageName.equals(mPackageName)) {
|
||||
// package updated, make sure to rebind
|
||||
unbind();
|
||||
}
|
||||
// check the new package is case it is better
|
||||
bindBestPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, int uid) {
|
||||
if (packageName.equals(mPackageName)) {
|
||||
unbind();
|
||||
// the currently bound package was removed,
|
||||
// need to search for a new package
|
||||
bindBestPackage(null);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder binder) {
|
||||
synchronized (mLock) {
|
||||
String packageName = name.getPackageName();
|
||||
if (packageName.equals(mPackageName)) {
|
||||
if (D) Log.d(mTag, packageName + " connected");
|
||||
mBinder = binder;
|
||||
if (mHandler !=null && mNewServiceWork != null) {
|
||||
mHandler.post(mNewServiceWork);
|
||||
}
|
||||
} else {
|
||||
Log.w(mTag, "unexpected onServiceConnected: " + packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
synchronized (mLock) {
|
||||
String packageName = name.getPackageName();
|
||||
if (D) Log.d(mTag, packageName + " disconnected");
|
||||
|
||||
if (packageName.equals(mPackageName)) {
|
||||
mBinder = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getBestPackageName() {
|
||||
synchronized (mLock) {
|
||||
return mPackageName;
|
||||
}
|
||||
}
|
||||
|
||||
public int getBestVersion() {
|
||||
synchronized (mLock) {
|
||||
return mVersion;
|
||||
}
|
||||
}
|
||||
|
||||
public IBinder getBinder() {
|
||||
synchronized (mLock) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,92 +16,64 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.location.Address;
|
||||
import android.location.GeocoderParams;
|
||||
import android.location.IGeocodeProvider;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.server.ServiceWatcher;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class for proxying IGeocodeProvider implementations.
|
||||
*
|
||||
* {@hide}
|
||||
* Proxy for IGeocodeProvider implementations.
|
||||
*/
|
||||
public class GeocoderProxy {
|
||||
|
||||
private static final String TAG = "GeocoderProxy";
|
||||
|
||||
public static final String SERVICE_ACTION =
|
||||
"com.android.location.service.GeocodeProvider";
|
||||
private static final String SERVICE_ACTION = "com.android.location.service.GeocodeProvider";
|
||||
|
||||
private final Context mContext;
|
||||
private final Intent mIntent;
|
||||
private final Object mMutex = new Object(); // synchronizes access to mServiceConnection
|
||||
private Connection mServiceConnection; // never null after ctor
|
||||
private final ServiceWatcher mServiceWatcher;
|
||||
|
||||
public GeocoderProxy(Context context, String packageName) {
|
||||
public static GeocoderProxy createAndBind(Context context,
|
||||
List<String> initialPackageNames) {
|
||||
GeocoderProxy proxy = new GeocoderProxy(context, initialPackageNames);
|
||||
if (proxy.bind()) {
|
||||
return proxy;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public GeocoderProxy(Context context, List<String> initialPackageNames) {
|
||||
mContext = context;
|
||||
mIntent = new Intent(SERVICE_ACTION);
|
||||
reconnect(packageName);
|
||||
|
||||
mServiceWatcher = new ServiceWatcher(mContext, TAG, SERVICE_ACTION, initialPackageNames,
|
||||
null, null);
|
||||
}
|
||||
|
||||
/** Bind to service. Will reconnect if already connected */
|
||||
public void reconnect(String packageName) {
|
||||
synchronized (mMutex) {
|
||||
if (mServiceConnection != null) {
|
||||
mContext.unbindService(mServiceConnection);
|
||||
}
|
||||
mServiceConnection = new Connection();
|
||||
mIntent.setPackage(packageName);
|
||||
mContext.bindService(mIntent, mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND
|
||||
| Context.BIND_ALLOW_OOM_MANAGEMENT);
|
||||
}
|
||||
private boolean bind () {
|
||||
return mServiceWatcher.start();
|
||||
}
|
||||
|
||||
private class Connection implements ServiceConnection {
|
||||
private IGeocodeProvider getService() {
|
||||
return IGeocodeProvider.Stub.asInterface(mServiceWatcher.getBinder());
|
||||
}
|
||||
|
||||
private IGeocodeProvider mProvider;
|
||||
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
synchronized (this) {
|
||||
mProvider = IGeocodeProvider.Stub.asInterface(service);
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
synchronized (this) {
|
||||
mProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public IGeocodeProvider getProvider() {
|
||||
synchronized (this) {
|
||||
return mProvider;
|
||||
}
|
||||
}
|
||||
public String getConnectedPackageName() {
|
||||
return mServiceWatcher.getBestPackageName();
|
||||
}
|
||||
|
||||
public String getFromLocation(double latitude, double longitude, int maxResults,
|
||||
GeocoderParams params, List<Address> addrs) {
|
||||
IGeocodeProvider provider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
IGeocodeProvider provider = getService();
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.getFromLocation(latitude, longitude, maxResults,
|
||||
params, addrs);
|
||||
return provider.getFromLocation(latitude, longitude, maxResults, params, addrs);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "getFromLocation failed", e);
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return "Service not Available";
|
||||
@@ -111,19 +83,17 @@ public class GeocoderProxy {
|
||||
double lowerLeftLatitude, double lowerLeftLongitude,
|
||||
double upperRightLatitude, double upperRightLongitude, int maxResults,
|
||||
GeocoderParams params, List<Address> addrs) {
|
||||
IGeocodeProvider provider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
IGeocodeProvider provider = getService();
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.getFromLocationName(locationName, lowerLeftLatitude,
|
||||
lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
|
||||
maxResults, params, addrs);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "getFromLocationName failed", e);
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return "Service not Available";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,47 +25,36 @@ import android.Manifest.permission;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.location.Geofence;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationRequest;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
|
||||
public class GeofenceManager implements LocationListener, PendingIntent.OnFinished {
|
||||
static final String TAG = "GeofenceManager";
|
||||
private static final String TAG = "GeofenceManager";
|
||||
|
||||
/**
|
||||
* Assume a maximum land speed, as a heuristic to throttle location updates.
|
||||
* (Air travel should result in an airplane mode toggle which will
|
||||
* force a new location update anyway).
|
||||
*/
|
||||
static final int MAX_SPEED_M_S = 100; // 360 km/hr (high speed train)
|
||||
private static final int MAX_SPEED_M_S = 100; // 360 km/hr (high speed train)
|
||||
|
||||
class GeofenceWrapper {
|
||||
final Geofence fence;
|
||||
final long expiry;
|
||||
final String packageName;
|
||||
final PendingIntent intent;
|
||||
private final Context mContext;
|
||||
private final LocationManager mLocationManager;
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
private final Looper mLooper; // looper thread to take location updates on
|
||||
|
||||
public GeofenceWrapper(Geofence fence, long expiry, String packageName,
|
||||
PendingIntent intent) {
|
||||
this.fence = fence;
|
||||
this.expiry = expiry;
|
||||
this.packageName = packageName;
|
||||
this.intent = intent;
|
||||
}
|
||||
}
|
||||
private Object mLock = new Object();
|
||||
|
||||
final Context mContext;
|
||||
final LocationManager mLocationManager;
|
||||
final PowerManager.WakeLock mWakeLock;
|
||||
final Looper mLooper; // looper thread to take location updates on
|
||||
|
||||
// access to members below is synchronized on this
|
||||
Location mLastLocation;
|
||||
List<GeofenceWrapper> mFences = new LinkedList<GeofenceWrapper>();
|
||||
// access to members below is synchronized on mLock
|
||||
private Location mLastLocation;
|
||||
private List<GeofenceState> mFences = new LinkedList<GeofenceState>();
|
||||
|
||||
public GeofenceManager(Context context) {
|
||||
mContext = context;
|
||||
@@ -73,82 +62,98 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
|
||||
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
|
||||
mLooper = Looper.myLooper();
|
||||
mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 0, 0, this);
|
||||
|
||||
LocationRequest request = new LocationRequest()
|
||||
.setQuality(LocationRequest.POWER_NONE)
|
||||
.setFastestInterval(0);
|
||||
mLocationManager.requestLocationUpdates(request, this, Looper.myLooper());
|
||||
}
|
||||
|
||||
public void addFence(double latitude, double longitude, float radius, long expiration,
|
||||
PendingIntent intent, int uid, String packageName) {
|
||||
long expiry = SystemClock.elapsedRealtime() + expiration;
|
||||
if (expiration < 0) {
|
||||
expiry = Long.MAX_VALUE;
|
||||
}
|
||||
Geofence fence = new Geofence(latitude, longitude, radius, mLastLocation);
|
||||
GeofenceWrapper fenceWrapper = new GeofenceWrapper(fence, expiry, packageName, intent);
|
||||
public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent, int uid,
|
||||
String packageName) {
|
||||
GeofenceState state = new GeofenceState(geofence, mLastLocation,
|
||||
request.getExpireAt(), packageName, intent);
|
||||
|
||||
synchronized (this) {
|
||||
mFences.add(fenceWrapper);
|
||||
updateProviderRequirements();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFence(PendingIntent intent) {
|
||||
synchronized (this) {
|
||||
Iterator<GeofenceWrapper> iter = mFences.iterator();
|
||||
while (iter.hasNext()) {
|
||||
GeofenceWrapper fenceWrapper = iter.next();
|
||||
if (fenceWrapper.intent.equals(intent)) {
|
||||
iter.remove();
|
||||
synchronized (mLock) {
|
||||
// first make sure it doesn't already exist
|
||||
for (int i = mFences.size() - 1; i >= 0; i--) {
|
||||
GeofenceState w = mFences.get(i);
|
||||
if (geofence.equals(w.mFence) && intent.equals(w.mIntent)) {
|
||||
// already exists, remove the old one
|
||||
mFences.remove(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
updateProviderRequirements();
|
||||
mFences.add(state);
|
||||
updateProviderRequirementsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFence(Geofence fence, PendingIntent intent) {
|
||||
synchronized (mLock) {
|
||||
Iterator<GeofenceState> iter = mFences.iterator();
|
||||
while (iter.hasNext()) {
|
||||
GeofenceState state = iter.next();
|
||||
if (state.mIntent.equals(intent)) {
|
||||
|
||||
if (fence == null) {
|
||||
// alwaus remove
|
||||
iter.remove();
|
||||
} else {
|
||||
// just remove matching fences
|
||||
if (fence.equals(state.mFence)) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
updateProviderRequirementsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFence(String packageName) {
|
||||
synchronized (this) {
|
||||
Iterator<GeofenceWrapper> iter = mFences.iterator();
|
||||
synchronized (mLock) {
|
||||
Iterator<GeofenceState> iter = mFences.iterator();
|
||||
while (iter.hasNext()) {
|
||||
GeofenceWrapper fenceWrapper = iter.next();
|
||||
if (fenceWrapper.packageName.equals(packageName)) {
|
||||
GeofenceState state = iter.next();
|
||||
if (state.mPackageName.equals(packageName)) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
updateProviderRequirements();
|
||||
updateProviderRequirementsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
void removeExpiredFences() {
|
||||
synchronized (this) {
|
||||
long time = SystemClock.elapsedRealtime();
|
||||
Iterator<GeofenceWrapper> iter = mFences.iterator();
|
||||
while (iter.hasNext()) {
|
||||
GeofenceWrapper fenceWrapper = iter.next();
|
||||
if (fenceWrapper.expiry < time) {
|
||||
iter.remove();
|
||||
}
|
||||
private void removeExpiredFencesLocked() {
|
||||
long time = SystemClock.elapsedRealtime();
|
||||
Iterator<GeofenceState> iter = mFences.iterator();
|
||||
while (iter.hasNext()) {
|
||||
GeofenceState state = iter.next();
|
||||
if (state.mExpireAt < time) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processLocation(Location location) {
|
||||
private void processLocation(Location location) {
|
||||
List<PendingIntent> enterIntents = new LinkedList<PendingIntent>();
|
||||
List<PendingIntent> exitIntents = new LinkedList<PendingIntent>();
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (mLock) {
|
||||
mLastLocation = location;
|
||||
|
||||
removeExpiredFences();
|
||||
removeExpiredFencesLocked();
|
||||
|
||||
for (GeofenceWrapper fenceWrapper : mFences) {
|
||||
int event = fenceWrapper.fence.processLocation(location);
|
||||
if ((event & Geofence.FLAG_ENTER) != 0) {
|
||||
enterIntents.add(fenceWrapper.intent);
|
||||
for (GeofenceState state : mFences) {
|
||||
int event = state.processLocation(location);
|
||||
if ((event & GeofenceState.FLAG_ENTER) != 0) {
|
||||
enterIntents.add(state.mIntent);
|
||||
}
|
||||
if ((event & Geofence.FLAG_EXIT) != 0) {
|
||||
exitIntents.add(fenceWrapper.intent);
|
||||
if ((event & GeofenceState.FLAG_EXIT) != 0) {
|
||||
exitIntents.add(state.mIntent);
|
||||
}
|
||||
}
|
||||
updateProviderRequirements();
|
||||
updateProviderRequirementsLocked();
|
||||
}
|
||||
|
||||
// release lock before sending intents
|
||||
@@ -160,52 +165,50 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
|
||||
}
|
||||
}
|
||||
|
||||
void sendIntentEnter(PendingIntent pendingIntent) {
|
||||
private void sendIntentEnter(PendingIntent pendingIntent) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
|
||||
sendIntent(pendingIntent, intent);
|
||||
}
|
||||
|
||||
void sendIntentExit(PendingIntent pendingIntent) {
|
||||
private void sendIntentExit(PendingIntent pendingIntent) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
|
||||
sendIntent(pendingIntent, intent);
|
||||
}
|
||||
|
||||
void sendIntent(PendingIntent pendingIntent, Intent intent) {
|
||||
private void sendIntent(PendingIntent pendingIntent, Intent intent) {
|
||||
try {
|
||||
mWakeLock.acquire();
|
||||
pendingIntent.send(mContext, 0, intent, this, null, permission.ACCESS_FINE_LOCATION);
|
||||
} catch (PendingIntent.CanceledException e) {
|
||||
removeFence(pendingIntent);
|
||||
removeFence(null, pendingIntent);
|
||||
mWakeLock.release();
|
||||
}
|
||||
}
|
||||
|
||||
void updateProviderRequirements() {
|
||||
synchronized (this) {
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
for (GeofenceWrapper alert : mFences) {
|
||||
if (alert.fence.getDistance() < minDistance) {
|
||||
minDistance = alert.fence.getDistance();
|
||||
}
|
||||
private void updateProviderRequirementsLocked() {
|
||||
double minDistance = Double.MAX_VALUE;
|
||||
for (GeofenceState state : mFences) {
|
||||
if (state.getDistance() < minDistance) {
|
||||
minDistance = state.getDistance();
|
||||
}
|
||||
}
|
||||
|
||||
if (minDistance == Double.MAX_VALUE) {
|
||||
disableLocation();
|
||||
} else {
|
||||
int intervalMs = (int)(minDistance * 1000) / MAX_SPEED_M_S;
|
||||
setLocationInterval(intervalMs);
|
||||
}
|
||||
if (minDistance == Double.MAX_VALUE) {
|
||||
disableLocationLocked();
|
||||
} else {
|
||||
int intervalMs = (int)(minDistance * 1000) / MAX_SPEED_M_S;
|
||||
requestLocationLocked(intervalMs);
|
||||
}
|
||||
}
|
||||
|
||||
void setLocationInterval(int intervalMs) {
|
||||
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, intervalMs, 0, this,
|
||||
private void requestLocationLocked(int intervalMs) {
|
||||
mLocationManager.requestLocationUpdates(new LocationRequest().setInterval(intervalMs), this,
|
||||
mLooper);
|
||||
}
|
||||
|
||||
void disableLocation() {
|
||||
private void disableLocationLocked() {
|
||||
mLocationManager.removeUpdates(this);
|
||||
}
|
||||
|
||||
@@ -231,11 +234,12 @@ public class GeofenceManager implements LocationListener, PendingIntent.OnFinish
|
||||
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.println(" Geofences:");
|
||||
for (GeofenceWrapper fenceWrapper : mFences) {
|
||||
|
||||
for (GeofenceState state : mFences) {
|
||||
pw.append(" ");
|
||||
pw.append(fenceWrapper.packageName);
|
||||
pw.append(state.mPackageName);
|
||||
pw.append(" ");
|
||||
pw.append(fenceWrapper.fence.toString());
|
||||
pw.append(state.mFence.toString());
|
||||
pw.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,37 +17,42 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.location.Geofence;
|
||||
import android.location.Location;
|
||||
|
||||
/**
|
||||
* Represents a simple circular GeoFence.
|
||||
* Represents state associated with a geofence
|
||||
*/
|
||||
public class Geofence {
|
||||
public class GeofenceState {
|
||||
public final static int FLAG_ENTER = 0x01;
|
||||
public final static int FLAG_EXIT = 0x02;
|
||||
|
||||
static final int STATE_UNKNOWN = 0;
|
||||
static final int STATE_INSIDE = 1;
|
||||
static final int STATE_OUTSIDE = 2;
|
||||
private static final int STATE_UNKNOWN = 0;
|
||||
private static final int STATE_INSIDE = 1;
|
||||
private static final int STATE_OUTSIDE = 2;
|
||||
|
||||
final double mLatitude;
|
||||
final double mLongitude;
|
||||
final float mRadius;
|
||||
final Location mLocation;
|
||||
public final Geofence mFence;
|
||||
private final Location mLocation;
|
||||
public final long mExpireAt;
|
||||
public final String mPackageName;
|
||||
public final PendingIntent mIntent;
|
||||
|
||||
int mState; // current state
|
||||
double mDistance; // current distance to center of fence
|
||||
|
||||
public Geofence(double latitude, double longitude, float radius, Location prevLocation) {
|
||||
public GeofenceState(Geofence fence, Location prevLocation, long expireAt,
|
||||
String packageName, PendingIntent intent) {
|
||||
mState = STATE_UNKNOWN;
|
||||
|
||||
mLatitude = latitude;
|
||||
mLongitude = longitude;
|
||||
mRadius = radius;
|
||||
mFence = fence;
|
||||
mExpireAt = expireAt;
|
||||
mPackageName = packageName;
|
||||
mIntent = intent;
|
||||
|
||||
mLocation = new Location("");
|
||||
mLocation.setLatitude(latitude);
|
||||
mLocation.setLongitude(longitude);
|
||||
mLocation.setLatitude(fence.getLatitude());
|
||||
mLocation.setLongitude(fence.getLongitude());
|
||||
|
||||
if (prevLocation != null) {
|
||||
processLocation(prevLocation);
|
||||
@@ -63,7 +68,7 @@ public class Geofence {
|
||||
|
||||
int prevState = mState;
|
||||
//TODO: inside/outside detection could be made more rigorous
|
||||
boolean inside = mDistance <= Math.max(mRadius, location.getAccuracy());
|
||||
boolean inside = mDistance <= Math.max(mFence.getRadius(), location.getAccuracy());
|
||||
if (inside) {
|
||||
mState = STATE_INSIDE;
|
||||
} else {
|
||||
@@ -94,7 +99,6 @@ public class Geofence {
|
||||
default:
|
||||
state = "?";
|
||||
}
|
||||
return String.format("(%.4f, %.4f r=%.0f d=%.0f %s)", mLatitude, mLongitude, mRadius,
|
||||
mDistance, state);
|
||||
return String.format("%s d=%.0f %s", mFence.toString(), mDistance, state);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import android.location.IGpsStatusProvider;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.INetInitiatedListener;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.net.ConnectivityManager;
|
||||
@@ -54,17 +55,19 @@ import android.telephony.TelephonyManager;
|
||||
import android.telephony.gsm.GsmCellLocation;
|
||||
import android.util.Log;
|
||||
import android.util.NtpTrustedTime;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
|
||||
import com.android.internal.telephony.Phone;
|
||||
import com.android.internal.telephony.PhoneConstants;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
@@ -84,6 +87,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
|
||||
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
private static final ProviderProperties PROPERTIES = new ProviderProperties(
|
||||
true, true, false, false, true, true, true,
|
||||
Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
|
||||
|
||||
// these need to match GpsPositionMode enum in gps.h
|
||||
private static final int GPS_POSITION_MODE_STANDALONE = 0;
|
||||
private static final int GPS_POSITION_MODE_MS_BASED = 1;
|
||||
@@ -150,14 +157,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
// Handler messages
|
||||
private static final int CHECK_LOCATION = 1;
|
||||
private static final int ENABLE = 2;
|
||||
private static final int ENABLE_TRACKING = 3;
|
||||
private static final int SET_REQUEST = 3;
|
||||
private static final int UPDATE_NETWORK_STATE = 4;
|
||||
private static final int INJECT_NTP_TIME = 5;
|
||||
private static final int DOWNLOAD_XTRA_DATA = 6;
|
||||
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;
|
||||
|
||||
// Request setid
|
||||
private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
|
||||
@@ -179,6 +185,18 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
|
||||
private static final String PROPERTIES_FILE = "/etc/gps.conf";
|
||||
|
||||
/** simpler wrapper for ProviderRequest + Worksource */
|
||||
private static class GpsRequest {
|
||||
public ProviderRequest request;
|
||||
public WorkSource source;
|
||||
public GpsRequest(ProviderRequest request, WorkSource source) {
|
||||
this.request = request;
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
|
||||
private Object mLock = new Object();
|
||||
|
||||
private int mLocationFlags = LOCATION_INVALID;
|
||||
|
||||
// current status
|
||||
@@ -198,9 +216,16 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
// Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
|
||||
private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
|
||||
|
||||
// true if we are enabled
|
||||
private volatile boolean mEnabled;
|
||||
|
||||
// how often to request NTP time, in milliseconds
|
||||
// current setting 24 hours
|
||||
private static final long NTP_INTERVAL = 24*60*60*1000;
|
||||
// how long to wait if we have a network error in NTP or XTRA downloading
|
||||
// current setting - 5 minutes
|
||||
private static final long RETRY_INTERVAL = 5*60*1000;
|
||||
|
||||
// true if we are enabled, protected by this
|
||||
private boolean mEnabled;
|
||||
|
||||
// true if we have network connectivity
|
||||
private boolean mNetworkAvailable;
|
||||
|
||||
@@ -217,16 +242,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
|
||||
// true if GPS engine is on
|
||||
private boolean mEngineOn;
|
||||
|
||||
|
||||
// requested frequency of fixes, in milliseconds
|
||||
private int mFixInterval = 1000;
|
||||
|
||||
// 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;
|
||||
|
||||
@@ -236,7 +258,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
// for calculating time to first fix
|
||||
private long mFixRequestTime = 0;
|
||||
// time to first fix for most recent session
|
||||
private int mTTFF = 0;
|
||||
private int mTimeToFirstFix = 0;
|
||||
// time we received our last fix
|
||||
private long mLastFixTime;
|
||||
|
||||
@@ -251,7 +273,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
|
||||
private final Context mContext;
|
||||
private final NtpTrustedTime mNtpTime;
|
||||
private final ILocationManager mLocationManager;
|
||||
private final ILocationManager mILocationManager;
|
||||
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
|
||||
private Bundle mLocationExtras = new Bundle();
|
||||
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
|
||||
@@ -267,17 +289,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private int mAGpsDataConnectionState;
|
||||
private int mAGpsDataConnectionIpAddr;
|
||||
private final ConnectivityManager mConnMgr;
|
||||
private final GpsNetInitiatedHandler mNIHandler;
|
||||
private final GpsNetInitiatedHandler mNIHandler;
|
||||
|
||||
// Wakelocks
|
||||
private final static String WAKELOCK_KEY = "GpsLocationProvider";
|
||||
private final PowerManager.WakeLock mWakeLock;
|
||||
// bitfield of pending messages to our Handler
|
||||
// used only for messages that cannot have multiple instances queued
|
||||
private int mPendingMessageBits;
|
||||
// separate counter for ADD_LISTENER and REMOVE_LISTENER messages,
|
||||
// which might have multiple instances queued
|
||||
private int mPendingListenerMessages;
|
||||
|
||||
// Alarms
|
||||
private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
|
||||
@@ -287,22 +303,18 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private final PendingIntent mTimeoutIntent;
|
||||
|
||||
private final IBatteryStats mBatteryStats;
|
||||
private final SparseIntArray mClientUids = new SparseIntArray();
|
||||
|
||||
// how often to request NTP time, in milliseconds
|
||||
// current setting 24 hours
|
||||
private static final long NTP_INTERVAL = 24*60*60*1000;
|
||||
// how long to wait if we have a network error in NTP or XTRA downloading
|
||||
// current setting - 5 minutes
|
||||
private static final long RETRY_INTERVAL = 5*60*1000;
|
||||
// only modified on handler thread
|
||||
private int[] mClientUids = new int[0];
|
||||
|
||||
private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
|
||||
@Override
|
||||
public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
|
||||
if (listener == null) {
|
||||
throw new NullPointerException("listener is null in addGpsStatusListener");
|
||||
}
|
||||
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
IBinder binder = listener.asBinder();
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
@@ -319,12 +331,13 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGpsStatusListener(IGpsStatusListener listener) {
|
||||
if (listener == null) {
|
||||
throw new NullPointerException("listener is null in addGpsStatusListener");
|
||||
}
|
||||
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
IBinder binder = listener.asBinder();
|
||||
Listener l = null;
|
||||
int size = mListeners.size();
|
||||
@@ -353,7 +366,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
|
||||
if (action.equals(ALARM_WAKEUP)) {
|
||||
if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
|
||||
startNavigating(false);
|
||||
startNavigating();
|
||||
} else if (action.equals(ALARM_TIMEOUT)) {
|
||||
if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
|
||||
hibernate();
|
||||
@@ -361,6 +374,22 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
checkSmsSuplInit(intent);
|
||||
} else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
|
||||
checkWapSuplInit(intent);
|
||||
} else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||
int networkState;
|
||||
if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
|
||||
networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
|
||||
} else {
|
||||
networkState = LocationProvider.AVAILABLE;
|
||||
}
|
||||
|
||||
// retrieve NetworkInfo result for this UID
|
||||
NetworkInfo info =
|
||||
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
|
||||
ConnectivityManager connManager = (ConnectivityManager)
|
||||
mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
info = connManager.getNetworkInfo(info.getType());
|
||||
|
||||
updateNetworkState(networkState, info);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -382,10 +411,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
return native_is_supported();
|
||||
}
|
||||
|
||||
public GpsLocationProvider(Context context, ILocationManager locationManager) {
|
||||
public GpsLocationProvider(Context context, ILocationManager ilocationManager) {
|
||||
mContext = context;
|
||||
mNtpTime = NtpTrustedTime.getInstance(context);
|
||||
mLocationManager = locationManager;
|
||||
mILocationManager = ilocationManager;
|
||||
mNIHandler = new GpsNetInitiatedHandler(context);
|
||||
|
||||
mLocation.setExtras(mLocationExtras);
|
||||
@@ -393,7 +422,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
// Create a wake lock
|
||||
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
|
||||
mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
|
||||
mWakeLock.setReferenceCounted(false);
|
||||
mWakeLock.setReferenceCounted(true);
|
||||
|
||||
mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
|
||||
@@ -473,16 +502,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
/**
|
||||
* Returns the name of this provider.
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
return LocationManager.GPS_PROVIDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* data network (e.g., the Internet), false otherwise.
|
||||
*/
|
||||
public boolean requiresNetwork() {
|
||||
return true;
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return PROPERTIES;
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state, NetworkInfo info) {
|
||||
@@ -516,7 +543,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
String apnName = info.getExtraInfo();
|
||||
if (mNetworkAvailable) {
|
||||
if (apnName == null) {
|
||||
/* Assign a dummy value in the case of C2K as otherwise we will have a runtime
|
||||
/* Assign a dummy value in the case of C2K as otherwise we will have a runtime
|
||||
exception in the following call to native_agps_data_conn_open*/
|
||||
apnName = "dummy-apn";
|
||||
}
|
||||
@@ -613,18 +640,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
// try again later
|
||||
// since this is delayed and not urgent we do not hold a wake lock here
|
||||
mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
|
||||
mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA), RETRY_INTERVAL);
|
||||
mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA),
|
||||
RETRY_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called to inform us when another location provider returns a location.
|
||||
* Someday we might use this for network location injection to aid the GPS
|
||||
*/
|
||||
public void updateLocation(Location location) {
|
||||
sendMessage(UPDATE_LOCATION, 0, location);
|
||||
}
|
||||
|
||||
private void handleUpdateLocation(Location location) {
|
||||
if (location.hasAccuracy()) {
|
||||
native_inject_location(location.getLatitude(), location.getLongitude(),
|
||||
@@ -632,108 +652,27 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to a
|
||||
* satellite-based positioning system (e.g., GPS), false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean requiresSatellite() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider requires access to an appropriate
|
||||
* cellular network (e.g., to make use of cell tower IDs), false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean requiresCell() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the use of this provider may result in a
|
||||
* monetary charge to the user, false if use is free. It is up to
|
||||
* each provider to give accurate information.
|
||||
*/
|
||||
public boolean hasMonetaryCost() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide altitude
|
||||
* information, false otherwise. A provider that reports altitude
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public boolean supportsAltitude() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide speed
|
||||
* information, false otherwise. A provider that reports speed
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public boolean supportsSpeed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provider is able to provide bearing
|
||||
* information, false otherwise. A provider that reports bearing
|
||||
* under most circumstances but may occassionally not report it
|
||||
* should return true.
|
||||
*/
|
||||
public boolean supportsBearing() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the power requirement for this provider.
|
||||
*
|
||||
* @return the power requirement for this provider, as one of the
|
||||
* constants Criteria.POWER_REQUIREMENT_*.
|
||||
*/
|
||||
public int getPowerRequirement() {
|
||||
return Criteria.POWER_HIGH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* of the constants Criteria.ACCURACY_*.
|
||||
*/
|
||||
public int getAccuracy() {
|
||||
return Criteria.ACCURACY_FINE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables this provider. When enabled, calls to getStatus()
|
||||
* must be handled. Hardware may be started up
|
||||
* when the provider is enabled.
|
||||
*/
|
||||
@Override
|
||||
public void enable() {
|
||||
synchronized (mHandler) {
|
||||
sendMessage(ENABLE, 1, null);
|
||||
}
|
||||
sendMessage(ENABLE, 1, null);
|
||||
}
|
||||
|
||||
private void handleEnable() {
|
||||
if (DEBUG) Log.d(TAG, "handleEnable");
|
||||
if (mEnabled) return;
|
||||
mEnabled = native_init();
|
||||
|
||||
if (mEnabled) {
|
||||
synchronized (mLock) {
|
||||
if (mEnabled) return;
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
boolean enabled = native_init();
|
||||
|
||||
if (enabled) {
|
||||
mSupportsXtra = native_supports_xtra();
|
||||
if (mSuplServerHost != null) {
|
||||
native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
|
||||
@@ -742,6 +681,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
|
||||
}
|
||||
} else {
|
||||
synchronized (mLock) {
|
||||
mEnabled = false;
|
||||
}
|
||||
Log.w(TAG, "Failed to enable location provider");
|
||||
}
|
||||
}
|
||||
@@ -751,27 +693,35 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
* need not be handled. Hardware may be shut
|
||||
* down while the provider is disabled.
|
||||
*/
|
||||
@Override
|
||||
public void disable() {
|
||||
synchronized (mHandler) {
|
||||
sendMessage(ENABLE, 0, null);
|
||||
}
|
||||
sendMessage(ENABLE, 0, null);
|
||||
}
|
||||
|
||||
private void handleDisable() {
|
||||
if (DEBUG) Log.d(TAG, "handleDisable");
|
||||
if (!mEnabled) return;
|
||||
|
||||
mEnabled = false;
|
||||
synchronized (mLock) {
|
||||
if (!mEnabled) return;
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
stopNavigating();
|
||||
mAlarmManager.cancel(mWakeupIntent);
|
||||
mAlarmManager.cancel(mTimeoutIntent);
|
||||
|
||||
// do this before releasing wakelock
|
||||
native_cleanup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
synchronized (mLock) {
|
||||
return mEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
if (extras != null) {
|
||||
extras.putInt("satellites", mSvCount);
|
||||
@@ -788,93 +738,69 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return mStatusUpdateTime;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) {
|
||||
sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
|
||||
}
|
||||
|
||||
private void handleEnableLocationTracking(boolean enable) {
|
||||
if (enable) {
|
||||
mTTFF = 0;
|
||||
mLastFixTime = 0;
|
||||
startNavigating(false);
|
||||
} else {
|
||||
if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
|
||||
mAlarmManager.cancel(mWakeupIntent);
|
||||
mAlarmManager.cancel(mTimeoutIntent);
|
||||
private void handleSetRequest(ProviderRequest request, WorkSource source) {
|
||||
if (DEBUG) Log.d(TAG, "setRequest " + request);
|
||||
|
||||
|
||||
|
||||
if (request.reportLocation) {
|
||||
// update client uids
|
||||
int[] uids = new int[source.size()];
|
||||
for (int i=0; i < source.size(); i++) {
|
||||
uids[i] = source.get(i);
|
||||
}
|
||||
stopNavigating();
|
||||
}
|
||||
}
|
||||
updateClientUids(uids);
|
||||
|
||||
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;
|
||||
}
|
||||
mFixInterval = (int) request.interval;
|
||||
|
||||
private void handleRequestSingleShot() {
|
||||
mTTFF = 0;
|
||||
mLastFixTime = 0;
|
||||
startNavigating(true);
|
||||
}
|
||||
|
||||
public void setMinTime(long minTime, WorkSource ws) {
|
||||
if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
|
||||
|
||||
if (minTime >= 0) {
|
||||
mFixInterval = (int)minTime;
|
||||
// check for overflow
|
||||
if (mFixInterval != request.interval) {
|
||||
Log.w(TAG, "interval overflow: " + request.interval);
|
||||
mFixInterval = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
// apply request to GPS engine
|
||||
if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
|
||||
// change period
|
||||
if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
|
||||
mFixInterval, 0, 0)) {
|
||||
Log.e(TAG, "set_position_mode failed in setMinTime()");
|
||||
}
|
||||
} else if (!mStarted) {
|
||||
// start GPS
|
||||
startNavigating();
|
||||
}
|
||||
} else {
|
||||
updateClientUids(new int[0]);
|
||||
|
||||
stopNavigating();
|
||||
mAlarmManager.cancel(mWakeupIntent);
|
||||
mAlarmManager.cancel(mTimeoutIntent);
|
||||
}
|
||||
}
|
||||
|
||||
public String getInternalState() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(" mFixInterval=").append(mFixInterval).append("\n");
|
||||
s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
|
||||
if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
|
||||
if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
|
||||
if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
|
||||
if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
|
||||
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
|
||||
s.append(")\n");
|
||||
|
||||
s.append(native_get_internal_state());
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
private final class Listener implements IBinder.DeathRecipient {
|
||||
final IGpsStatusListener mListener;
|
||||
|
||||
int mSensors = 0;
|
||||
|
||||
|
||||
Listener(IGpsStatusListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
if (DEBUG) Log.d(TAG, "GPS status listener died");
|
||||
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
mListeners.remove(this);
|
||||
}
|
||||
if (mListener != null) {
|
||||
@@ -883,64 +809,47 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener(int uid) {
|
||||
synchronized (mWakeLock) {
|
||||
mPendingListenerMessages++;
|
||||
mWakeLock.acquire();
|
||||
Message m = Message.obtain(mHandler, ADD_LISTENER);
|
||||
m.arg1 = uid;
|
||||
mHandler.sendMessage(m);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleAddListener(int uid) {
|
||||
synchronized(mListeners) {
|
||||
if (mClientUids.indexOfKey(uid) >= 0) {
|
||||
// Shouldn't be here -- already have this uid.
|
||||
Log.w(TAG, "Duplicate add listener for uid " + uid);
|
||||
return;
|
||||
private void updateClientUids(int[] uids) {
|
||||
// Find uid's that were not previously tracked
|
||||
for (int uid1 : uids) {
|
||||
boolean newUid = true;
|
||||
for (int uid2 : mClientUids) {
|
||||
if (uid1 == uid2) {
|
||||
newUid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mClientUids.put(uid, 0);
|
||||
if (mNavigating) {
|
||||
if (newUid) {
|
||||
try {
|
||||
mBatteryStats.noteStartGps(uid);
|
||||
mBatteryStats.noteStartGps(uid1);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in addListener");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(int uid) {
|
||||
synchronized (mWakeLock) {
|
||||
mPendingListenerMessages++;
|
||||
mWakeLock.acquire();
|
||||
Message m = Message.obtain(mHandler, REMOVE_LISTENER);
|
||||
m.arg1 = uid;
|
||||
mHandler.sendMessage(m);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleRemoveListener(int uid) {
|
||||
synchronized(mListeners) {
|
||||
if (mClientUids.indexOfKey(uid) < 0) {
|
||||
// Shouldn't be here -- don't have this uid.
|
||||
Log.w(TAG, "Unneeded remove listener for uid " + uid);
|
||||
return;
|
||||
}
|
||||
mClientUids.delete(uid);
|
||||
if (mNavigating) {
|
||||
try {
|
||||
mBatteryStats.noteStopGps(uid);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in removeListener");
|
||||
Log.w(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find uid'd that were tracked but have now disappeared
|
||||
for (int uid1 : mClientUids) {
|
||||
boolean oldUid = true;
|
||||
for (int uid2 : uids) {
|
||||
if (uid1 == uid2) {
|
||||
oldUid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (oldUid) {
|
||||
try {
|
||||
mBatteryStats.noteStopGps(uid1);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
|
||||
|
||||
long identity = Binder.clearCallingIdentity();
|
||||
boolean result = false;
|
||||
|
||||
@@ -957,7 +866,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
} else {
|
||||
Log.w(TAG, "sendExtraCommand: unknown command " + command);
|
||||
}
|
||||
|
||||
|
||||
Binder.restoreCallingIdentity(identity);
|
||||
return result;
|
||||
}
|
||||
@@ -992,18 +901,17 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void startNavigating(boolean singleShot) {
|
||||
private void startNavigating() {
|
||||
if (!mStarted) {
|
||||
if (DEBUG) Log.d(TAG, "startNavigating");
|
||||
mTimeToFirstFix = 0;
|
||||
mLastFixTime = 0;
|
||||
mStarted = true;
|
||||
mSingleShot = singleShot;
|
||||
mPositionMode = GPS_POSITION_MODE_STANDALONE;
|
||||
|
||||
if (Settings.Secure.getInt(mContext.getContentResolver(),
|
||||
Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
|
||||
if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
|
||||
mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
|
||||
} else if (hasCapability(GPS_CAPABILITY_MSB)) {
|
||||
if (hasCapability(GPS_CAPABILITY_MSB)) {
|
||||
mPositionMode = GPS_POSITION_MODE_MS_BASED;
|
||||
}
|
||||
}
|
||||
@@ -1039,9 +947,8 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
if (DEBUG) Log.d(TAG, "stopNavigating");
|
||||
if (mStarted) {
|
||||
mStarted = false;
|
||||
mSingleShot = false;
|
||||
native_stop();
|
||||
mTTFF = 0;
|
||||
mTimeToFirstFix = 0;
|
||||
mLastFixTime = 0;
|
||||
mLocationFlags = LOCATION_INVALID;
|
||||
|
||||
@@ -1056,8 +963,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
mAlarmManager.cancel(mTimeoutIntent);
|
||||
mAlarmManager.cancel(mWakeupIntent);
|
||||
long now = SystemClock.elapsedRealtime();
|
||||
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
SystemClock.elapsedRealtime() + mFixInterval, mWakeupIntent);
|
||||
mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
|
||||
}
|
||||
|
||||
private boolean hasCapability(int capability) {
|
||||
@@ -1105,7 +1011,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
mLocation.setExtras(mLocationExtras);
|
||||
|
||||
try {
|
||||
mLocationManager.reportLocation(mLocation, false);
|
||||
mILocationManager.reportLocation(mLocation, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
}
|
||||
@@ -1113,17 +1019,17 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
|
||||
mLastFixTime = System.currentTimeMillis();
|
||||
// report time to first fix
|
||||
if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
|
||||
mTTFF = (int)(mLastFixTime - mFixRequestTime);
|
||||
if (DEBUG) Log.d(TAG, "TTFF: " + mTTFF);
|
||||
if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
|
||||
mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
|
||||
if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
|
||||
|
||||
// notify status listeners
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener listener = mListeners.get(i);
|
||||
try {
|
||||
listener.mListener.onFirstFix(mTTFF);
|
||||
listener.mListener.onFirstFix(mTimeToFirstFix);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in stopNavigating");
|
||||
mListeners.remove(listener);
|
||||
@@ -1134,9 +1040,6 @@ 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
|
||||
@@ -1164,7 +1067,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private void reportStatus(int status) {
|
||||
if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
|
||||
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
boolean wasNavigating = mNavigating;
|
||||
|
||||
switch (status) {
|
||||
@@ -1202,20 +1105,6 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// update battery stats
|
||||
for (int i=mClientUids.size() - 1; i >= 0; i--) {
|
||||
int uid = mClientUids.keyAt(i);
|
||||
if (mNavigating) {
|
||||
mBatteryStats.noteStartGps(uid);
|
||||
} else {
|
||||
mBatteryStats.noteStopGps(uid);
|
||||
}
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in reportStatus");
|
||||
}
|
||||
|
||||
// send an intent to notify that the GPS has been enabled or disabled.
|
||||
Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
|
||||
intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
|
||||
@@ -1230,15 +1119,15 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
private void reportSvStatus() {
|
||||
|
||||
int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
|
||||
|
||||
synchronized(mListeners) {
|
||||
|
||||
synchronized (mListeners) {
|
||||
int size = mListeners.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
Listener listener = mListeners.get(i);
|
||||
try {
|
||||
listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
|
||||
mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
|
||||
mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
|
||||
listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
|
||||
mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
|
||||
mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "RemoteException in reportSvInfo");
|
||||
mListeners.remove(listener);
|
||||
@@ -1254,7 +1143,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
" almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
|
||||
for (int i = 0; i < svCount; i++) {
|
||||
Log.v(TAG, "sv: " + mSvs[i] +
|
||||
" snr: " + (float)mSnrs[i]/10 +
|
||||
" snr: " + mSnrs[i]/10 +
|
||||
" elev: " + mSvElevations[i] +
|
||||
" azimuth: " + mSvAzimuths[i] +
|
||||
((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
|
||||
@@ -1342,7 +1231,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
* called from native code to report NMEA data received
|
||||
*/
|
||||
private void reportNmea(long timestamp) {
|
||||
synchronized(mListeners) {
|
||||
synchronized (mListeners) {
|
||||
int size = mListeners.size();
|
||||
if (size > 0) {
|
||||
// don't bother creating the String if we have no listeners
|
||||
@@ -1389,19 +1278,18 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
//=============================================================
|
||||
private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
|
||||
// Sends a response for an NI reqeust to HAL.
|
||||
@Override
|
||||
public boolean sendNiResponse(int notificationId, int userResponse)
|
||||
{
|
||||
// TODO Add Permission check
|
||||
|
||||
StringBuilder extrasBuf = new StringBuilder();
|
||||
|
||||
if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
|
||||
", response: " + userResponse);
|
||||
native_send_ni_response(notificationId, userResponse);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public INetInitiatedListener getNetInitiatedListener() {
|
||||
return mNetInitiatedListener;
|
||||
}
|
||||
@@ -1550,16 +1438,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
}
|
||||
|
||||
private void sendMessage(int message, int arg, Object obj) {
|
||||
// hold a wake lock while messages are pending
|
||||
synchronized (mWakeLock) {
|
||||
mPendingMessageBits |= (1 << message);
|
||||
mWakeLock.acquire();
|
||||
mHandler.removeMessages(message);
|
||||
Message m = Message.obtain(mHandler, message);
|
||||
m.arg1 = arg;
|
||||
m.obj = obj;
|
||||
mHandler.sendMessage(m);
|
||||
}
|
||||
// hold a wake lock until this message is delivered
|
||||
mWakeLock.acquire();
|
||||
mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
|
||||
}
|
||||
|
||||
private final class ProviderHandler extends Handler {
|
||||
@@ -1574,11 +1455,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
handleDisable();
|
||||
}
|
||||
break;
|
||||
case ENABLE_TRACKING:
|
||||
handleEnableLocationTracking(msg.arg1 == 1);
|
||||
break;
|
||||
case REQUEST_SINGLE_SHOT:
|
||||
handleRequestSingleShot();
|
||||
case SET_REQUEST:
|
||||
GpsRequest gpsRequest = (GpsRequest) msg.obj;
|
||||
handleSetRequest(gpsRequest.request, gpsRequest.source);
|
||||
break;
|
||||
case UPDATE_NETWORK_STATE:
|
||||
handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
|
||||
@@ -1594,22 +1473,10 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
case UPDATE_LOCATION:
|
||||
handleUpdateLocation((Location)msg.obj);
|
||||
break;
|
||||
case ADD_LISTENER:
|
||||
handleAddListener(msg.arg1);
|
||||
break;
|
||||
case REMOVE_LISTENER:
|
||||
handleRemoveListener(msg.arg1);
|
||||
break;
|
||||
}
|
||||
// release wake lock if no messages are pending
|
||||
synchronized (mWakeLock) {
|
||||
mPendingMessageBits &= ~(1 << message);
|
||||
if (message == ADD_LISTENER || message == REMOVE_LISTENER) {
|
||||
mPendingListenerMessages--;
|
||||
}
|
||||
if (mPendingMessageBits == 0 && mPendingListenerMessages == 0) {
|
||||
mWakeLock.release();
|
||||
}
|
||||
if (msg.arg2 == 1) {
|
||||
// wakelock was taken for this message, release it
|
||||
mWakeLock.release();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1620,17 +1487,39 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
super("GpsLocationProvider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
|
||||
initialize();
|
||||
Looper.prepare();
|
||||
|
||||
LocationManager locManager =
|
||||
(LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
|
||||
mHandler = new ProviderHandler();
|
||||
// signal when we are initialized and ready to go
|
||||
mInitializedLatch.countDown();
|
||||
locManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
|
||||
0, 0, new NetworkLocationListener(), Looper.myLooper());
|
||||
Looper.loop();
|
||||
}
|
||||
}
|
||||
|
||||
private final class NetworkLocationListener implements LocationListener {
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
// this callback happens on mHandler looper
|
||||
if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
|
||||
handleUpdateLocation(location);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) { }
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) { }
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) { }
|
||||
}
|
||||
|
||||
private String getSelectedApn() {
|
||||
Uri uri = Uri.parse("content://telephony/carriers/preferapn");
|
||||
String apn = null;
|
||||
@@ -1650,6 +1539,22 @@ public class GpsLocationProvider implements LocationProviderInterface {
|
||||
return apn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append(" mFixInterval=").append(mFixInterval).append("\n");
|
||||
s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
|
||||
if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
|
||||
if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
|
||||
if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
|
||||
if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
|
||||
if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
|
||||
s.append(")\n");
|
||||
|
||||
s.append(native_get_internal_state());
|
||||
pw.append(s);
|
||||
}
|
||||
|
||||
// for GPS SV statistics
|
||||
private static final int MAX_SVS = 32;
|
||||
private static final int EPHEMERIS_MASK = 0;
|
||||
|
||||
@@ -16,42 +16,33 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.net.NetworkInfo;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.WorkSource;
|
||||
|
||||
/**
|
||||
* Location Manager's interface for location providers.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
public interface LocationProviderInterface {
|
||||
String getName();
|
||||
boolean requiresNetwork();
|
||||
boolean requiresSatellite();
|
||||
boolean requiresCell();
|
||||
boolean hasMonetaryCost();
|
||||
boolean supportsAltitude();
|
||||
boolean supportsSpeed();
|
||||
boolean supportsBearing();
|
||||
int getPowerRequirement();
|
||||
boolean meetsCriteria(Criteria criteria);
|
||||
int getAccuracy();
|
||||
boolean isEnabled();
|
||||
void enable();
|
||||
void disable();
|
||||
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, WorkSource ws);
|
||||
void updateNetworkState(int state, NetworkInfo info);
|
||||
void updateLocation(Location location);
|
||||
boolean sendExtraCommand(String command, Bundle extras);
|
||||
void addListener(int uid);
|
||||
void removeListener(int uid);
|
||||
public String getName();
|
||||
|
||||
public void enable();
|
||||
public void disable();
|
||||
public boolean isEnabled();
|
||||
public void setRequest(ProviderRequest request, WorkSource source);
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args);
|
||||
|
||||
// --- deprecated (but still supported) ---
|
||||
public ProviderProperties getProperties();
|
||||
public int getStatus(Bundle extras);
|
||||
public long getStatusUpdateTime();
|
||||
public boolean sendExtraCommand(String command, Bundle extras);
|
||||
}
|
||||
|
||||
@@ -16,458 +16,272 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.List;
|
||||
|
||||
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;
|
||||
import android.location.LocationProvider;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.location.DummyLocationProvider;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ILocationProvider;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.server.LocationManagerService;
|
||||
import com.android.server.ServiceWatcher;
|
||||
|
||||
/**
|
||||
* A class for proxying location providers implemented as services.
|
||||
*
|
||||
* {@hide}
|
||||
* Proxy for ILocationProvider implementations.
|
||||
*/
|
||||
public class LocationProviderProxy implements LocationProviderInterface {
|
||||
|
||||
private static final String TAG = "LocationProviderProxy";
|
||||
|
||||
public static final String SERVICE_ACTION =
|
||||
"com.android.location.service.NetworkLocationProvider";
|
||||
private static final boolean D = LocationManagerService.D;
|
||||
|
||||
private final Context mContext;
|
||||
private final String mName;
|
||||
private final Intent mIntent;
|
||||
private final Handler mHandler;
|
||||
private final Object mMutex = new Object(); // synchronizes access to non-final members
|
||||
private Connection mServiceConnection; // never null after ctor
|
||||
private final ServiceWatcher mServiceWatcher;
|
||||
|
||||
// cached values set by the location manager
|
||||
private boolean mLocationTracking = false;
|
||||
private Object mLock = new Object();
|
||||
|
||||
// cached values set by the location manager, synchronized on mLock
|
||||
private ProviderProperties mProperties;
|
||||
private boolean mEnabled = false;
|
||||
private long mMinTime = -1;
|
||||
private WorkSource mMinTimeSource = new WorkSource();
|
||||
private int mNetworkState;
|
||||
private NetworkInfo mNetworkInfo;
|
||||
private ProviderRequest mRequest = null;
|
||||
private WorkSource mWorksource = new WorkSource();
|
||||
|
||||
// constructor for proxying location providers implemented in a separate service
|
||||
public LocationProviderProxy(Context context, String name, String packageName,
|
||||
Handler handler) {
|
||||
public static LocationProviderProxy createAndBind(Context context, String name, String action,
|
||||
List<String> initialPackageNames, Handler handler) {
|
||||
LocationProviderProxy proxy = new LocationProviderProxy(context, name, action,
|
||||
initialPackageNames, handler);
|
||||
if (proxy.bind()) {
|
||||
return proxy;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private LocationProviderProxy(Context context, String name, String action,
|
||||
List<String> initialPackageNames, Handler handler) {
|
||||
mContext = context;
|
||||
mName = name;
|
||||
mIntent = new Intent(SERVICE_ACTION);
|
||||
mHandler = handler;
|
||||
reconnect(packageName);
|
||||
mServiceWatcher = new ServiceWatcher(mContext, TAG, action, initialPackageNames,
|
||||
mNewServiceWork, handler);
|
||||
}
|
||||
|
||||
/** Bind to service. Will reconnect if already connected */
|
||||
public void reconnect(String packageName) {
|
||||
synchronized (mMutex) {
|
||||
if (mServiceConnection != null) {
|
||||
mContext.unbindService(mServiceConnection);
|
||||
}
|
||||
mServiceConnection = new Connection();
|
||||
mIntent.setPackage(packageName);
|
||||
mContext.bindService(mIntent, mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND |
|
||||
Context.BIND_ALLOW_OOM_MANAGEMENT);
|
||||
}
|
||||
private boolean bind () {
|
||||
return mServiceWatcher.start();
|
||||
}
|
||||
|
||||
private class Connection implements ServiceConnection, Runnable {
|
||||
private ILocationProvider getService() {
|
||||
return ILocationProvider.Stub.asInterface(mServiceWatcher.getBinder());
|
||||
}
|
||||
|
||||
private ILocationProvider mProvider;
|
||||
|
||||
// for caching requiresNetwork, requiresSatellite, etc.
|
||||
private DummyLocationProvider mCachedAttributes; // synchronized by mMutex
|
||||
|
||||
public void onServiceConnected(ComponentName className, IBinder service) {
|
||||
synchronized (this) {
|
||||
mProvider = ILocationProvider.Stub.asInterface(service);
|
||||
if (mProvider != null) {
|
||||
mHandler.post(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
synchronized (this) {
|
||||
mProvider = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized ILocationProvider getProvider() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
public synchronized DummyLocationProvider getCachedAttributes() {
|
||||
return mCachedAttributes;
|
||||
}
|
||||
public String getConnectedPackageName() {
|
||||
return mServiceWatcher.getBestPackageName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Work to apply current state to a newly connected provider.
|
||||
* Remember we can switch the service that implements a providers
|
||||
* at run-time, so need to apply current state.
|
||||
*/
|
||||
private Runnable mNewServiceWork = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
synchronized (mMutex) {
|
||||
if (mServiceConnection != this) {
|
||||
// This ServiceConnection no longer the one we want to bind to.
|
||||
return;
|
||||
}
|
||||
ILocationProvider provider = getProvider();
|
||||
if (provider == null) {
|
||||
return;
|
||||
if (D) Log.d(TAG, "applying state to connected service");
|
||||
|
||||
boolean enabled;
|
||||
ProviderProperties properties = null;
|
||||
ProviderRequest request;
|
||||
WorkSource source;
|
||||
ILocationProvider service;
|
||||
synchronized (mLock) {
|
||||
enabled = mEnabled;
|
||||
request = mRequest;
|
||||
source = mWorksource;
|
||||
service = getService();
|
||||
}
|
||||
|
||||
if (service == null) return;
|
||||
|
||||
try {
|
||||
// load properties from provider
|
||||
properties = service.getProperties();
|
||||
if (properties == null) {
|
||||
Log.e(TAG, mServiceWatcher.getBestPackageName() +
|
||||
" has invalid locatino provider properties");
|
||||
}
|
||||
|
||||
// resend previous values from the location manager if the service has restarted
|
||||
try {
|
||||
if (mEnabled) {
|
||||
provider.enable();
|
||||
// apply current state to new service
|
||||
if (enabled) {
|
||||
service.enable();
|
||||
if (request != null) {
|
||||
service.setRequest(request, source);
|
||||
}
|
||||
if (mLocationTracking) {
|
||||
provider.enableLocationTracking(true);
|
||||
}
|
||||
if (mMinTime >= 0) {
|
||||
provider.setMinTime(mMinTime, mMinTimeSource);
|
||||
}
|
||||
if (mNetworkInfo != null) {
|
||||
provider.updateNetworkState(mNetworkState, mNetworkInfo);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
|
||||
// init cache of parameters
|
||||
if (mCachedAttributes == null) {
|
||||
try {
|
||||
mCachedAttributes = new DummyLocationProvider(mName, null);
|
||||
mCachedAttributes.setRequiresNetwork(provider.requiresNetwork());
|
||||
mCachedAttributes.setRequiresSatellite(provider.requiresSatellite());
|
||||
mCachedAttributes.setRequiresCell(provider.requiresCell());
|
||||
mCachedAttributes.setHasMonetaryCost(provider.hasMonetaryCost());
|
||||
mCachedAttributes.setSupportsAltitude(provider.supportsAltitude());
|
||||
mCachedAttributes.setSupportsSpeed(provider.supportsSpeed());
|
||||
mCachedAttributes.setSupportsBearing(provider.supportsBearing());
|
||||
mCachedAttributes.setPowerRequirement(provider.getPowerRequirement());
|
||||
mCachedAttributes.setAccuracy(provider.getAccuracy());
|
||||
} catch (RemoteException e) {
|
||||
mCachedAttributes = null;
|
||||
}
|
||||
}
|
||||
synchronized (mLock) {
|
||||
mProperties = properties;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
private DummyLocationProvider getCachedAttributes() {
|
||||
synchronized (mMutex) {
|
||||
return mServiceConnection.getCachedAttributes();
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
synchronized (mLock) {
|
||||
return mProperties;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean requiresNetwork() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.requiresNetwork();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean requiresSatellite() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.requiresSatellite();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean requiresCell() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.requiresCell();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasMonetaryCost() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.hasMonetaryCost();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsAltitude() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.supportsAltitude();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsSpeed() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.supportsSpeed();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean supportsBearing() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.supportsBearing();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPowerRequirement() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.getPowerRequirement();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int getAccuracy() {
|
||||
DummyLocationProvider cachedAttributes = getCachedAttributes();
|
||||
if (cachedAttributes != null) {
|
||||
return cachedAttributes.getAccuracy();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean meetsCriteria(Criteria criteria) {
|
||||
synchronized (mMutex) {
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
synchronized (mMutex) {
|
||||
synchronized (mLock) {
|
||||
mEnabled = true;
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.enable();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return;
|
||||
|
||||
try {
|
||||
service.enable();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
synchronized (mMutex) {
|
||||
synchronized (mLock) {
|
||||
mEnabled = false;
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.disable();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return;
|
||||
|
||||
try {
|
||||
service.disable();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
synchronized (mMutex) {
|
||||
synchronized (mLock) {
|
||||
return mEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) {
|
||||
synchronized (mLock) {
|
||||
mRequest = request;
|
||||
mWorksource = source;
|
||||
}
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return;
|
||||
|
||||
try {
|
||||
service.setRequest(request, source);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.append("REMOTE SERVICE");
|
||||
pw.append(" name=").append(mName);
|
||||
pw.append(" pkg=").append(mServiceWatcher.getBestPackageName());
|
||||
pw.append(" version=").append("" + mServiceWatcher.getBestVersion());
|
||||
pw.append('\n');
|
||||
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) {
|
||||
pw.println("service down (null)");
|
||||
return;
|
||||
}
|
||||
pw.flush();
|
||||
|
||||
try {
|
||||
service.asBinder().dump(fd, args);
|
||||
} catch (RemoteException e) {
|
||||
pw.println("service down (RemoteException)");
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
pw.println("service down (Exception)");
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
ILocationProvider provider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return LocationProvider.TEMPORARILY_UNAVAILABLE;
|
||||
|
||||
try {
|
||||
return service.getStatus(extras);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.getStatus(extras);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return LocationProvider.TEMPORARILY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
ILocationProvider provider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.getStatusUpdateTime();
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return 0;
|
||||
|
||||
try {
|
||||
return service.getStatusUpdateTime();
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String getInternalState() {
|
||||
ILocationProvider provider;
|
||||
synchronized (mMutex) {
|
||||
provider = mServiceConnection.getProvider();
|
||||
}
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.getInternalState();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "getInternalState failed", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isLocationTracking() {
|
||||
synchronized (mMutex) {
|
||||
return mLocationTracking;
|
||||
}
|
||||
}
|
||||
|
||||
public void enableLocationTracking(boolean enable) {
|
||||
synchronized (mMutex) {
|
||||
mLocationTracking = enable;
|
||||
if (!enable) {
|
||||
mMinTime = -1;
|
||||
mMinTimeSource.clear();
|
||||
}
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.enableLocationTracking(enable);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean requestSingleShotFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getMinTime() {
|
||||
synchronized (mMutex) {
|
||||
return mMinTime;
|
||||
}
|
||||
}
|
||||
|
||||
public void setMinTime(long minTime, WorkSource ws) {
|
||||
synchronized (mMutex) {
|
||||
mMinTime = minTime;
|
||||
mMinTimeSource.set(ws);
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.setMinTime(minTime, ws);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state, NetworkInfo info) {
|
||||
synchronized (mMutex) {
|
||||
mNetworkState = state;
|
||||
mNetworkInfo = info;
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.updateNetworkState(state, info);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateLocation(Location location) {
|
||||
synchronized (mMutex) {
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.updateLocation(location);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
synchronized (mMutex) {
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
return provider.sendExtraCommand(command, extras);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
ILocationProvider service = getService();
|
||||
if (service == null) return false;
|
||||
|
||||
try {
|
||||
return service.sendExtraCommand(command, extras);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (Exception e) {
|
||||
// never let remote service crash system server
|
||||
Log.e(TAG, "Exception from " + mServiceWatcher.getBestPackageName(), e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addListener(int uid) {
|
||||
synchronized (mMutex) {
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.addListener(uid);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener(int uid) {
|
||||
synchronized (mMutex) {
|
||||
ILocationProvider provider = mServiceConnection.getProvider();
|
||||
if (provider != null) {
|
||||
try {
|
||||
provider.removeListener(uid);
|
||||
} catch (RemoteException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,15 +20,19 @@ import android.location.Criteria;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationProvider;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
import android.util.PrintWriterPrinter;
|
||||
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
/**
|
||||
* A mock location provider used by LocationManagerService to implement test providers.
|
||||
*
|
||||
@@ -36,60 +40,56 @@ import java.io.PrintWriter;
|
||||
*/
|
||||
public class MockProvider implements LocationProviderInterface {
|
||||
private final String mName;
|
||||
private final ProviderProperties mProperties;
|
||||
private final ILocationManager mLocationManager;
|
||||
private final boolean mRequiresNetwork;
|
||||
private final boolean mRequiresSatellite;
|
||||
private final boolean mRequiresCell;
|
||||
private final boolean mHasMonetaryCost;
|
||||
private final boolean mSupportsAltitude;
|
||||
private final boolean mSupportsSpeed;
|
||||
private final boolean mSupportsBearing;
|
||||
private final int mPowerRequirement;
|
||||
private final int mAccuracy;
|
||||
|
||||
private final Location mLocation;
|
||||
private final Bundle mExtras = new Bundle();
|
||||
|
||||
private int mStatus;
|
||||
private long mStatusUpdateTime;
|
||||
private final Bundle mExtras = new Bundle();
|
||||
private boolean mHasLocation;
|
||||
private boolean mHasStatus;
|
||||
private boolean mEnabled;
|
||||
|
||||
private static final String TAG = "MockProvider";
|
||||
|
||||
public MockProvider(String name, ILocationManager locationManager,
|
||||
boolean requiresNetwork, boolean requiresSatellite,
|
||||
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
|
||||
boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
|
||||
public MockProvider(String name, ILocationManager locationManager,
|
||||
ProviderProperties properties) {
|
||||
if (properties == null) throw new NullPointerException("properties is null");
|
||||
|
||||
mName = name;
|
||||
mLocationManager = locationManager;
|
||||
mRequiresNetwork = requiresNetwork;
|
||||
mRequiresSatellite = requiresSatellite;
|
||||
mRequiresCell = requiresCell;
|
||||
mHasMonetaryCost = hasMonetaryCost;
|
||||
mSupportsAltitude = supportsAltitude;
|
||||
mSupportsBearing = supportsBearing;
|
||||
mSupportsSpeed = supportsSpeed;
|
||||
mPowerRequirement = powerRequirement;
|
||||
mAccuracy = accuracy;
|
||||
mProperties = properties;
|
||||
mLocation = new Location(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return mProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
mEnabled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
mEnabled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
if (mHasStatus) {
|
||||
extras.clear();
|
||||
@@ -100,75 +100,20 @@ public class MockProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return mStatusUpdateTime;
|
||||
}
|
||||
|
||||
public int getAccuracy() {
|
||||
return mAccuracy;
|
||||
}
|
||||
|
||||
public int getPowerRequirement() {
|
||||
return mPowerRequirement;
|
||||
}
|
||||
|
||||
public boolean hasMonetaryCost() {
|
||||
return mHasMonetaryCost;
|
||||
}
|
||||
|
||||
public boolean requiresCell() {
|
||||
return mRequiresCell;
|
||||
}
|
||||
|
||||
public boolean requiresNetwork() {
|
||||
return mRequiresNetwork;
|
||||
}
|
||||
|
||||
public boolean requiresSatellite() {
|
||||
return mRequiresSatellite;
|
||||
}
|
||||
|
||||
public boolean supportsAltitude() {
|
||||
return mSupportsAltitude;
|
||||
}
|
||||
|
||||
public boolean supportsBearing() {
|
||||
return mSupportsBearing;
|
||||
}
|
||||
|
||||
public boolean supportsSpeed() {
|
||||
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;
|
||||
try {
|
||||
mLocationManager.reportLocation(mLocation, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
if (mEnabled) {
|
||||
try {
|
||||
mLocationManager.reportLocation(mLocation, false);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "RemoteException calling reportLocation");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,34 +136,9 @@ public class MockProvider implements LocationProviderInterface {
|
||||
mStatusUpdateTime = 0;
|
||||
}
|
||||
|
||||
public String getInternalState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void enableLocationTracking(boolean enable) {
|
||||
}
|
||||
|
||||
public boolean requestSingleShotFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setMinTime(long minTime, WorkSource ws) {
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state, NetworkInfo info) {
|
||||
}
|
||||
|
||||
public void updateLocation(Location location) {
|
||||
}
|
||||
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addListener(int uid) {
|
||||
}
|
||||
|
||||
public void removeListener(int uid) {
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
dump(pw, "");
|
||||
}
|
||||
|
||||
public void dump(PrintWriter pw, String prefix) {
|
||||
@@ -231,4 +151,12 @@ public class MockProvider implements LocationProviderInterface {
|
||||
pw.println(prefix + "mStatusUpdateTime=" + mStatusUpdateTime);
|
||||
pw.println(prefix + "mExtras=" + mExtras);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) { }
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,17 +16,23 @@
|
||||
|
||||
package com.android.server.location;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
|
||||
import android.location.Criteria;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.location.LocationProvider;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.WorkSource;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
/**
|
||||
* A passive location provider reports locations received from other providers
|
||||
* for clients that want to listen passively without actually triggering
|
||||
@@ -35,103 +41,63 @@ import android.util.Log;
|
||||
* {@hide}
|
||||
*/
|
||||
public class PassiveProvider implements LocationProviderInterface {
|
||||
|
||||
private static final String TAG = "PassiveProvider";
|
||||
|
||||
private static final ProviderProperties PROPERTIES = new ProviderProperties(
|
||||
false, false, false, false, false, false, false,
|
||||
Criteria.POWER_LOW, Criteria.ACCURACY_COARSE);
|
||||
|
||||
private final ILocationManager mLocationManager;
|
||||
private boolean mTracking;
|
||||
private boolean mReportLocation;
|
||||
|
||||
public PassiveProvider(ILocationManager locationManager) {
|
||||
mLocationManager = locationManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return LocationManager.PASSIVE_PROVIDER;
|
||||
}
|
||||
|
||||
public boolean requiresNetwork() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean requiresSatellite() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean requiresCell() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasMonetaryCost() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsAltitude() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsSpeed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsBearing() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getPowerRequirement() {
|
||||
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;
|
||||
@Override
|
||||
public ProviderProperties getProperties() {
|
||||
return PROPERTIES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disable() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus(Bundle extras) {
|
||||
if (mTracking) {
|
||||
if (mReportLocation) {
|
||||
return LocationProvider.AVAILABLE;
|
||||
} else {
|
||||
return LocationProvider.TEMPORARILY_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getStatusUpdateTime() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public String getInternalState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void enableLocationTracking(boolean enable) {
|
||||
mTracking = enable;
|
||||
}
|
||||
|
||||
public boolean requestSingleShotFix() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setMinTime(long minTime, WorkSource ws) {
|
||||
}
|
||||
|
||||
public void updateNetworkState(int state, NetworkInfo info) {
|
||||
@Override
|
||||
public void setRequest(ProviderRequest request, WorkSource source) {
|
||||
mReportLocation = request.reportLocation;
|
||||
}
|
||||
|
||||
public void updateLocation(Location location) {
|
||||
if (mTracking) {
|
||||
if (mReportLocation) {
|
||||
try {
|
||||
// pass the location back to the location manager
|
||||
mLocationManager.reportLocation(location, true);
|
||||
@@ -141,13 +107,13 @@ public class PassiveProvider implements LocationProviderInterface {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String command, Bundle extras) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addListener(int uid) {
|
||||
}
|
||||
|
||||
public void removeListener(int uid) {
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("mReportLocaiton=" + mReportLocation);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user