summaryrefslogtreecommitdiffstats
path: root/location/java
diff options
context:
space:
mode:
Diffstat (limited to 'location/java')
-rw-r--r--location/java/android/location/Geocoder.java17
-rw-r--r--location/java/android/location/GeocoderParams.aidl19
-rw-r--r--location/java/android/location/GeocoderParams.java94
-rw-r--r--location/java/android/location/IGeocodeProvider.aidl5
-rw-r--r--location/java/android/location/ILocationManager.aidl16
-rw-r--r--location/java/android/location/ILocationProvider.aidl4
-rw-r--r--location/java/android/location/LocationManager.java88
-rw-r--r--location/java/android/location/LocationProvider.java4
-rw-r--r--location/java/android/location/LocationProviderInterface.java52
-rw-r--r--location/java/android/location/provider/GeocodeProvider.java83
-rw-r--r--location/java/android/location/provider/LocationProvider.java344
-rw-r--r--location/java/com/android/internal/location/GeocoderProxy.java105
-rwxr-xr-xlocation/java/com/android/internal/location/GpsLocationProvider.java501
-rw-r--r--location/java/com/android/internal/location/GpsXtraDownloader.java3
-rw-r--r--location/java/com/android/internal/location/LocationProviderProxy.java359
-rw-r--r--location/java/com/android/internal/location/MockProvider.java22
-rw-r--r--location/java/com/android/internal/location/NmeaParser.java437
-rw-r--r--location/java/com/android/internal/location/PassiveProvider.java143
18 files changed, 1424 insertions, 872 deletions
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java
index 2ce1273..c325b1b 100644
--- a/location/java/android/location/Geocoder.java
+++ b/location/java/android/location/Geocoder.java
@@ -45,10 +45,7 @@ import java.util.List;
public final class Geocoder {
private static final String TAG = "Geocoder";
- private String mLanguage;
- private String mCountry;
- private String mVariant;
- private String mAppName;
+ private GeocoderParams mParams;
private ILocationManager mService;
/**
@@ -64,11 +61,7 @@ public final class Geocoder {
if (locale == null) {
throw new NullPointerException("locale == null");
}
- mLanguage = locale.getLanguage();
- mCountry = locale.getCountry();
- mVariant = locale.getVariant();
- mAppName = context.getPackageName();
-
+ mParams = new GeocoderParams(context, locale);
IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE);
mService = ILocationManager.Stub.asInterface(b);
}
@@ -119,7 +112,7 @@ public final class Geocoder {
try {
List<Address> results = new ArrayList<Address>();
String ex = mService.getFromLocation(latitude, longitude, maxResults,
- mLanguage, mCountry, mVariant, mAppName, results);
+ mParams, results);
if (ex != null) {
throw new IOException(ex);
} else {
@@ -161,7 +154,7 @@ public final class Geocoder {
try {
List<Address> results = new ArrayList<Address>();
String ex = mService.getFromLocationName(locationName,
- 0, 0, 0, 0, maxResults, mLanguage, mCountry, mVariant, mAppName, results);
+ 0, 0, 0, 0, maxResults, mParams, results);
if (ex != null) {
throw new IOException(ex);
} else {
@@ -234,7 +227,7 @@ public final class Geocoder {
ArrayList<Address> result = new ArrayList<Address>();
String ex = mService.getFromLocationName(locationName,
lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
- maxResults, mLanguage, mCountry, mVariant, mAppName, result);
+ maxResults, mParams, result);
if (ex != null) {
throw new IOException(ex);
} else {
diff --git a/location/java/android/location/GeocoderParams.aidl b/location/java/android/location/GeocoderParams.aidl
new file mode 100644
index 0000000..2484e20
--- /dev/null
+++ b/location/java/android/location/GeocoderParams.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.location;
+
+parcelable GeocoderParams;
diff --git a/location/java/android/location/GeocoderParams.java b/location/java/android/location/GeocoderParams.java
new file mode 100644
index 0000000..174fe3e
--- /dev/null
+++ b/location/java/android/location/GeocoderParams.java
@@ -0,0 +1,94 @@
+/*
+ * 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 android.location;
+
+import android.content.Context;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Locale;
+
+/**
+ * This class contains extra parameters to pass to an IGeocodeProvider
+ * implementation from the Geocoder class. Currently this contains the
+ * language, country and variant information from the Geocoder's locale
+ * as well as the Geocoder client's package name for geocoder server
+ * logging. This information is kept in a separate class to allow for
+ * future expansion of the IGeocodeProvider interface.
+ *
+ * @hide
+ */
+public class GeocoderParams implements Parcelable {
+ private Locale mLocale;
+ private String mPackageName;
+
+ // used only for parcelling
+ private GeocoderParams() {
+ }
+
+ /**
+ * This object is only constructed by the Geocoder class
+ *
+ * @hide
+ */
+ public GeocoderParams(Context context, Locale locale) {
+ mLocale = locale;
+ mPackageName = context.getPackageName();
+ }
+
+ /**
+ * returns the Geocoder's locale
+ */
+ public Locale getLocale() {
+ return mLocale;
+ }
+
+ /**
+ * returns the package name of the Geocoder's client
+ */
+ public String getClientPackage() {
+ return mPackageName;
+ }
+
+ public static final Parcelable.Creator<GeocoderParams> CREATOR =
+ new Parcelable.Creator<GeocoderParams>() {
+ public GeocoderParams createFromParcel(Parcel in) {
+ GeocoderParams gp = new GeocoderParams();
+ String language = in.readString();
+ String country = in.readString();
+ String variant = in.readString();
+ gp.mLocale = new Locale(language, country, variant);
+ gp.mPackageName = in.readString();
+ return gp;
+ }
+
+ public GeocoderParams[] newArray(int size) {
+ return new GeocoderParams[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mLocale.getLanguage());
+ parcel.writeString(mLocale.getCountry());
+ parcel.writeString(mLocale.getVariant());
+ parcel.writeString(mPackageName);
+ }
+}
diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl
index e79e8d2..aaa70c7 100644
--- a/location/java/android/location/IGeocodeProvider.aidl
+++ b/location/java/android/location/IGeocodeProvider.aidl
@@ -17,6 +17,7 @@
package android.location;
import android.location.Address;
+import android.location.GeocoderParams;
/**
* An interface for location providers implementing the Geocoder services.
@@ -26,10 +27,10 @@ import android.location.Address;
interface IGeocodeProvider {
String getFromLocation(double latitude, double longitude, int maxResults,
- String language, String country, String variant, String appName, out List<Address> addrs);
+ in GeocoderParams params, out List<Address> addrs);
String getFromLocationName(String locationName,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
- String language, String country, String variant, String appName, out List<Address> addrs);
+ in GeocoderParams params, out List<Address> addrs);
}
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index b6c59d6..2c0399e 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -18,10 +18,10 @@ package android.location;
import android.app.PendingIntent;
import android.location.Address;
+import android.location.GeocoderParams;
import android.location.IGeocodeProvider;
import android.location.IGpsStatusListener;
import android.location.ILocationListener;
-import android.location.ILocationProvider;
import android.location.Location;
import android.os.Bundle;
@@ -59,15 +59,17 @@ interface ILocationManager
Location getLastKnownLocation(String provider);
- /* used by location providers to tell the location manager when it has a new location */
- void reportLocation(in Location location);
+ // 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);
String getFromLocation(double latitude, double longitude, int maxResults,
- String language, String country, String variant, String appName, out List<Address> addrs);
+ in GeocoderParams params, out List<Address> addrs);
String getFromLocationName(String locationName,
double lowerLeftLatitude, double lowerLeftLongitude,
double upperRightLatitude, double upperRightLongitude, int maxResults,
- String language, String country, String variant, String appName, out List<Address> addrs);
+ in GeocoderParams params, out List<Address> addrs);
void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
@@ -80,10 +82,6 @@ interface ILocationManager
void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime);
void clearTestProviderStatus(String provider);
- /* for installing external Location Providers */
- void installLocationProvider(String name, ILocationProvider provider);
- void installGeocodeProvider(IGeocodeProvider provider);
-
// for NI support
boolean sendNiResponse(int notifId, int userResponse);
}
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 7da16e4..97b283c 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -21,7 +21,7 @@ import android.net.NetworkInfo;
import android.os.Bundle;
/**
- * Binder interface for location providers.
+ * Binder interface for services that implement location providers.
*
* {@hide}
*/
@@ -37,9 +37,9 @@ interface ILocationProvider {
int getAccuracy();
void enable();
void disable();
- boolean isEnabled();
int getStatus(out Bundle extras);
long getStatusUpdateTime();
+ String getInternalState();
void enableLocationTracking(boolean enable);
void setMinTime(long minTime);
void updateNetworkState(int state, in NetworkInfo info);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 94ced22..9e4a16b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -23,7 +23,6 @@ import android.os.Looper;
import android.os.RemoteException;
import android.os.Handler;
import android.os.Message;
-import android.util.Config;
import android.util.Log;
import com.android.internal.location.DummyLocationProvider;
@@ -82,6 +81,19 @@ public class LocationManager {
public static final String GPS_PROVIDER = "gps";
/**
+ * A special location provider for receiving locations without actually initiating
+ * a location fix. This provider can be used to passively receive location updates
+ * when other applications or services request them without actually requesting
+ * the locations yourself. This provider will return locations generated by other
+ * providers. You can query the {@link Location#getProvider()} method to determine
+ * the origin of the location update.
+ *
+ * Requires the permission android.permission.ACCESS_FINE_LOCATION, although if the GPS
+ * is not enabled this provider might only return coarse fixes.
+ */
+ public static final String PASSIVE_PROVIDER = "passive";
+
+ /**
* Key used for the Bundle extra holding a boolean indicating whether
* a proximity alert is entering (true) or exiting (false)..
*/
@@ -206,7 +218,7 @@ public class LocationManager {
* factory Context.getSystemService.
*/
public LocationManager(ILocationManager service) {
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "Constructor: service = " + service);
}
mService = service;
@@ -235,7 +247,7 @@ public class LocationManager {
* @return list of Strings containing names of the providers
*/
public List<String> getAllProviders() {
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "getAllProviders");
}
try {
@@ -305,7 +317,7 @@ public class LocationManager {
List<String> providers = getProviders(enabledOnly);
for (String providerName : providers) {
LocationProvider provider = getProvider(providerName);
- if (provider.meetsCriteria(criteria)) {
+ if (provider != null && provider.meetsCriteria(criteria)) {
if (goodProviders.isEmpty()) {
goodProviders = new ArrayList<String>();
}
@@ -787,7 +799,7 @@ public class LocationManager {
if (listener == null) {
throw new IllegalArgumentException("listener==null");
}
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "removeUpdates: listener = " + listener);
}
try {
@@ -812,7 +824,7 @@ public class LocationManager {
if (intent == null) {
throw new IllegalArgumentException("intent==null");
}
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "removeUpdates: intent = " + intent);
}
try {
@@ -867,7 +879,7 @@ public class LocationManager {
*/
public void addProximityAlert(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "addProximityAlert: latitude = " + latitude +
", longitude = " + longitude + ", radius = " + radius +
", expiration = " + expiration +
@@ -888,7 +900,7 @@ public class LocationManager {
* proximity alerts
*/
public void removeProximityAlert(PendingIntent intent) {
- if (Config.LOGD) {
+ if (false) {
Log.d(TAG, "removeProximityAlert: intent = " + intent);
}
try {
@@ -1354,66 +1366,6 @@ public class LocationManager {
return false;
}
}
-
- /**
- * Installs a location provider.
- *
- * @param name of the location provider
- * @param provider Binder interface for the location provider
- *
- * @return true if the command succeeds.
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- *
- * {@hide}
- */
- public boolean installLocationProvider(String name, ILocationProvider provider) {
- try {
- mService.installLocationProvider(name, provider);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in installLocationProvider: ", e);
- return false;
- }
- }
-
- /**
- * Installs a geocoder server.
- *
- * @param provider Binder interface for the geocoder provider
- *
- * @return true if the command succeeds.
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- *
- * {@hide}
- */
- public boolean installGeocodeProvider(IGeocodeProvider provider) {
- try {
- mService.installGeocodeProvider(provider);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in setGeocodeProvider: ", e);
- return false;
- }
- }
-
- /**
- * Used by location providers to report new locations.
- *
- * @param location new Location to report
- *
- * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
- *
- * {@hide}
- */
- public void reportLocation(Location location) {
- try {
- mService.reportLocation(location);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in reportLocation: ", e);
- }
- }
/**
* Used by NetInitiatedActivity to report user response
diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java
index 3faba58..bb3e2a5 100644
--- a/location/java/android/location/LocationProvider.java
+++ b/location/java/android/location/LocationProvider.java
@@ -71,6 +71,10 @@ public abstract class LocationProvider {
* false otherwise.
*/
public boolean meetsCriteria(Criteria criteria) {
+ // We do not want to match the special passive provider based on criteria.
+ if (LocationManager.PASSIVE_PROVIDER.equals(mName)) {
+ return false;
+ }
if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) &&
(criteria.getAccuracy() < getAccuracy())) {
return false;
diff --git a/location/java/android/location/LocationProviderInterface.java b/location/java/android/location/LocationProviderInterface.java
new file mode 100644
index 0000000..5ffe15c
--- /dev/null
+++ b/location/java/android/location/LocationProviderInterface.java
@@ -0,0 +1,52 @@
+/*
+ * 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 android.location;
+
+import android.location.Location;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+
+/**
+ * Location Manager's interface for location providers.
+ *
+ * {@hide}
+ */
+public interface LocationProviderInterface {
+ String getName();
+ boolean requiresNetwork();
+ boolean requiresSatellite();
+ boolean requiresCell();
+ boolean hasMonetaryCost();
+ boolean supportsAltitude();
+ boolean supportsSpeed();
+ boolean supportsBearing();
+ int getPowerRequirement();
+ int getAccuracy();
+ boolean isEnabled();
+ void enable();
+ void disable();
+ int getStatus(Bundle extras);
+ long getStatusUpdateTime();
+ void enableLocationTracking(boolean enable);
+ String getInternalState();
+ void setMinTime(long minTime);
+ void updateNetworkState(int state, NetworkInfo info);
+ void updateLocation(Location location);
+ boolean sendExtraCommand(String command, Bundle extras);
+ void addListener(int uid);
+ void removeListener(int uid);
+}
diff --git a/location/java/android/location/provider/GeocodeProvider.java b/location/java/android/location/provider/GeocodeProvider.java
new file mode 100644
index 0000000..86376a7
--- /dev/null
+++ b/location/java/android/location/provider/GeocodeProvider.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.location.provider;
+
+import android.os.IBinder;
+
+import android.location.Address;
+import android.location.GeocoderParams;
+import android.location.IGeocodeProvider;
+
+import java.util.List;
+
+/**
+ * An abstract superclass for geocode providers that are implemented
+ * outside of the core android platform.
+ * Geocode providers can be implemented as services and return the result of
+ * {@link GeocodeProvider#getBinder()} in its getBinder() method.
+ *
+ * @hide
+ */
+public abstract class GeocodeProvider {
+
+ private IGeocodeProvider.Stub mProvider = new IGeocodeProvider.Stub() {
+ public String getFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ return GeocodeProvider.this.onGetFromLocation(latitude, longitude, maxResults,
+ params, addrs);
+ }
+
+ public String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ return GeocodeProvider.this.onGetFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ }
+ };
+
+ /**
+ * This method is overridden to implement the
+ * {@link Geocoder#getFromLocation(double, double, int)} method.
+ * Classes implementing this method should not hold a reference to the params parameter.
+ */
+ public abstract String onGetFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs);
+
+ /**
+ * This method is overridden to implement the
+ * {@link Geocoder#getFromLocationName(String, int, double, double, double, double)} method.
+ * Classes implementing this method should not hold a reference to the params parameter.
+ */
+ public abstract String onGetFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs);
+
+ /**
+ * Returns the Binder interface for the geocode provider.
+ * This is intended to be used for the onBind() method of
+ * a service that implements a geocoder service.
+ *
+ * @return the IBinder instance for the provider
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+}
+
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
new file mode 100644
index 0000000..56cfb33
--- /dev/null
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -0,0 +1,344 @@
+/*
+ * 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 android.location.provider;
+
+import android.content.Context;
+import android.net.NetworkInfo;
+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.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 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) {
+ LocationProvider.this.onSetMinTime(minTime);
+ }
+
+ 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);
+ }
+
+ public void removeListener(int uid) {
+ LocationProvider.this.onRemoveListener(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 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 #OUT_OF_SERVICE} is returned if the provider is
+ * out of service, and this is not expected to change in the near
+ * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
+ * the provider is temporarily unavailable but is expected to be
+ * available shortly; and {@link #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.
+ */
+ public abstract void onSetMinTime(long minTime);
+
+ /**
+ * Updates the network state for the given provider. This function must
+ * be overwritten if {@link #requiresNetwork} returns true. The state is
+ * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #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.
+ */
+ public abstract void onAddListener(int uid);
+
+ /**
+ * Notifies the location provider when a client is no longer listening for locations.
+ *
+ * @param uid user ID of the client no longer listening.
+ */
+ public abstract void onRemoveListener(int uid);
+}
+
diff --git a/location/java/com/android/internal/location/GeocoderProxy.java b/location/java/com/android/internal/location/GeocoderProxy.java
new file mode 100644
index 0000000..b06297b
--- /dev/null
+++ b/location/java/com/android/internal/location/GeocoderProxy.java
@@ -0,0 +1,105 @@
+/*
+ * 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.internal.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 java.util.List;
+
+/**
+ * A class for proxying IGeocodeProvider implementations.
+ *
+ * {@hide}
+ */
+public class GeocoderProxy {
+
+ private static final String TAG = "GeocoderProxy";
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private final Connection mServiceConnection = new Connection();
+ private IGeocodeProvider mProvider;
+
+ public GeocoderProxy(Context context, String serviceName) {
+ mContext = context;
+ mIntent = new Intent(serviceName);
+ mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private class Connection implements ServiceConnection {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected " + className);
+ synchronized (this) {
+ mProvider = IGeocodeProvider.Stub.asInterface(service);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected " + className);
+ synchronized (this) {
+ mProvider = null;
+ }
+ }
+ }
+
+ public String getFromLocation(double latitude, double longitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ IGeocodeProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getFromLocation(latitude, longitude, maxResults,
+ params, addrs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getFromLocation failed", e);
+ }
+ }
+ return "Service not Available";
+ }
+
+ public String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ GeocoderParams params, List<Address> addrs) {
+ IGeocodeProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getFromLocationName(locationName, lowerLeftLatitude,
+ lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
+ maxResults, params, addrs);
+ } catch (RemoteException e) {
+ Log.e(TAG, "getFromLocationName failed", e);
+ }
+ }
+ return "Service not Available";
+ }
+}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index ed3fdde..fa53ccf 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -26,22 +26,25 @@ import android.location.Criteria;
import android.location.IGpsStatusListener;
import android.location.IGpsStatusProvider;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.INetInitiatedListener;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.SntpClient;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.PowerManager;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.provider.Settings;
-import android.util.Config;
import android.util.Log;
import android.util.SparseIntArray;
@@ -60,19 +63,20 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;
import java.util.Map.Entry;
+import java.util.concurrent.CountDownLatch;
/**
* A GPS implementation of LocationProvider used by LocationManager.
*
* {@hide}
*/
-public class GpsLocationProvider extends ILocationProvider.Stub {
+public class GpsLocationProvider implements LocationProviderInterface {
private static final String TAG = "GpsLocationProvider";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final boolean VERBOSE = false;
-
+
/**
* Broadcast intent action indicating that the GPS has either been
* enabled or disabled. An intent extra provides this state as a boolean,
@@ -156,6 +160,17 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private static final int AGPS_DATA_CONNECTION_OPENING = 1;
private static final int AGPS_DATA_CONNECTION_OPEN = 2;
+ // 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 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 String PROPERTIES_FILE = "/etc/gps.conf";
private int mLocationFlags = LOCATION_INVALID;
@@ -176,11 +191,16 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private static final int NO_FIX_TIMEOUT = 60;
// true if we are enabled
- private boolean mEnabled;
+ private volatile boolean mEnabled;
// true if we have network connectivity
private boolean mNetworkAvailable;
+ // flags to trigger NTP or XTRA data download when network becomes available
+ // initialized to true so we do NTP and XTRA when the network comes up after booting
+ private boolean mInjectNtpTimePending = true;
+ private boolean mDownloadXtraDataPending = true;
+
// true if GPS is navigating
private boolean mNavigating;
@@ -216,9 +236,15 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
private Bundle mLocationExtras = new Bundle();
private ArrayList<Listener> mListeners = new ArrayList<Listener>();
- private GpsEventThread mEventThread;
- private GpsNetworkThread mNetworkThread;
- private Object mNetworkThreadLock = new Object();
+
+ // GpsLocationProvider's handler thread
+ private final Thread mThread;
+ // Handler for processing events in mThread.
+ private Handler mHandler;
+ // Used to signal when our main thread has initialized everything
+ private final CountDownLatch mInitializedLatch = new CountDownLatch(1);
+ // Thread for receiving events from the native code
+ private Thread mEventThread;
private String mAGpsApn;
private int mAGpsDataConnectionState;
@@ -322,7 +348,9 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
public GpsLocationProvider(Context context, ILocationManager locationManager) {
mContext = context;
mLocationManager = locationManager;
- mNIHandler= new GpsNetInitiatedHandler(context, this);
+ mNIHandler = new GpsNetInitiatedHandler(context, this);
+
+ mLocation.setExtras(mLocationExtras);
// Create a wake lock
PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -332,11 +360,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ALARM_WAKEUP);
- intentFilter.addAction(ALARM_TIMEOUT);
- context.registerReceiver(mBroadcastReciever, intentFilter);
-
mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
// Battery statistics service to be notified when GPS turns on or off
@@ -372,6 +395,33 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
} catch (IOException e) {
Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
}
+
+ // wait until we are fully initialized before returning
+ mThread = new GpsLocationProviderThread();
+ mThread.start();
+ while (true) {
+ try {
+ mInitializedLatch.await();
+ break;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ private void initialize() {
+ // register our receiver on our thread rather than the main thread
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(ALARM_WAKEUP);
+ intentFilter.addAction(ALARM_TIMEOUT);
+ mContext.registerReceiver(mBroadcastReciever, intentFilter);
+ }
+
+ /**
+ * Returns the name of this provider.
+ */
+ public String getName() {
+ return LocationManager.GPS_PROVIDER;
}
/**
@@ -383,9 +433,17 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void updateNetworkState(int state, NetworkInfo info) {
+ mHandler.removeMessages(UPDATE_NETWORK_STATE);
+ Message m = Message.obtain(mHandler, UPDATE_NETWORK_STATE);
+ m.arg1 = state;
+ m.obj = info;
+ mHandler.sendMessage(m);
+ }
+
+ private void handleUpdateNetworkState(int state, NetworkInfo info) {
mNetworkAvailable = (state == LocationProvider.AVAILABLE);
- if (Config.LOGD) {
+ if (DEBUG) {
Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
+ " info: " + info);
}
@@ -406,10 +464,84 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
- if (mNetworkAvailable && mNetworkThread != null && mEnabled) {
- // signal the network thread when the network becomes available
- mNetworkThread.signal();
- }
+ if (mNetworkAvailable) {
+ if (mInjectNtpTimePending) {
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessage(Message.obtain(mHandler, INJECT_NTP_TIME));
+ }
+ if (mDownloadXtraDataPending) {
+ mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+ mHandler.sendMessage(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA));
+ }
+ }
+ }
+
+ private void handleInjectNtpTime() {
+ if (!mNetworkAvailable) {
+ // try again when network is up
+ mInjectNtpTimePending = true;
+ return;
+ }
+ mInjectNtpTimePending = false;
+
+ SntpClient client = new SntpClient();
+ long delay;
+
+ if (client.requestTime(mNtpServer, 10000)) {
+ long time = client.getNtpTime();
+ long timeReference = client.getNtpTimeReference();
+ int certainty = (int)(client.getRoundTripTime()/2);
+ long now = System.currentTimeMillis();
+ long systemTimeOffset = time - now;
+
+ Log.d(TAG, "NTP server returned: "
+ + time + " (" + new Date(time)
+ + ") reference: " + timeReference
+ + " certainty: " + certainty
+ + " system time offset: " + systemTimeOffset);
+
+ // sanity check NTP time and do not use if it is too far from system time
+ if (systemTimeOffset < 0) {
+ systemTimeOffset = -systemTimeOffset;
+ }
+ if (systemTimeOffset < MAX_NTP_SYSTEM_TIME_OFFSET) {
+ native_inject_time(time, timeReference, certainty);
+ } else {
+ Log.e(TAG, "NTP time differs from system time by " + systemTimeOffset
+ + "ms. Ignoring.");
+ }
+ delay = NTP_INTERVAL;
+ } else {
+ if (DEBUG) Log.d(TAG, "requestTime failed");
+ delay = RETRY_INTERVAL;
+ }
+
+ // send delayed message for next NTP injection
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ }
+
+ private void handleDownloadXtraData() {
+ if (!mDownloadXtraDataPending) {
+ // try again when network is up
+ mDownloadXtraDataPending = true;
+ return;
+ }
+ mDownloadXtraDataPending = false;
+
+
+ GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
+ byte[] data = xtraDownloader.downloadXtraData();
+ if (data != null) {
+ if (DEBUG) {
+ Log.d(TAG, "calling native_inject_xtra_data");
+ }
+ native_inject_xtra_data(data, data.length);
+ } else {
+ // try again later
+ mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA), RETRY_INTERVAL);
+ }
}
/**
@@ -417,6 +549,13 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
* Someday we might use this for network location injection to aid the GPS
*/
public void updateLocation(Location location) {
+ mHandler.removeMessages(UPDATE_LOCATION);
+ Message m = Message.obtain(mHandler, UPDATE_LOCATION);
+ m.obj = location;
+ mHandler.sendMessage(m);
+ }
+
+ private void handleUpdateLocation(Location location) {
if (location.hasAccuracy()) {
native_inject_location(location.getLatitude(), location.getLongitude(),
location.getAccuracy());
@@ -505,8 +644,17 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
* must be handled. Hardware may be started up
* when the provider is enabled.
*/
- public synchronized void enable() {
- if (Config.LOGD) Log.d(TAG, "enable");
+ public void enable() {
+ synchronized (mHandler) {
+ mHandler.removeMessages(ENABLE);
+ Message m = Message.obtain(mHandler, ENABLE);
+ m.arg1 = 1;
+ mHandler.sendMessage(m);
+ }
+ }
+
+ private void handleEnable() {
+ if (DEBUG) Log.d(TAG, "handleEnable");
if (mEnabled) return;
mEnabled = native_init();
@@ -521,16 +669,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// run event listener thread while we are enabled
mEventThread = new GpsEventThread();
mEventThread.start();
-
- if (requiresNetwork()) {
- // run network thread for NTP and XTRA support
- if (mNetworkThread == null) {
- mNetworkThread = new GpsNetworkThread();
- mNetworkThread.start();
- } else {
- mNetworkThread.signal();
- }
- }
} else {
Log.w(TAG, "Failed to enable location provider");
}
@@ -541,8 +679,17 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
* need not be handled. Hardware may be shut
* down while the provider is disabled.
*/
- public synchronized void disable() {
- if (Config.LOGD) Log.d(TAG, "disable");
+ public void disable() {
+ synchronized (mHandler) {
+ mHandler.removeMessages(ENABLE);
+ Message m = Message.obtain(mHandler, ENABLE);
+ m.arg1 = 0;
+ mHandler.sendMessage(m);
+ }
+ }
+
+ private void handleDisable() {
+ if (DEBUG) Log.d(TAG, "handleDisable");
if (!mEnabled) return;
mEnabled = false;
@@ -559,11 +706,6 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mEventThread = null;
}
- if (mNetworkThread != null) {
- mNetworkThread.setDone();
- mNetworkThread = null;
- }
-
// do this before releasing wakelock
native_cleanup();
@@ -602,6 +744,15 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void enableLocationTracking(boolean enable) {
+ synchronized (mHandler) {
+ mHandler.removeMessages(ENABLE_TRACKING);
+ Message m = Message.obtain(mHandler, ENABLE_TRACKING);
+ m.arg1 = (enable ? 1 : 0);
+ mHandler.sendMessage(m);
+ }
+ }
+
+ private void handleEnableLocationTracking(boolean enable) {
if (enable) {
mTTFF = 0;
mLastFixTime = 0;
@@ -614,7 +765,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void setMinTime(long minTime) {
- if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime);
+ if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
if (minTime >= 0) {
int interval = (int)(minTime/1000);
@@ -625,6 +776,10 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
+ public String getInternalState() {
+ return native_get_internal_state();
+ }
+
private final class Listener implements IBinder.DeathRecipient {
final IGpsStatusListener mListener;
@@ -635,7 +790,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void binderDied() {
- if (Config.LOGD) Log.d(TAG, "GPS status listener died");
+ if (DEBUG) Log.d(TAG, "GPS status listener died");
synchronized(mListeners) {
mListeners.remove(this);
@@ -647,6 +802,12 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void addListener(int uid) {
+ 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.
@@ -665,6 +826,12 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
public void removeListener(int uid) {
+ 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.
@@ -688,10 +855,12 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
return deleteAidingData(extras);
}
if ("force_time_injection".equals(command)) {
- return forceTimeInjection();
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessage(Message.obtain(mHandler, INJECT_NTP_TIME));
+ return true;
}
if ("force_xtra_injection".equals(command)) {
- if (native_supports_xtra() && mNetworkThread != null) {
+ if (native_supports_xtra()) {
xtraDownloadRequest();
return true;
}
@@ -732,16 +901,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
return false;
}
- private boolean forceTimeInjection() {
- if (Config.LOGD) Log.d(TAG, "forceTimeInjection");
- if (mNetworkThread != null) {
- mNetworkThread.timeInjectRequest();
- return true;
- }
- return false;
- }
-
- public void startNavigating() {
+ private void startNavigating() {
if (!mStarted) {
if (DEBUG) Log.d(TAG, "startNavigating");
mStarted = true;
@@ -753,7 +913,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
positionMode = GPS_POSITION_MODE_STANDALONE;
}
- if (!native_start(positionMode, false, mFixInterval)) {
+ if (!native_start(positionMode, false, 1)) {
mStarted = false;
Log.e(TAG, "native_start failed in startNavigating()");
return;
@@ -772,7 +932,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
- public void stopNavigating() {
+ private void stopNavigating() {
if (DEBUG) Log.d(TAG, "stopNavigating");
if (mStarted) {
mStarted = false;
@@ -834,7 +994,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
try {
- mLocationManager.reportLocation(mLocation);
+ mLocationManager.reportLocation(mLocation, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
@@ -844,7 +1004,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
// report time to first fix
if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
mTTFF = (int)(mLastFixTime - mFixRequestTime);
- if (Config.LOGD) Log.d(TAG, "TTFF: " + mTTFF);
+ if (DEBUG) Log.d(TAG, "TTFF: " + mTTFF);
// notify status listeners
synchronized(mListeners) {
@@ -852,7 +1012,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
for (int i = 0; i < size; i++) {
Listener listener = mListeners.get(i);
try {
- listener.mListener.onFirstFix(mTTFF);
+ listener.mListener.onFirstFix(mTTFF);
} catch (RemoteException e) {
Log.w(TAG, "RemoteException in stopNavigating");
mListeners.remove(listener);
@@ -864,7 +1024,12 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
if (mStarted && mStatus != LocationProvider.AVAILABLE) {
- mAlarmManager.cancel(mTimeoutIntent);
+ // we still want to time out if we do not receive MIN_FIX_COUNT
+ // within the time out and we are requesting infrequent fixes
+ if (mFixInterval < NO_FIX_TIMEOUT) {
+ mAlarmManager.cancel(mTimeoutIntent);
+ }
+
// send an intent to notify that the GPS is receiving fixes.
Intent intent = new Intent(GPS_FIX_CHANGE_ACTION);
intent.putExtra(EXTRA_ENABLED, true);
@@ -1075,11 +1240,13 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
}
}
+ /**
+ * called from native code to request XTRA data
+ */
private void xtraDownloadRequest() {
- if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
- if (mNetworkThread != null) {
- mNetworkThread.xtraDownloadRequest();
- }
+ if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
+ mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
+ mHandler.sendMessage(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA));
}
//=============================================================
@@ -1093,7 +1260,7 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
StringBuilder extrasBuf = new StringBuilder();
- if (Config.LOGD) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
+ if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
", response: " + userResponse);
native_send_ni_response(notificationId, userResponse);
@@ -1172,176 +1339,81 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
mNIHandler.handleNiNotification(notification);
}
- private class GpsEventThread extends Thread {
+ // this thread is used to receive events from the native code.
+ // native_wait_for_event() will callback to us via reportLocation(), reportStatus(), etc.
+ // this is necessary because native code cannot call Java on a thread that the JVM does
+ // not know about.
+ private final class GpsEventThread extends Thread {
public GpsEventThread() {
super("GpsEventThread");
}
public void run() {
- if (Config.LOGD) Log.d(TAG, "GpsEventThread starting");
+ if (DEBUG) Log.d(TAG, "GpsEventThread starting");
// Exit as soon as disable() is called instead of waiting for the GPS to stop.
while (mEnabled) {
// this will wait for an event from the GPS,
// which will be reported via reportLocation or reportStatus
native_wait_for_event();
}
- if (Config.LOGD) Log.d(TAG, "GpsEventThread exiting");
+ if (DEBUG) Log.d(TAG, "GpsEventThread exiting");
}
}
- private class GpsNetworkThread extends Thread {
-
- private long mNextNtpTime = 0;
- private long mNextXtraTime = 0;
- private boolean mTimeInjectRequested = false;
- private boolean mXtraDownloadRequested = false;
- private boolean mDone = false;
-
- public GpsNetworkThread() {
- super("GpsNetworkThread");
- }
-
- public void run() {
- synchronized (mNetworkThreadLock) {
- if (!mDone) {
- runLocked();
- }
- }
- }
-
- public void runLocked() {
- if (Config.LOGD) Log.d(TAG, "NetworkThread starting");
-
- SntpClient client = new SntpClient();
- GpsXtraDownloader xtraDownloader = null;
-
- if (native_supports_xtra()) {
- xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
- }
-
- // thread exits after disable() is called
- while (!mDone) {
- long waitTime = getWaitTime();
- do {
- synchronized (this) {
- try {
- if (!mNetworkAvailable) {
- if (Config.LOGD) Log.d(TAG,
- "NetworkThread wait for network");
- wait();
- } else if (waitTime > 0) {
- if (Config.LOGD) {
- Log.d(TAG, "NetworkThread wait for " +
- waitTime + "ms");
- }
- wait(waitTime);
- }
- } catch (InterruptedException e) {
- if (Config.LOGD) {
- Log.d(TAG, "InterruptedException in GpsNetworkThread");
- }
- }
- }
- waitTime = getWaitTime();
- } while (!mDone && ((!mXtraDownloadRequested &&
- !mTimeInjectRequested && waitTime > 0)
- || !mNetworkAvailable));
- if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop");
-
- if (!mDone) {
- if (mNtpServer != null &&
- (mTimeInjectRequested || mNextNtpTime <= System.currentTimeMillis())) {
- if (Config.LOGD) {
- Log.d(TAG, "Requesting time from NTP server " + mNtpServer);
- }
- mTimeInjectRequested = false;
- if (client.requestTime(mNtpServer, 10000)) {
- long time = client.getNtpTime();
- long timeReference = client.getNtpTimeReference();
- int certainty = (int)(client.getRoundTripTime()/2);
- long now = System.currentTimeMillis();
- long systemTimeOffset = time - now;
-
- Log.d(TAG, "NTP server returned: "
- + time + " (" + new Date(time)
- + ") reference: " + timeReference
- + " certainty: " + certainty
- + " system time offset: " + systemTimeOffset);
-
- // sanity check NTP time and do not use if it is too far from system time
- if (systemTimeOffset < 0) {
- systemTimeOffset = -systemTimeOffset;
- }
- if (systemTimeOffset < MAX_NTP_SYSTEM_TIME_OFFSET) {
- native_inject_time(time, timeReference, certainty);
- } else {
- Log.e(TAG, "NTP time differs from system time by " + systemTimeOffset
- + "ms. Ignoring.");
- }
- mNextNtpTime = now + NTP_INTERVAL;
- } else {
- if (Config.LOGD) Log.d(TAG, "requestTime failed");
- mNextNtpTime = System.currentTimeMillis() + RETRY_INTERVAL;
- }
+ private final class ProviderHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg)
+ {
+ switch (msg.what) {
+ case ENABLE:
+ if (msg.arg1 == 1) {
+ handleEnable();
+ } else {
+ handleDisable();
}
-
- if ((mXtraDownloadRequested ||
- (mNextXtraTime > 0 && mNextXtraTime <= System.currentTimeMillis()))
- && xtraDownloader != null) {
- mXtraDownloadRequested = false;
- byte[] data = xtraDownloader.downloadXtraData();
- if (data != null) {
- if (Config.LOGD) {
- Log.d(TAG, "calling native_inject_xtra_data");
- }
- native_inject_xtra_data(data, data.length);
- mNextXtraTime = 0;
- } else {
- mNextXtraTime = System.currentTimeMillis() + RETRY_INTERVAL;
- }
+ break;
+ case ENABLE_TRACKING:
+ handleEnableLocationTracking(msg.arg1 == 1);
+ break;
+ case UPDATE_NETWORK_STATE:
+ handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
+ break;
+ case INJECT_NTP_TIME:
+ handleInjectNtpTime();
+ break;
+ case DOWNLOAD_XTRA_DATA:
+ if (native_supports_xtra()) {
+ handleDownloadXtraData();
}
- }
+ break;
+ case UPDATE_LOCATION:
+ handleUpdateLocation((Location)msg.obj);
+ break;
+ case ADD_LISTENER:
+ handleAddListener(msg.arg1);
+ break;
+ case REMOVE_LISTENER:
+ handleRemoveListener(msg.arg1);
+ break;
}
- if (Config.LOGD) Log.d(TAG, "NetworkThread exiting");
- }
-
- synchronized void xtraDownloadRequest() {
- mXtraDownloadRequested = true;
- notify();
- }
-
- synchronized void timeInjectRequest() {
- mTimeInjectRequested = true;
- notify();
}
+ };
- synchronized void signal() {
- notify();
- }
+ private final class GpsLocationProviderThread extends Thread {
- synchronized void setDone() {
- if (Config.LOGD) Log.d(TAG, "stopping NetworkThread");
- mDone = true;
- notify();
+ public GpsLocationProviderThread() {
+ super("GpsLocationProvider");
}
- private long getWaitTime() {
- long now = System.currentTimeMillis();
- long waitTime = Long.MAX_VALUE;
- if (mNtpServer != null) {
- waitTime = mNextNtpTime - now;
- }
- if (mNextXtraTime != 0) {
- long xtraWaitTime = mNextXtraTime - now;
- if (xtraWaitTime < waitTime) {
- waitTime = xtraWaitTime;
- }
- }
- if (waitTime < 0) {
- waitTime = 0;
- }
- return waitTime;
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ initialize();
+ Looper.prepare();
+ mHandler = new ProviderHandler();
+ // signal when we are initialized and ready to go
+ mInitializedLatch.countDown();
+ Looper.loop();
}
}
@@ -1380,12 +1452,15 @@ public class GpsLocationProvider extends ILocationProvider.Stub {
private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
private native void native_inject_location(double latitude, double longitude, float accuracy);
- // XTRA Support
+ // XTRA Support
private native void native_inject_time(long time, long timeReference, int uncertainty);
private native boolean native_supports_xtra();
private native void native_inject_xtra_data(byte[] data, int length);
- // AGPS Support
+ // DEBUG Support
+ private native String native_get_internal_state();
+
+ // AGPS Support
private native void native_agps_data_conn_open(String apn);
private native void native_agps_data_conn_closed();
private native void native_agps_data_conn_failed();
diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java
index 33ebce7..978bda2 100644
--- a/location/java/com/android/internal/location/GpsXtraDownloader.java
+++ b/location/java/com/android/internal/location/GpsXtraDownloader.java
@@ -36,6 +36,8 @@ import android.net.http.AndroidHttpClient;
import android.util.Config;
import android.util.Log;
+
+
/**
* A class for downloading GPS XTRA data.
*
@@ -169,4 +171,3 @@ public class GpsXtraDownloader {
}
}
-
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index 89337b3..31ec09a 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -16,179 +16,262 @@
package com.android.internal.location;
-import android.location.Address;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
import android.location.ILocationProvider;
import android.location.Location;
-import android.location.LocationManager;
+import android.location.LocationProviderInterface;
import android.net.NetworkInfo;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.SystemClock;
import android.util.Log;
-import java.util.List;
-
/**
- * A class for proxying remote ILocationProvider implementations.
+ * A class for proxying location providers implemented as services.
*
* {@hide}
*/
-public class LocationProviderProxy implements IBinder.DeathRecipient {
+public class LocationProviderProxy implements LocationProviderInterface {
private static final String TAG = "LocationProviderProxy";
+ private final Context mContext;
private final String mName;
- private final ILocationProvider mProvider;
- private boolean mLocationTracking = false;
- private long mMinTime = 0;
- private boolean mDead;
+ private ILocationProvider mProvider;
+ private Handler mHandler;
+ private final Connection mServiceConnection = new Connection();
- public LocationProviderProxy(String name, ILocationProvider provider) {
+ // cached values set by the location manager
+ private boolean mLocationTracking = false;
+ private boolean mEnabled = false;
+ private long mMinTime = -1;
+ private int mNetworkState;
+ private NetworkInfo mNetworkInfo;
+
+ // for caching requiresNetwork, requiresSatellite, etc.
+ private DummyLocationProvider mCachedAttributes;
+
+ // constructor for proxying location providers implemented in a separate service
+ public LocationProviderProxy(Context context, String name, String serviceName,
+ Handler handler) {
+ mContext = context;
mName = name;
- mProvider = provider;
- try {
- provider.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.e(TAG, "linkToDeath failed", e);
- mDead = true;
- }
+ mHandler = handler;
+ mContext.bindService(new Intent(serviceName), mServiceConnection, Context.BIND_AUTO_CREATE);
}
- public void unlinkProvider() {
- if (mProvider != null) {
- mProvider.asBinder().unlinkToDeath(this, 0);
+ private class Connection implements ServiceConnection {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "LocationProviderProxy.onServiceConnected " + className);
+ synchronized (this) {
+ mProvider = ILocationProvider.Stub.asInterface(service);
+ if (mProvider != null) {
+ mHandler.post(mServiceConnectedTask);
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "LocationProviderProxy.onServiceDisconnected " + className);
+ synchronized (this) {
+ mProvider = null;
+ }
}
}
+ private Runnable mServiceConnectedTask = new Runnable() {
+ public void run() {
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ if (provider == null) {
+ return;
+ }
+ }
+
+ if (mCachedAttributes == null) {
+ try {
+ mCachedAttributes = new DummyLocationProvider(mName);
+ 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;
+ }
+ }
+
+ // resend previous values from the location manager if the service has restarted
+ try {
+ if (mEnabled) {
+ provider.enable();
+ }
+ if (mLocationTracking) {
+ provider.enableLocationTracking(true);
+ }
+ if (mMinTime >= 0) {
+ provider.setMinTime(mMinTime);
+ }
+ if (mNetworkInfo != null) {
+ provider.updateNetworkState(mNetworkState, mNetworkInfo);
+ }
+ } catch (RemoteException e) {
+ }
+ }
+ };
+
public String getName() {
return mName;
}
- public boolean isDead() {
- return mDead;
- }
-
public boolean requiresNetwork() {
- try {
- return mProvider.requiresNetwork();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresNetwork failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresNetwork();
+ } else {
return false;
}
}
public boolean requiresSatellite() {
- try {
- return mProvider.requiresSatellite();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresSatellite failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresSatellite();
+ } else {
return false;
}
}
public boolean requiresCell() {
- try {
- return mProvider.requiresCell();
- } catch (RemoteException e) {
- Log.e(TAG, "requiresCell failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.requiresCell();
+ } else {
return false;
}
}
public boolean hasMonetaryCost() {
- try {
- return mProvider.hasMonetaryCost();
- } catch (RemoteException e) {
- Log.e(TAG, "hasMonetaryCost failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.hasMonetaryCost();
+ } else {
return false;
}
}
public boolean supportsAltitude() {
- try {
- return mProvider.supportsAltitude();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsAltitude failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsAltitude();
+ } else {
return false;
}
}
public boolean supportsSpeed() {
- try {
- return mProvider.supportsSpeed();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsSpeed failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsSpeed();
+ } else {
return false;
}
}
public boolean supportsBearing() {
- try {
- return mProvider.supportsBearing();
- } catch (RemoteException e) {
- Log.e(TAG, "supportsBearing failed", e);
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.supportsBearing();
+ } else {
return false;
}
}
public int getPowerRequirement() {
- try {
- return mProvider.getPowerRequirement();
- } catch (RemoteException e) {
- Log.e(TAG, "getPowerRequirement failed", e);
- return 0;
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.getPowerRequirement();
+ } else {
+ return -1;
}
}
public int getAccuracy() {
- try {
- return mProvider.getAccuracy();
- } catch (RemoteException e) {
- Log.e(TAG, "getAccuracy failed", e);
- return 0;
+ if (mCachedAttributes != null) {
+ return mCachedAttributes.getAccuracy();
+ } else {
+ return -1;
}
}
public void enable() {
- try {
- mProvider.enable();
- } catch (RemoteException e) {
- Log.e(TAG, "enable failed", e);
+ mEnabled = true;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.enable();
+ } catch (RemoteException e) {
+ }
}
}
public void disable() {
- try {
- mProvider.disable();
- } catch (RemoteException e) {
- Log.e(TAG, "disable failed", e);
+ mEnabled = false;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.disable();
+ } catch (RemoteException e) {
+ }
}
}
public boolean isEnabled() {
- try {
- return mProvider.isEnabled();
- } catch (RemoteException e) {
- Log.e(TAG, "isEnabled failed", e);
- return false;
- }
+ return mEnabled;
}
public int getStatus(Bundle extras) {
- try {
- return mProvider.getStatus(extras);
- } catch (RemoteException e) {
- Log.e(TAG, "getStatus failed", e);
- return 0;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getStatus(extras);
+ } catch (RemoteException e) {
+ }
}
+ return 0;
}
public long getStatusUpdateTime() {
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ return provider.getStatusUpdateTime();
+ } catch (RemoteException e) {
+ }
+ }
+ return 0;
+ }
+
+ public String getInternalState() {
try {
- return mProvider.getStatusUpdateTime();
+ return mProvider.getInternalState();
} catch (RemoteException e) {
- Log.e(TAG, "getStatusUpdateTime failed", e);
- return 0;
+ Log.e(TAG, "getInternalState failed", e);
+ return null;
}
}
@@ -198,10 +281,18 @@ public class LocationProviderProxy implements IBinder.DeathRecipient {
public void enableLocationTracking(boolean enable) {
mLocationTracking = enable;
- try {
- mProvider.enableLocationTracking(enable);
- } catch (RemoteException e) {
- Log.e(TAG, "enableLocationTracking failed", e);
+ if (!enable) {
+ mMinTime = -1;
+ }
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.enableLocationTracking(enable);
+ } catch (RemoteException e) {
+ }
}
}
@@ -210,58 +301,84 @@ public class LocationProviderProxy implements IBinder.DeathRecipient {
}
public void setMinTime(long minTime) {
- mMinTime = minTime;
- try {
- mProvider.setMinTime(minTime);
- } catch (RemoteException e) {
- Log.e(TAG, "setMinTime failed", e);
+ mMinTime = minTime;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.setMinTime(minTime);
+ } catch (RemoteException e) {
+ }
}
}
public void updateNetworkState(int state, NetworkInfo info) {
- try {
- mProvider.updateNetworkState(state, info);
- } catch (RemoteException e) {
- Log.e(TAG, "updateNetworkState failed", e);
+ mNetworkState = state;
+ mNetworkInfo = info;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.updateNetworkState(state, info);
+ } catch (RemoteException e) {
+ }
}
}
public void updateLocation(Location location) {
- try {
- mProvider.updateLocation(location);
- } catch (RemoteException e) {
- Log.e(TAG, "updateLocation failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.updateLocation(location);
+ } catch (RemoteException e) {
+ }
}
}
public boolean sendExtraCommand(String command, Bundle extras) {
- try {
- return mProvider.sendExtraCommand(command, extras);
- } catch (RemoteException e) {
- Log.e(TAG, "sendExtraCommand failed", e);
- return false;
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.sendExtraCommand(command, extras);
+ } catch (RemoteException e) {
+ }
}
+ return false;
}
public void addListener(int uid) {
- try {
- mProvider.addListener(uid);
- } catch (RemoteException e) {
- Log.e(TAG, "addListener failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.addListener(uid);
+ } catch (RemoteException e) {
+ }
}
}
public void removeListener(int uid) {
- try {
- mProvider.removeListener(uid);
- } catch (RemoteException e) {
- Log.e(TAG, "removeListener failed", e);
+ ILocationProvider provider;
+ synchronized (mServiceConnection) {
+ provider = mProvider;
+ }
+ if (provider != null) {
+ try {
+ provider.removeListener(uid);
+ } catch (RemoteException e) {
+ }
}
- }
-
- public void binderDied() {
- Log.w(TAG, "Location Provider " + mName + " died");
- mDead = true;
- mProvider.asBinder().unlinkToDeath(this, 0);
}
}
diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java
index 2614f82..d912740 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/location/java/com/android/internal/location/MockProvider.java
@@ -17,9 +17,9 @@
package com.android.internal.location;
import android.location.ILocationManager;
-import android.location.ILocationProvider;
import android.location.Location;
import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.RemoteException;
@@ -33,7 +33,7 @@ import java.io.PrintWriter;
*
* {@hide}
*/
-public class MockProvider extends ILocationProvider.Stub {
+public class MockProvider implements LocationProviderInterface {
private final String mName;
private final ILocationManager mLocationManager;
private final boolean mRequiresNetwork;
@@ -73,6 +73,10 @@ public class MockProvider extends ILocationProvider.Stub {
mLocation = new Location(name);
}
+ public String getName() {
+ return mName;
+ }
+
public void disable() {
mEnabled = false;
}
@@ -81,6 +85,10 @@ public class MockProvider extends ILocationProvider.Stub {
mEnabled = true;
}
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
public int getStatus(Bundle extras) {
if (mHasStatus) {
extras.clear();
@@ -95,10 +103,6 @@ public class MockProvider extends ILocationProvider.Stub {
return mStatusUpdateTime;
}
- public boolean isEnabled() {
- return mEnabled;
- }
-
public int getAccuracy() {
return mAccuracy;
}
@@ -139,7 +143,7 @@ public class MockProvider extends ILocationProvider.Stub {
mLocation.set(l);
mHasLocation = true;
try {
- mLocationManager.reportLocation(mLocation);
+ mLocationManager.reportLocation(mLocation, false);
} catch (RemoteException e) {
Log.e(TAG, "RemoteException calling reportLocation");
}
@@ -164,6 +168,10 @@ public class MockProvider extends ILocationProvider.Stub {
mStatusUpdateTime = 0;
}
+ public String getInternalState() {
+ return null;
+ }
+
public void enableLocationTracking(boolean enable) {
}
diff --git a/location/java/com/android/internal/location/NmeaParser.java b/location/java/com/android/internal/location/NmeaParser.java
deleted file mode 100644
index 43afa1d..0000000
--- a/location/java/com/android/internal/location/NmeaParser.java
+++ /dev/null
@@ -1,437 +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 java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
-
-import android.location.Location;
-import android.os.Bundle;
-import android.util.Log;
-
-/**
- * {@hide}
- */
-public class NmeaParser {
-
- private static final String TAG = "NmeaParser";
-
- private static final TimeZone sUtcTimeZone = TimeZone.getTimeZone("UTC");
-
- private static final float KNOTS_TO_METERS_PER_SECOND = 0.51444444444f;
-
- private final String mName;
-
- private int mYear = -1;
- private int mMonth;
- private int mDay;
-
- private long mTime = -1;
- private long mBaseTime;
- private double mLatitude;
- private double mLongitude;
-
- private boolean mHasAltitude;
- private double mAltitude;
- private boolean mHasBearing;
- private float mBearing;
- private boolean mHasSpeed;
- private float mSpeed;
-
- private boolean mNewWaypoint = false;
- private Location mLocation = null;
- private Bundle mExtras;
-
- public NmeaParser(String name) {
- mName = name;
- }
-
- private boolean updateTime(String time) {
- if (time.length() < 6) {
- return false;
- }
- if (mYear == -1) {
- // Since we haven't seen a day/month/year yet,
- // we can't construct a meaningful time stamp.
- // Clean up any old data.
- mLatitude = 0.0;
- mLongitude = 0.0;
- mHasAltitude = false;
- mHasBearing = false;
- mHasSpeed = false;
- mExtras = null;
- return false;
- }
-
- int hour, minute;
- float second;
- try {
- hour = Integer.parseInt(time.substring(0, 2));
- minute = Integer.parseInt(time.substring(2, 4));
- second = Float.parseFloat(time.substring(4, time.length()));
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Error parsing timestamp " + time);
- return false;
- }
-
- int isecond = (int) second;
- int millis = (int) ((second - isecond) * 1000);
- Calendar c = new GregorianCalendar(sUtcTimeZone);
- c.set(mYear, mMonth, mDay, hour, minute, isecond);
- long newTime = c.getTimeInMillis() + millis;
-
- if (mTime == -1) {
- mTime = 0;
- mBaseTime = newTime;
- }
- newTime -= mBaseTime;
-
- // If the timestamp has advanced, copy the temporary data
- // into a new Location
- if (newTime != mTime) {
- mNewWaypoint = true;
- mLocation = new Location(mName);
- mLocation.setTime(mTime);
- mLocation.setLatitude(mLatitude);
- mLocation.setLongitude(mLongitude);
- if (mHasAltitude) {
- mLocation.setAltitude(mAltitude);
- }
- if (mHasBearing) {
- mLocation.setBearing(mBearing);
- }
- if (mHasSpeed) {
- mLocation.setSpeed(mSpeed);
- }
- mLocation.setExtras(mExtras);
- mExtras = null;
-
- mTime = newTime;
- mHasAltitude = false;
- mHasBearing = false;
- mHasSpeed = false;
- }
- return true;
- }
-
- private boolean updateDate(String date) {
- if (date.length() != 6) {
- return false;
- }
- int month, day, year;
- try {
- day = Integer.parseInt(date.substring(0, 2));
- month = Integer.parseInt(date.substring(2, 4));
- year = 2000 + Integer.parseInt(date.substring(4, 6));
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Error parsing date " + date);
- return false;
- }
-
- mYear = year;
- mMonth = month;
- mDay = day;
- return true;
- }
-
- private boolean updateTime(String time, String date) {
- if (!updateDate(date)) {
- return false;
- }
- return updateTime(time);
- }
-
- private boolean updateIntExtra(String name, String value) {
- int val;
- try {
- val = Integer.parseInt(value);
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing int " + name + ": " + value, nfe);
- return false;
- }
- if (mExtras == null) {
- mExtras = new Bundle();
- }
- mExtras.putInt(name, val);
- return true;
- }
-
- private boolean updateFloatExtra(String name, String value) {
- float val;
- try {
- val = Float.parseFloat(value);
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing float " + name + ": " + value, nfe);
- return false;
- }
- if (mExtras == null) {
- mExtras = new Bundle();
- }
- mExtras.putFloat(name, val);
- return true;
- }
-
- private boolean updateDoubleExtra(String name, String value) {
- double val;
- try {
- val = Double.parseDouble(value);
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing double " + name + ": " + value, nfe);
- return false;
- }
- if (mExtras == null) {
- mExtras = new Bundle();
- }
- mExtras.putDouble(name, val);
- return true;
- }
-
- private double convertFromHHMM(String coord) {
- double val = Double.parseDouble(coord);
- int degrees = ((int) Math.floor(val)) / 100;
- double minutes = val - (degrees * 100);
- double dcoord = degrees + minutes / 60.0;
- return dcoord;
- }
-
- private boolean updateLatLon(String latitude, String latitudeHemi,
- String longitude, String longitudeHemi) {
- if (latitude.length() == 0 || longitude.length() == 0) {
- return false;
- }
-
- // Lat/long values are expressed as {D}DDMM.MMMM
- double lat, lon;
- try {
- lat = convertFromHHMM(latitude);
- if (latitudeHemi.charAt(0) == 'S') {
- lat = -lat;
- }
- } catch (NumberFormatException nfe1) {
- Log.e(TAG, "Exception parsing lat/long: " + nfe1, nfe1);
- return false;
- }
-
- try {
- lon = convertFromHHMM(longitude);
- if (longitudeHemi.charAt(0) == 'W') {
- lon = -lon;
- }
- } catch (NumberFormatException nfe2) {
- Log.e(TAG, "Exception parsing lat/long: " + nfe2, nfe2);
- return false;
- }
-
- // Only update if both were parsed cleanly
- mLatitude = lat;
- mLongitude = lon;
- return true;
- }
-
- private boolean updateAltitude(String altitude) {
- if (altitude.length() == 0) {
- return false;
- }
- double alt;
- try {
- alt = Double.parseDouble(altitude);
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing altitude " + altitude + ": " + nfe,
- nfe);
- return false;
- }
-
- mHasAltitude = true;
- mAltitude = alt;
- return true;
- }
-
- private boolean updateBearing(String bearing) {
- float brg;
- try {
- brg = Float.parseFloat(bearing);
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing bearing " + bearing + ": " + nfe,
- nfe);
- return false;
- }
-
- mHasBearing = true;
- mBearing = brg;
- return true;
- }
-
- private boolean updateSpeed(String speed) {
- float spd;
- try {
- spd = Float.parseFloat(speed) * KNOTS_TO_METERS_PER_SECOND;
- } catch (NumberFormatException nfe) {
- Log.e(TAG, "Exception parsing speed " + speed + ": " + nfe, nfe);
- return false;
- }
-
- mHasSpeed = true;
- mSpeed = spd;
- return true;
- }
-
- public boolean parseSentence(String s) {
- int len = s.length();
- if (len < 9) {
- return false;
- }
- if (s.charAt(len - 3) == '*') {
- // String checksum = s.substring(len - 4, len);
- s = s.substring(0, len - 3);
- }
- String[] tokens = s.split(",");
- String sentenceId = tokens[0].substring(3, 6);
-
- int idx = 1;
- try {
- if (sentenceId.equals("GGA")) {
- String time = tokens[idx++];
- String latitude = tokens[idx++];
- String latitudeHemi = tokens[idx++];
- String longitude = tokens[idx++];
- String longitudeHemi = tokens[idx++];
- String fixQuality = tokens[idx++];
- String numSatellites = tokens[idx++];
- String horizontalDilutionOfPrecision = tokens[idx++];
- String altitude = tokens[idx++];
- String altitudeUnits = tokens[idx++];
- String heightOfGeoid = tokens[idx++];
- String heightOfGeoidUnits = tokens[idx++];
- String timeSinceLastDgpsUpdate = tokens[idx++];
-
- updateTime(time);
- updateLatLon(latitude, latitudeHemi,
- longitude, longitudeHemi);
- updateAltitude(altitude);
- // updateQuality(fixQuality);
- updateIntExtra("numSatellites", numSatellites);
- updateFloatExtra("hdop", horizontalDilutionOfPrecision);
-
- if (mNewWaypoint) {
- mNewWaypoint = false;
- return true;
- }
- } else if (sentenceId.equals("GSA")) {
- // DOP and active satellites
- String selectionMode = tokens[idx++]; // m=manual, a=auto 2d/3d
- String mode = tokens[idx++]; // 1=no fix, 2=2d, 3=3d
- for (int i = 0; i < 12; i++) {
- String id = tokens[idx++];
- }
- String pdop = tokens[idx++];
- String hdop = tokens[idx++];
- String vdop = tokens[idx++];
-
- // TODO - publish satellite ids
- updateFloatExtra("pdop", pdop);
- updateFloatExtra("hdop", hdop);
- updateFloatExtra("vdop", vdop);
- } else if (sentenceId.equals("GSV")) {
- // Satellites in view
- String numMessages = tokens[idx++];
- String messageNum = tokens[idx++];
- String svsInView = tokens[idx++];
- for (int i = 0; i < 4; i++) {
- if (idx + 2 < tokens.length) {
- String prnNumber = tokens[idx++];
- String elevation = tokens[idx++];
- String azimuth = tokens[idx++];
- if (idx < tokens.length) {
- String snr = tokens[idx++];
- }
- }
- }
- // TODO - publish this info
- } else if (sentenceId.equals("RMC")) {
- // Recommended minimum navigation information
- String time = tokens[idx++];
- String fixStatus = tokens[idx++];
- String latitude = tokens[idx++];
- String latitudeHemi = tokens[idx++];
- String longitude = tokens[idx++];
- String longitudeHemi = tokens[idx++];
- String speed = tokens[idx++];
- String bearing = tokens[idx++];
- String utcDate = tokens[idx++];
- String magneticVariation = tokens[idx++];
- String magneticVariationDir = tokens[idx++];
- String mode = tokens[idx++];
-
- if (fixStatus.charAt(0) == 'A') {
- updateTime(time, utcDate);
- updateLatLon(latitude, latitudeHemi,
- longitude, longitudeHemi);
- updateBearing(bearing);
- updateSpeed(speed);
- }
-
- if (mNewWaypoint) {
- return true;
- }
- } else {
- Log.e(TAG, "Unknown sentence: " + s);
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- // do nothing - sentence will have no effect
- Log.e(TAG, "AIOOBE", e);
-
- for (int i = 0; i < tokens.length; i++) {
- Log.e(TAG, "Got token #" + i + " = " + tokens[i]);
- }
- }
-
- return false;
- }
-
-// } else if (sentenceId.equals("GLL")) {
-// // Geographics position lat/long
-// String latitude = tokens[idx++];
-// String latitudeHemi = tokens[idx++];
-// String longitude = tokens[idx++];
-// String longitudeHemi = tokens[idx++];
-// String time = tokens[idx++];
-// String status = tokens[idx++];
-// String mode = tokens[idx++];
-// String checksum = tokens[idx++];
-//
-// if (status.charAt(0) == 'A') {
-// updateTime(time);
-// updateLatLon(latitude, latitudeHemi, longitude, longitudeHemi);
-// }
-//} else if (sentenceId.equals("VTG")) {
-// String trackMadeGood = tokens[idx++];
-// String t = tokens[idx++];
-// String unused1 = tokens[idx++];
-// String unused2 = tokens[idx++];
-// String groundSpeedKnots = tokens[idx++];
-// String n = tokens[idx++];
-// String groundSpeedKph = tokens[idx++];
-// String k = tokens[idx++];
-// String checksum = tokens[idx++];
-//
-// updateSpeed(groundSpeedKph);
-
- public Location getLocation() {
- return mLocation;
- }
-}
diff --git a/location/java/com/android/internal/location/PassiveProvider.java b/location/java/com/android/internal/location/PassiveProvider.java
new file mode 100644
index 0000000..ab90937
--- /dev/null
+++ b/location/java/com/android/internal/location/PassiveProvider.java
@@ -0,0 +1,143 @@
+/*
+ * 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.internal.location;
+
+import android.location.ILocationManager;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.location.LocationProviderInterface;
+import android.net.NetworkInfo;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * A passive location provider reports locations received from other providers
+ * for clients that want to listen passively without actually triggering
+ * location updates.
+ *
+ * {@hide}
+ */
+public class PassiveProvider implements LocationProviderInterface {
+
+ private static final String TAG = "PassiveProvider";
+
+ private final ILocationManager mLocationManager;
+ private boolean mTracking;
+
+ public PassiveProvider(ILocationManager locationManager) {
+ mLocationManager = locationManager;
+ }
+
+ 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 int getAccuracy() {
+ return -1;
+ }
+
+ public boolean isEnabled() {
+ return true;
+ }
+
+ public void enable() {
+ }
+
+ public void disable() {
+ }
+
+ public int getStatus(Bundle extras) {
+ if (mTracking) {
+ return LocationProvider.AVAILABLE;
+ } else {
+ return LocationProvider.TEMPORARILY_UNAVAILABLE;
+ }
+ }
+
+ public long getStatusUpdateTime() {
+ return -1;
+ }
+
+ public String getInternalState() {
+ return null;
+ }
+
+ public void enableLocationTracking(boolean enable) {
+ mTracking = enable;
+ }
+
+ public void setMinTime(long minTime) {
+ }
+
+ public void updateNetworkState(int state, NetworkInfo info) {
+ }
+
+ public void updateLocation(Location location) {
+ if (mTracking) {
+ try {
+ // pass the location back to the location manager
+ mLocationManager.reportLocation(location, true);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling reportLocation");
+ }
+ }
+ }
+
+ public boolean sendExtraCommand(String command, Bundle extras) {
+ return false;
+ }
+
+ public void addListener(int uid) {
+ }
+
+ public void removeListener(int uid) {
+ }
+}