diff options
Diffstat (limited to 'location/java')
19 files changed, 1037 insertions, 1644 deletions
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java index 709ad23..53e46b7 100644 --- a/location/java/android/location/Geocoder.java +++ b/location/java/android/location/Geocoder.java @@ -36,7 +36,11 @@ import java.util.List; * coordinate into a (partial) address. The amount of detail in a * reverse geocoded location description may vary, for example one * might contain the full street address of the closest building, while - * another might contain only a city name and postal code. + * another might contain only a city name and postal code. + * + * The Geocoder class requires a backend service that is not included in + * the core android framework. The Geocoder query methods will return an + * empty list if there no backend service in the platform. */ public final class Geocoder { private static final String TAG = "Geocoder"; @@ -94,8 +98,8 @@ public final class Geocoder { * @param longitude the longitude a point for the search * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended * - * @return a list of Address objects or null if no matches were - * found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if latitude is * less than -90 or greater than 90 @@ -143,7 +147,8 @@ public final class Geocoder { * @param locationName a user-supplied description of a location * @param maxResults max number of results to return. Smaller numbers (1 to 5) are recommended * - * @return a list of Address objects or null if no matches were found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if locationName is null * @throws IOException if the network is unavailable or any other @@ -192,7 +197,8 @@ public final class Geocoder { * @param upperRightLatitude the latitude of the upper right corner of the bounding box * @param upperRightLongitude the longitude of the upper right corner of the bounding box * - * @return a list of Address objects or null if no matches were found. + * @return a list of Address objects. Returns null or empty list if no matches were + * found or there is no backend service available. * * @throws IllegalArgumentException if locationName is null * @throws IllegalArgumentException if any latitude is diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java index a40b1fb..2cda7fa 100644 --- a/location/java/android/location/GpsStatus.java +++ b/location/java/android/location/GpsStatus.java @@ -25,7 +25,7 @@ import java.util.NoSuchElementException; * This class is used in conjunction with the {@link Listener} interface. */ public final class GpsStatus { - private static final int NUM_SATELLITES = 32; + private static final int NUM_SATELLITES = 255; /* These package private values are modified by the LocationManager class */ private int mTimeToFirstFix; diff --git a/location/java/android/location/IGeocodeProvider.aidl b/location/java/android/location/IGeocodeProvider.aidl new file mode 100644 index 0000000..e79e8d2 --- /dev/null +++ b/location/java/android/location/IGeocodeProvider.aidl @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2009 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.Address; + +/** + * An interface for location providers implementing the Geocoder services. + * + * {@hide} + */ +interface IGeocodeProvider { + + String getFromLocation(double latitude, double longitude, int maxResults, + String language, String country, String variant, String appName, 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); +} diff --git a/location/java/android/location/IGpsStatusProvider.aidl b/location/java/android/location/IGpsStatusProvider.aidl new file mode 100644 index 0000000..cf277c8 --- /dev/null +++ b/location/java/android/location/IGpsStatusProvider.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2009 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.IGpsStatusListener; + +/** + * An interface for location providers that provide GPS status information. + * + * {@hide} + */ +interface IGpsStatusProvider { + void addGpsStatusListener(IGpsStatusListener listener); + void removeGpsStatusListener(IGpsStatusListener listener); +} diff --git a/location/java/com/android/internal/location/INetworkLocationManager.java b/location/java/android/location/ILocationCollector.aidl index d85ff0a..b2e1796 100644 --- a/location/java/com/android/internal/location/INetworkLocationManager.java +++ b/location/java/android/location/ILocationCollector.aidl @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,24 +14,23 @@ * limitations under the License. */ -package com.android.internal.location; +package android.location; -import android.content.Context; +import android.location.Location; /** - * Used to register network location and collection services - * with the Location Manager Service. + * Listens for GPS and cell/wifi changes and anonymously uploads to server + * for improving quality of service of NetworkLocationProvider. + * This service is only enabled when the user has enabled the + * network location provider. * * {@hide} */ -public interface INetworkLocationManager { - - /* callback to allow installation to occur in Location Manager's thread */ - public interface InstallCallback { - void installNetworkLocationProvider(INetworkLocationManager manager); - } - - void setInstallCallback(InstallCallback callback); - void setNetworkLocationProvider(INetworkLocationProvider provider); - void setLocationCollector(ILocationCollector collector); -}
\ No newline at end of file +oneway interface ILocationCollector { + /** + * Updates GPS location if collection is enabled + * + * @param location location object + */ + void updateLocation(in Location location); +} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index 69c404a..2c214c9 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -18,8 +18,11 @@ package android.location; import android.app.PendingIntent; import android.location.Address; +import android.location.IGeocodeProvider; import android.location.IGpsStatusListener; +import android.location.ILocationCollector; import android.location.ILocationListener; +import android.location.ILocationProvider; import android.location.Location; import android.os.Bundle; @@ -33,8 +36,6 @@ interface ILocationManager List getAllProviders(); List getProviders(boolean enabledOnly); - void updateProviders(); - void requestLocationUpdates(String provider, long minTime, float minDistance, in ILocationListener listener); void requestLocationUpdatesPI(String provider, long minTime, float minDistance, @@ -44,7 +45,10 @@ interface ILocationManager 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, @@ -56,6 +60,9 @@ 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); + String getFromLocation(double latitude, double longitude, int maxResults, String language, String country, String variant, String appName, out List<Address> addrs); String getFromLocationName(String locationName, @@ -73,4 +80,9 @@ interface ILocationManager void clearTestProviderEnabled(String provider); 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 installLocationCollector(ILocationCollector collector); + void installGeocodeProvider(IGeocodeProvider provider); } diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl new file mode 100644 index 0000000..6c23f83 --- /dev/null +++ b/location/java/android/location/ILocationProvider.aidl @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2009 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.Bundle; + +/** + * Binder interface for location providers. + * + * {@hide} + */ +interface ILocationProvider { + boolean requiresNetwork(); + boolean requiresSatellite(); + boolean requiresCell(); + boolean hasMonetaryCost(); + boolean supportsAltitude(); + boolean supportsSpeed(); + boolean supportsBearing(); + int getPowerRequirement(); + int getAccuracy(); + void enable(); + void disable(); + boolean isEnabled(); + int getStatus(out Bundle extras); + long getStatusUpdateTime(); + void enableLocationTracking(boolean enable); + void setMinTime(long minTime); + void updateNetworkState(int state); + boolean sendExtraCommand(String command, inout Bundle extras); + void addListener(int uid); + void removeListener(int uid); +} diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 022ee25..872838c 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -26,6 +26,8 @@ import android.os.Message; import android.util.Config; import android.util.Log; +import com.android.internal.location.DummyLocationProvider; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -101,9 +103,6 @@ public class LocationManager { */ public static final String KEY_LOCATION_CHANGED = "location"; - /** @hide -- does this belong here? */ - public static final String PROVIDER_DIR = "/data/location"; - /** @hide */ public static final String SYSTEM_DIR = "/data/system/location"; @@ -194,6 +193,11 @@ public class LocationManager { mListener.onProviderDisabled((String) msg.obj); break; } + try { + mService.locationCallbackFinished(this); + } catch (RemoteException e) { + Log.e(TAG, "locationCallbackFinished: RemoteException", e); + } } } /** @@ -313,20 +317,6 @@ public class LocationManager { } /** - * Propagates the enabled/disabled state of the providers from the system - * settings to the providers themselves. - * - * {@hide} - */ - public void updateProviders() { - try { - mService.updateProviders(); - } catch (RemoteException ex) { - Log.e(TAG, "updateProviders: RemoteException", ex); - } - } - - /** * Returns the next looser power requirement, in the sequence: * * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT @@ -1265,4 +1255,85 @@ 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 location collector. + * + * @param provider Binder interface for the location collector + * + * @return true if the command succeeds. + * + * Requires the android.permission.INSTALL_LOCATION_COLLECTOR permission. + * + * {@hide} + */ + public boolean installLocationCollector(ILocationCollector collector) { + try { + mService.installLocationCollector(collector); + return true; + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in setLocationCollector: ", 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); + } + } } diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java index b1670d5..3faba58 100644 --- a/location/java/android/location/LocationProvider.java +++ b/location/java/android/location/LocationProvider.java @@ -47,8 +47,10 @@ public abstract class LocationProvider { * consist only of the characters [a-zA-Z0-9]. * * @throws IllegalArgumentException if name contains an illegal character + * + * {@hide} */ - LocationProvider(String name) { + public LocationProvider(String name) { if (name.matches(BAD_CHARS_REGEX)) { throw new IllegalArgumentException("name " + name + " contains an illegal character"); diff --git a/location/java/android/location/LocationProviderImpl.java b/location/java/android/location/LocationProviderImpl.java deleted file mode 100644 index 0962992..0000000 --- a/location/java/android/location/LocationProviderImpl.java +++ /dev/null @@ -1,261 +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 android.location; - -import com.android.internal.location.CellState; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -import android.os.Bundle; -import android.util.Config; -import android.util.Log; - -/** - * An abstract superclass for location provider implementations. - * Location provider implementations are typically instantiated by the - * location manager service in the system process, and location - * information is made available to implementations via the manager. - * - * {@hide} - */ -public abstract class LocationProviderImpl extends LocationProvider { - private static final String TAG = "LocationProviderImpl"; - - private static ArrayList<LocationProviderImpl> sProviders = - new ArrayList<LocationProviderImpl>(); - private static HashMap<String, LocationProviderImpl> sProvidersByName - = new HashMap<String, LocationProviderImpl>(); - - private boolean mLocationTracking = false; - private long mMinTime = 0; - - protected LocationProviderImpl(String name) { - super(name); - } - - public static void addProvider(LocationProviderImpl provider) { - sProviders.add(provider); - sProvidersByName.put(provider.getName(), provider); - } - - public static void removeProvider(LocationProviderImpl provider) { - sProviders.remove(provider); - sProvidersByName.remove(provider.getName()); - } - - public static List<LocationProviderImpl> getProviders() { - return new ArrayList<LocationProviderImpl>(sProviders); - } - - public static LocationProviderImpl getProvider(String name) { - return sProvidersByName.get(name); - } - - public static LocationProviderImpl loadFromClass(File classFile) { - if (!classFile.exists()) { - return null; - } - if (Config.LOGD) { - Log.d(TAG, "Loading class specifier file " + classFile.getPath()); - } - String className = null; - try { - BufferedReader br = - new BufferedReader(new FileReader(classFile), 8192); - className = br.readLine(); - br.close(); - Class providerClass = Class.forName(className); - if (Config.LOGD) { - Log.d(TAG, "Loading provider class " + providerClass.getName()); - } - LocationProviderImpl provider = - (LocationProviderImpl) providerClass.newInstance(); - if (Config.LOGD) { - Log.d(TAG, "Got provider instance " + provider); - } - - return provider; - } catch (IOException ioe) { - Log.e(TAG, "IOException loading config file " + - classFile.getPath(), ioe); - } catch (IllegalAccessException iae) { - Log.e(TAG, "IllegalAccessException loading class " + - className, iae); - } catch (InstantiationException ie) { - Log.e(TAG, "InstantiationException loading class " + - className, ie); - } catch (ClassNotFoundException cnfe) { - Log.e(TAG, "ClassNotFoundException loading class " + - className, cnfe); - } catch (ClassCastException cce) { - Log.e(TAG, "ClassCastException loading class " + - className, cce); - } - return null; - } - - /** - * Enables this provider. When enabled, calls to {@link #getStatus()} - * and {@link #getLocation} must be handled. Hardware may be started up - * when the provider is enabled. - */ - public abstract void enable(); - - /** - * Disables this provider. When disabled, calls to {@link #getStatus()} - * and {@link #getLocation} need not be handled. Hardware may be shut - * down while the provider is disabled. - */ - public abstract void disable(); - - /** - * Returns true if this provider is enabled, false otherwise; - */ - public abstract boolean isEnabled(); - - /** - * 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. - */ - public int getStatus() { - return getStatus(null); - } - - /** - * 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 getStatus(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()} each time - * 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 long getStatusUpdateTime() { - return 0; - } - - /** - * Sets a Location object with the information gathered - * during the most recent fix. - * - * @param l location object to set - * @return true if a location fix is available - */ - public abstract boolean getLocation(Location l); - - /** - * 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 void enableLocationTracking(boolean enable) { - mLocationTracking = enable; - } - - /** - * Returns true if the provider has any listeners - * - * @return true if provider is being tracked - */ - public boolean isLocationTracking() { - return mLocationTracking; - } - - /** - * 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 void setMinTime(long minTime) { - mMinTime = minTime; - } - - /** - * Gets the smallest minimum time between updates amongst all the clients listening - * for locations. By default this value is 0 (as frqeuently as possible) - * - * @return the smallest minTime value over all listeners for this provider - */ - public long getMinTime() { - return mMinTime; - } - - /** - * 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 void updateNetworkState(int state) { - } - - /** - * Updates the cell state for the given provider. This function must be - * overwritten if {@link #requiresCell} returns true. - * - * @param state cell state - */ - public void updateCellState(CellState state) { - } - - /** - * 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 sendExtraCommand(String command, Bundle extras) { - return false; - } -} diff --git a/location/java/com/android/internal/location/CellState.java b/location/java/com/android/internal/location/CellState.java deleted file mode 100644 index eb6535e..0000000 --- a/location/java/com/android/internal/location/CellState.java +++ /dev/null @@ -1,292 +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.telephony.CellLocation; -import android.telephony.TelephonyManager; -import android.telephony.NeighboringCellInfo; -import android.telephony.gsm.GsmCellLocation; -import android.util.Log; - -import com.android.internal.telephony.TelephonyProperties; - -import java.util.List; -import java.util.ArrayList; - -import android.os.SystemProperties; - -/** - * Stores the cell tower state - * - * {@hide} - */ -public class CellState { - - public static String TAG = "CellState"; - - public static int RADIO_TYPE_GPRS = 1; - public static int RADIO_TYPE_CDMA = 2; - public static int RADIO_TYPE_WCDMA = 3; - - private int mCid = -1; - private int mLac = -1; - private int mMcc = -1; - private int mMnc = -1; - private int mHomeMcc = -1; - private int mHomeMnc = -1; - private String mCarrier = null; - private int mRadioType = -1; - private long mTime = 0; - private int mSignalStrength = -1; - - private List<NeighborCell> mNeighbors; - - public CellState() { - // constructor for invalid cell location - } - - public CellState(TelephonyManager telephonyManager, CellLocation location, int signalStrength) { - GsmCellLocation loc = (GsmCellLocation)location; - mLac = loc.getLac(); // example: 6032 - mCid = loc.getCid(); // example: 31792 - mTime = System.currentTimeMillis(); - - // Get radio type - int radioType = telephonyManager.getNetworkType(); - if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || - radioType == TelephonyManager.NETWORK_TYPE_EDGE) { - mRadioType = RADIO_TYPE_GPRS; - } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { - mRadioType = RADIO_TYPE_WCDMA; - } - - // Get neighboring cells - mNeighbors = new ArrayList<NeighborCell>(); - List<NeighboringCellInfo> neighboringCells = telephonyManager.getNeighboringCellInfo(); - if (neighboringCells != null) { - for (NeighboringCellInfo n : neighboringCells) { - if (n.getCid() == NeighboringCellInfo.UNKNOWN_CID) { - continue; - } - - if (mRadioType == RADIO_TYPE_WCDMA) { - mNeighbors.add(new NeighborCell(-1, -1, n.getCid(), n.getRssi())); - } else if (mRadioType == RADIO_TYPE_GPRS) { - try { - String hexCidLac = Integer.toHexString(n.getCid()); - int l = hexCidLac.length(); - if (l > 8) { - Log.w(TAG, "Unable to parse 2G Cell \"" + hexCidLac + "\""); - continue; - } - if (l < 8) { - for (int i = 0; i < (8-l); i++) { - hexCidLac = "0" + hexCidLac; - } - } - int lac = Integer.valueOf(hexCidLac.substring(0, 4), 16); - int cid = Integer.valueOf(hexCidLac.substring(4), 16); - mNeighbors.add(new NeighborCell(cid, lac, -1, n.getRssi())); - - } catch (Exception e) { - Log.e(TAG, "Error parsing 2G Cell \"" + n.getCid() + "\"", e); - } - } - } - } - - // Get MCC/MNC - String operator = telephonyManager.getNetworkOperator(); - if (operator != null && !operator.equals("")) { - // Use a try/catch block to detect index out of bounds or number format exceptions. - // If an error occurs, both mMcc and mMnc will be equal to -1. - try { - String mcc = operator.substring(0, 3); - String mnc = operator.substring(3); - int mccTmp = Integer.parseInt(mcc); - int mncTmp = Integer.parseInt(mnc); - - // Parsing succeeded, update the instance variables together - mMcc = mccTmp; - mMnc = mncTmp; - } catch (Exception e) { - Log.e(TAG, "Error parsing MCC/MNC from operator \"" + operator + "\"", e); - } - } - - // Get Home MCC/MNC - String homeOperator = telephonyManager.getSimOperator(); - if (homeOperator != null && !homeOperator.equals("")) { - // Use a try/catch block to detect index out of bounds or number format exceptions. - // If an error occurs, both mHomeMcc and mHomeMnc will be equal to -1. - try { - String mcc = homeOperator.substring(0, 3); - String mnc = homeOperator.substring(3); - int mccTmp = Integer.parseInt(mcc); - int mncTmp = Integer.parseInt(mnc); - - // Parsing succeeded, update the instance variables together - mHomeMcc = mccTmp; - mHomeMnc = mncTmp; - } catch (Exception e) { - Log.e(TAG, "Error parsing MCC/MNC from home operator \"" + homeOperator + "\"", e); - } - } - - // Get Carrier - String carrier = telephonyManager.getNetworkOperatorName(); - if (carrier != null && !carrier.equals("")) { - mCarrier = carrier; - } - - // Initial signal strength - mSignalStrength = signalStrength; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - String neighbors = "["; - for (NeighborCell n : mNeighbors) { - neighbors += n.toString() + ","; - } - neighbors += "]"; - Log.d(TAG, "CellState(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength + "," + neighbors); - } - } - - public void updateRadioType(int radioType) { - mRadioType = radioType; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, "updateRadioType(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength); - } - } - - public void updateSignalStrength(int signalStrength) { - mSignalStrength = signalStrength; - - if (Log.isLoggable(TAG, Log.VERBOSE)) { - Log.d(TAG, "updateSignal(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + - mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + - mSignalStrength); - } - } - - public int getCid() { - return mCid; - } - - public int getLac() { - return mLac; - } - - public int getMcc() { - return mMcc; - } - - public int getMnc() { - return mMnc; - } - - public int getHomeMcc() { - return mHomeMcc; - } - - public void setHomeMcc(int homeMcc) { - this.mHomeMcc = homeMcc; - } - - public int getHomeMnc() { - return mHomeMnc; - } - - public void setHomeMnc(int homeMnc) { - this.mHomeMnc = homeMnc; - } - - public String getCarrier() { - return mCarrier; - } - - public void setCarrier(String carrier) { - this.mCarrier = carrier; - } - - public int getRadioType() { - return mRadioType; - } - - public long getTime() { - return mTime; - } - - public int getSignalStrength() { - return mSignalStrength; - } - - public List<NeighborCell> getNeighbors() { - return mNeighbors; - } - - public boolean equals(CellState other) { - return (mCid == other.mCid && mLac == other.mLac); - } - - public boolean isValid() { - return (mCid != -1 && mLac != -1); - } - - public static class NeighborCell { - private int mCid = -1; - private int mLac = -1; - private int mPsc = -1; - private int mRssi = -1; - - NeighborCell(int cid, int lac, int psc, int rssi) { - mCid = cid; - mLac = lac; - mPsc = psc; - mRssi = rssi; - } - - public int getCid() { - return mCid; - } - - public int getLac() { - return mLac; - } - - public int getPsc() { - return mPsc; - } - - public int getRssi() { - return mRssi; - } - - public String toString() { - if (mPsc != -1) { - return String.valueOf(mPsc) + "@" + mRssi; - } else { - return mCid + ":" + mLac + "@" + mRssi; - } - } - } -} diff --git a/location/java/android/location/DummyLocationProvider.java b/location/java/com/android/internal/location/DummyLocationProvider.java index e1cd4e9..ff5e27b 100644 --- a/location/java/android/location/DummyLocationProvider.java +++ b/location/java/com/android/internal/location/DummyLocationProvider.java @@ -14,7 +14,9 @@ * limitations under the License. */ -package android.location; +package com.android.internal.location; + +import android.location.LocationProvider; /** * A stub implementation of LocationProvider used by LocationManager. @@ -24,7 +26,7 @@ package android.location; * * {@hide} */ -class DummyLocationProvider extends LocationProvider { +public class DummyLocationProvider extends LocationProvider { private static final String TAG = "DummyLocationProvider"; @@ -39,7 +41,7 @@ class DummyLocationProvider extends LocationProvider { int mPowerRequirement; int mAccuracy; - /* package */ DummyLocationProvider(String name) { + public DummyLocationProvider(String name) { super(name); } diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index 887574a..565859c 100644 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -16,24 +16,33 @@ package com.android.internal.location; +import android.app.AlarmManager; +import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Criteria; import android.location.IGpsStatusListener; +import android.location.IGpsStatusProvider; +import android.location.ILocationManager; +import android.location.ILocationProvider; import android.location.Location; import android.location.LocationManager; import android.location.LocationProvider; -import android.location.LocationProviderImpl; +import android.net.ConnectivityManager; import android.net.SntpClient; import android.os.Bundle; import android.os.IBinder; +import android.os.PowerManager; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.util.Config; import android.util.Log; +import android.util.SparseIntArray; +import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.Phone; import com.android.internal.telephony.TelephonyIntents; @@ -50,9 +59,12 @@ import java.util.Properties; * * {@hide} */ -public class GpsLocationProvider extends LocationProviderImpl { +public class GpsLocationProvider extends ILocationProvider.Stub { private static final String TAG = "GpsLocationProvider"; + + private static final boolean DEBUG = true; + private static final boolean VERBOSE = false; /** * Broadcast intent action indicating that the GPS has either been @@ -97,6 +109,14 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int GPS_STATUS_ENGINE_ON = 3; private static final int GPS_STATUS_ENGINE_OFF = 4; + // these need to match GpsApgsStatusValue defines in gps.h + /** AGPS status event values. */ + private static final int GPS_REQUEST_AGPS_DATA_CONN = 1; + private static final int GPS_RELEASE_AGPS_DATA_CONN = 2; + private static final int GPS_AGPS_DATA_CONNECTED = 3; + private static final int GPS_AGPS_DATA_CONN_DONE = 4; + private static final int GPS_AGPS_DATA_CONN_FAILED = 5; + // these need to match GpsLocationFlags enum in gps.h private static final int LOCATION_INVALID = 0; private static final int LOCATION_HAS_LAT_LONG = 1; @@ -104,8 +124,8 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int LOCATION_HAS_SPEED = 4; private static final int LOCATION_HAS_BEARING = 8; private static final int LOCATION_HAS_ACCURACY = 16; - -// IMPORTANT - the GPS_DELETE_* symbols here must match constants in GpsLocationProvider.java + +// IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h private static final int GPS_DELETE_EPHEMERIS = 0x0001; private static final int GPS_DELETE_ALMANAC = 0x0002; private static final int GPS_DELETE_POSITION = 0x0004; @@ -120,23 +140,36 @@ public class GpsLocationProvider extends LocationProviderImpl { private static final int GPS_DELETE_CELLDB_INFO = 0x8000; private static final int GPS_DELETE_ALL = 0xFFFF; + // these need to match AGpsType enum in gps.h + private static final int AGPS_TYPE_SUPL = 1; + private static final int AGPS_TYPE_C2K = 2; + + // for mAGpsDataConnectionState + private static final int AGPS_DATA_CONNECTION_CLOSED = 0; + private static final int AGPS_DATA_CONNECTION_OPENING = 1; + private static final int AGPS_DATA_CONNECTION_OPEN = 2; + private static final String PROPERTIES_FILE = "/etc/gps.conf"; private int mLocationFlags = LOCATION_INVALID; // current status - private int mStatus = TEMPORARILY_UNAVAILABLE; + private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE; // time for last status update private long mStatusUpdateTime = SystemClock.elapsedRealtime(); // turn off GPS fix icon if we haven't received a fix in 10 seconds - private static final long RECENT_FIX_TIMEOUT = 10 * 1000; + private static final long RECENT_FIX_TIMEOUT = 10; + + // number of fixes to receive before disabling GPS + private static final int MIN_FIX_COUNT = 10; + + // stop trying if we do not receive a fix within 60 seconds + private static final int NO_FIX_TIMEOUT = 60; // true if we are enabled private boolean mEnabled; - // true if we are enabled for location updates - private boolean mLocationTracking; // true if we have network connectivity private boolean mNetworkAvailable; @@ -147,6 +180,9 @@ public class GpsLocationProvider extends LocationProviderImpl { // requested frequency of fixes, in seconds private int mFixInterval = 1; + // number of fixes we have received since we started navigating + private int mFixCount; + private int mPositionMode = GPS_POSITION_MODE_STANDALONE; // true if we started navigation @@ -163,7 +199,8 @@ public class GpsLocationProvider extends LocationProviderImpl { private Properties mProperties; private String mNtpServer; - private Context mContext; + private final Context mContext; + private final ILocationManager mLocationManager; private Location mLocation = new Location(LocationManager.GPS_PROVIDER); private Bundle mLocationExtras = new Bundle(); private ArrayList<Listener> mListeners = new ArrayList<Listener>(); @@ -173,7 +210,27 @@ public class GpsLocationProvider extends LocationProviderImpl { private String mSuplHost; private int mSuplPort; + private String mC2KHost; + private int mC2KPort; private boolean mSetSuplServer; + private boolean mSetC2KServer; + private String mAGpsApn; + private int mAGpsDataConnectionState; + private final ConnectivityManager mConnMgr; + + // Wakelocks + private final static String WAKELOCK_KEY = "GpsLocationProvider"; + private final PowerManager.WakeLock mWakeLock; + + // Alarms + private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP"; + private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT"; + private final AlarmManager mAlarmManager; + private final PendingIntent mWakeupIntent; + private final PendingIntent mTimeoutIntent; + + private final IBatteryStats mBatteryStats; + private final SparseIntArray mClientUids = new SparseIntArray(); // how often to request NTP time, in milliseconds // current setting 4 hours @@ -182,13 +239,68 @@ public class GpsLocationProvider extends LocationProviderImpl { // current setting - 5 minutes private static final long RETRY_INTERVAL = 5*60*1000; - private ILocationCollector mCollector; + private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() { + public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { + if (listener == null) { + throw new NullPointerException("listener is null in addGpsStatusListener"); + } + + synchronized(mListeners) { + IBinder binder = listener.asBinder(); + int size = mListeners.size(); + for (int i = 0; i < size; i++) { + Listener test = mListeners.get(i); + if (binder.equals(test.mListener.asBinder())) { + // listener already added + return; + } + } + + Listener l = new Listener(listener); + binder.linkToDeath(l, 0); + mListeners.add(l); + } + } + + public void removeGpsStatusListener(IGpsStatusListener listener) { + if (listener == null) { + throw new NullPointerException("listener is null in addGpsStatusListener"); + } + + synchronized(mListeners) { + IBinder binder = listener.asBinder(); + Listener l = null; + int size = mListeners.size(); + for (int i = 0; i < size && l == null; i++) { + Listener test = mListeners.get(i); + if (binder.equals(test.mListener.asBinder())) { + l = test; + } + } + + if (l != null) { + mListeners.remove(l); + binder.unlinkToDeath(l, 0); + } + } + } + }; + + public IGpsStatusProvider getGpsStatusProvider() { + return mGpsStatusProvider; + } - private class TelephonyBroadcastReceiver extends BroadcastReceiver { + private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { + if (action.equals(ALARM_WAKEUP)) { + if (DEBUG) Log.d(TAG, "ALARM_WAKEUP"); + startNavigating(); + } else if (action.equals(ALARM_TIMEOUT)) { + if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT"); + hibernate(); + } else if (action.equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { String state = intent.getStringExtra(Phone.STATE_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); @@ -196,27 +308,44 @@ public class GpsLocationProvider extends LocationProviderImpl { if (Config.LOGD) { Log.d(TAG, "state: " + state + " apnName: " + apnName + " reason: " + reason); } - if ("CONNECTED".equals(state)) { - native_set_supl_apn(apnName); - } else { - native_set_supl_apn(""); + // FIXME - might not have an APN on CDMA + if ("CONNECTED".equals(state) && apnName != null && apnName.length() > 0) { + mAGpsApn = apnName; + if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) { + native_agps_data_conn_open(mAGpsApn); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; + } } } } - } + }; public static boolean isSupported() { return native_is_supported(); } - public GpsLocationProvider(Context context) { - super(LocationManager.GPS_PROVIDER); + public GpsLocationProvider(Context context, ILocationManager locationManager) { mContext = context; + mLocationManager = locationManager; + + // Create a wake lock + PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY); + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0); + mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0); - TelephonyBroadcastReceiver receiver = new TelephonyBroadcastReceiver(); IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(ALARM_WAKEUP); + intentFilter.addAction(ALARM_TIMEOUT); intentFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - context.registerReceiver(receiver, intentFilter); + context.registerReceiver(mBroadcastReciever, intentFilter); + + mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE); + + // Battery statistics service to be notified when GPS turns on or off + mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo")); mProperties = new Properties(); try { @@ -225,14 +354,26 @@ public class GpsLocationProvider extends LocationProviderImpl { mProperties.load(stream); stream.close(); mNtpServer = mProperties.getProperty("NTP_SERVER", null); + mSuplHost = mProperties.getProperty("SUPL_HOST"); - String suplPortString = mProperties.getProperty("SUPL_PORT"); - if (mSuplHost != null && suplPortString != null) { + String portString = mProperties.getProperty("SUPL_PORT"); + if (mSuplHost != null && portString != null) { try { - mSuplPort = Integer.parseInt(suplPortString); + mSuplPort = Integer.parseInt(portString); mSetSuplServer = true; } catch (NumberFormatException e) { - Log.e(TAG, "unable to parse SUPL_PORT: " + suplPortString); + Log.e(TAG, "unable to parse SUPL_PORT: " + portString); + } + } + + mC2KHost = mProperties.getProperty("C2K_HOST"); + portString = mProperties.getProperty("C2K_PORT"); + if (mC2KHost != null && portString != null) { + try { + mC2KPort = Integer.parseInt(portString); + mSetC2KServer = true; + } catch (NumberFormatException e) { + Log.e(TAG, "unable to parse C2K_PORT: " + portString); } } } catch (IOException e) { @@ -240,19 +381,15 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - public void setLocationCollector(ILocationCollector collector) { - mCollector = collector; - } - /** * Returns true if the provider requires access to a * data network (e.g., the Internet), false otherwise. */ - @Override public boolean requiresNetwork() { // We want updateNetworkState() to get called when the network state changes // for XTRA and NTP time injection support. - return (mNtpServer != null || native_supports_xtra() || mSuplHost != null); + return (mNtpServer != null || native_supports_xtra() || + mSuplHost != null || mC2KHost != null); } public void updateNetworkState(int state) { @@ -273,7 +410,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * satellite-based positioning system (e.g., GPS), false * otherwise. */ - @Override public boolean requiresSatellite() { return true; } @@ -283,7 +419,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * cellular network (e.g., to make use of cell tower IDs), false * otherwise. */ - @Override public boolean requiresCell() { return false; } @@ -293,7 +428,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * 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 false; } @@ -304,7 +438,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsAltitude() { return true; } @@ -315,7 +448,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsSpeed() { return true; } @@ -326,7 +458,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * under most circumstances but may occassionally not report it * should return true. */ - @Override public boolean supportsBearing() { return true; } @@ -337,7 +468,6 @@ public class GpsLocationProvider extends LocationProviderImpl { * @return the power requirement for this provider, as one of the * constants Criteria.POWER_REQUIREMENT_*. */ - @Override public int getPowerRequirement() { return Criteria.POWER_HIGH; } @@ -348,17 +478,15 @@ public class GpsLocationProvider extends LocationProviderImpl { * @return the accuracy of location from this provider, as one * of the constants Criteria.ACCURACY_*. */ - @Override public int getAccuracy() { return Criteria.ACCURACY_FINE; } /** * Enables this provider. When enabled, calls to getStatus() - * and getLocation() must be handled. Hardware may be started up + * must be handled. Hardware may be started up * when the provider is enabled. */ - @Override public synchronized void enable() { if (Config.LOGD) Log.d(TAG, "enable"); if (mEnabled) return; @@ -385,10 +513,9 @@ public class GpsLocationProvider extends LocationProviderImpl { /** * Disables this provider. When disabled, calls to getStatus() - * and getLocation() need not be handled. Hardware may be shut + * need not be handled. Hardware may be shut * down while the provider is disabled. */ - @Override public synchronized void disable() { if (Config.LOGD) Log.d(TAG, "disable"); if (!mEnabled) return; @@ -412,15 +539,19 @@ public class GpsLocationProvider extends LocationProviderImpl { mNetworkThread = null; } + // The GpsEventThread does not wait for the GPS to shutdown + // so we need to report the GPS_STATUS_ENGINE_OFF event here + if (mNavigating) { + reportStatus(GPS_STATUS_ENGINE_OFF); + } + native_cleanup(); } - @Override public boolean isEnabled() { return mEnabled; } - @Override public int getStatus(Bundle extras) { if (extras != null) { extras.putInt("satellites", mSvCount); @@ -437,49 +568,23 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - @Override public long getStatusUpdateTime() { return mStatusUpdateTime; } - @Override - public boolean getLocation(Location l) { - synchronized (mLocation) { - // don't report locations without latitude and longitude - if ((mLocationFlags & LOCATION_HAS_LAT_LONG) == 0) { - return false; - } - l.set(mLocation); - l.setExtras(mLocationExtras); - return true; - } - } - - @Override public void enableLocationTracking(boolean enable) { - if (mLocationTracking == enable) { - return; - } - if (enable) { - mFixRequestTime = System.currentTimeMillis(); mTTFF = 0; mLastFixTime = 0; startNavigating(); } else { + mAlarmManager.cancel(mWakeupIntent); + mAlarmManager.cancel(mTimeoutIntent); stopNavigating(); } - mLocationTracking = enable; - } - - @Override - public boolean isLocationTracking() { - return mLocationTracking; } - @Override public void setMinTime(long minTime) { - super.setMinTime(minTime); if (Config.LOGD) Log.d(TAG, "setMinTime " + minTime); if (minTime >= 0) { @@ -488,7 +593,6 @@ public class GpsLocationProvider extends LocationProviderImpl { interval = 1; } mFixInterval = interval; - native_set_fix_frequency(mFixInterval); } } @@ -510,48 +614,28 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException { - if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); - - synchronized(mListeners) { - IBinder binder = listener.asBinder(); - int size = mListeners.size(); - for (int i = 0; i < size; i++) { - Listener test = mListeners.get(i); - if (binder.equals(test.mListener.asBinder())) { - // listener already added - return; - } + public void addListener(int uid) { + mClientUids.put(uid, 0); + if (mNavigating) { + try { + mBatteryStats.noteStartGps(uid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in addListener"); } - - Listener l = new Listener(listener); - binder.linkToDeath(l, 0); - mListeners.add(l); } } - - public void removeGpsStatusListener(IGpsStatusListener listener) { - if (listener == null) throw new NullPointerException("listener is null in addGpsStatusListener"); - synchronized(mListeners) { - IBinder binder = listener.asBinder(); - Listener l = null; - int size = mListeners.size(); - for (int i = 0; i < size && l == null; i++) { - Listener test = mListeners.get(i); - if (binder.equals(test.mListener.asBinder())) { - l = test; - } - } - - if (l != null) { - mListeners.remove(l); - binder.unlinkToDeath(l, 0); + public void removeListener(int uid) { + mClientUids.delete(uid); + if (mNavigating) { + try { + mBatteryStats.noteStopGps(uid); + } catch (RemoteException e) { + Log.w(TAG, "RemoteException in removeListener"); } } } - @Override public boolean sendExtraCommand(String command, Bundle extras) { if ("delete_aiding_data".equals(command)) { @@ -594,20 +678,29 @@ public class GpsLocationProvider extends LocationProviderImpl { public void startNavigating() { if (!mStarted) { - if (Config.LOGV) Log.v(TAG, "startNavigating"); + if (DEBUG) Log.d(TAG, "startNavigating"); mStarted = true; if (!native_start(mPositionMode, false, mFixInterval)) { mStarted = false; Log.e(TAG, "native_start failed in startNavigating()"); + return; } // reset SV count to zero - updateStatus(TEMPORARILY_UNAVAILABLE, 0); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); + mFixCount = 0; + mFixRequestTime = System.currentTimeMillis(); + // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT + // and our fix interval is not short + if (mFixInterval >= NO_FIX_TIMEOUT) { + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT * 1000, mTimeoutIntent); + } } } public void stopNavigating() { - if (Config.LOGV) Log.v(TAG, "stopNavigating"); + if (DEBUG) Log.d(TAG, "stopNavigating"); if (mStarted) { mStarted = false; native_stop(); @@ -616,16 +709,27 @@ public class GpsLocationProvider extends LocationProviderImpl { mLocationFlags = LOCATION_INVALID; // reset SV count to zero - updateStatus(TEMPORARILY_UNAVAILABLE, 0); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0); } } + private void hibernate() { + // stop GPS until our next fix interval arrives + stopNavigating(); + mFixCount = 0; + mAlarmManager.cancel(mTimeoutIntent); + mAlarmManager.cancel(mWakeupIntent); + long now = SystemClock.elapsedRealtime(); + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + mFixInterval * 1000, mWakeupIntent); + } + /** * called from native code to update our position. */ private void reportLocation(int flags, double latitude, double longitude, double altitude, float speed, float bearing, float accuracy, long timestamp) { - if (Config.LOGV) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + + if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude + " timestamp: " + timestamp); mLastFixTime = System.currentTimeMillis(); @@ -679,19 +783,25 @@ public class GpsLocationProvider extends LocationProviderImpl { mLocation.removeAccuracy(); } - // Send to collector - if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG - && mCollector != null) { - mCollector.updateLocation(mLocation); + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling reportLocation"); } } - if (mStarted && mStatus != AVAILABLE) { + if (mStarted && mStatus != LocationProvider.AVAILABLE) { + 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); mContext.sendBroadcast(intent); - updateStatus(AVAILABLE, mSvCount); + updateStatus(LocationProvider.AVAILABLE, mSvCount); + } + + if (mFixCount++ >= MIN_FIX_COUNT && mFixInterval > 1) { + if (DEBUG) Log.d(TAG, "exceeded MIN_FIX_COUNT"); + hibernate(); } } @@ -699,12 +809,16 @@ public class GpsLocationProvider extends LocationProviderImpl { * called from native code to update our status */ private void reportStatus(int status) { - if (Config.LOGV) Log.v(TAG, "reportStatus status: " + status); + if (VERBOSE) Log.v(TAG, "reportStatus status: " + status); boolean wasNavigating = mNavigating; mNavigating = (status == GPS_STATUS_SESSION_BEGIN); if (wasNavigating != mNavigating) { + if (mNavigating) { + if (DEBUG) Log.d(TAG, "Acquiring wakelock"); + mWakeLock.acquire(); + } synchronized(mListeners) { int size = mListeners.size(); for (int i = 0; i < size; i++) { @@ -724,10 +838,29 @@ public class GpsLocationProvider extends LocationProviderImpl { } } + 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(GPS_ENABLED_CHANGE_ACTION); intent.putExtra(EXTRA_ENABLED, mNavigating); mContext.sendBroadcast(intent); + + if (!mNavigating) { + if (DEBUG) Log.d(TAG, "Releasing wakelock"); + mWakeLock.release(); + } } } @@ -755,12 +888,12 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - if (Config.LOGD) { - if (Config.LOGV) Log.v(TAG, "SV count: " + svCount + + if (VERBOSE) { + Log.v(TAG, "SV count: " + svCount + " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) + " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK])); for (int i = 0; i < svCount; i++) { - if (Config.LOGV) Log.v(TAG, "sv: " + mSvs[i] + + Log.v(TAG, "sv: " + mSvs[i] + " snr: " + (float)mSnrs[i]/10 + " elev: " + mSvElevations[i] + " azimuth: " + mSvAzimuths[i] + @@ -772,16 +905,53 @@ public class GpsLocationProvider extends LocationProviderImpl { updateStatus(mStatus, svCount); - if (mNavigating && mStatus == AVAILABLE && mLastFixTime > 0 && - System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) { + if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 && + System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT * 1000) { // send an intent to notify that the GPS is no longer receiving fixes. Intent intent = new Intent(GPS_FIX_CHANGE_ACTION); intent.putExtra(EXTRA_ENABLED, false); mContext.sendBroadcast(intent); - updateStatus(TEMPORARILY_UNAVAILABLE, mSvCount); + updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount); } } - + + /** + * called from native code to update AGPS status + */ + private void reportAGpsStatus(int type, int status) { + switch (status) { + case GPS_REQUEST_AGPS_DATA_CONN: + int result = mConnMgr.startUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); + if (result == Phone.APN_ALREADY_ACTIVE) { + native_agps_data_conn_open(mAGpsApn); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN; + } else if (result == Phone.APN_REQUEST_STARTED) { + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING; + } else { + native_agps_data_conn_failed(); + } + break; + case GPS_RELEASE_AGPS_DATA_CONN: + if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) { + mConnMgr.stopUsingNetworkFeature( + ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL); + native_agps_data_conn_closed(); + mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED; + } + break; + case GPS_AGPS_DATA_CONNECTED: + // Log.d(TAG, "GPS_AGPS_DATA_CONNECTED"); + break; + case GPS_AGPS_DATA_CONN_DONE: + // Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE"); + break; + case GPS_AGPS_DATA_CONN_FAILED: + // Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED"); + break; + } + } + private void xtraDownloadRequest() { if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest"); if (mNetworkThread != null) { @@ -789,6 +959,29 @@ public class GpsLocationProvider extends LocationProviderImpl { } } + private boolean setAGpsServer(int type, String host, int port) { + try { + InetAddress inetAddress = InetAddress.getByName(host); + if (inetAddress != null) { + byte[] addrBytes = inetAddress.getAddress(); + long addr = 0; + for (int i = 0; i < addrBytes.length; i++) { + int temp = addrBytes[i]; + // signed -> unsigned + if (temp < 0) temp = 256 + temp; + addr = addr * 256 + temp; + } + // use MS-Based position mode if SUPL support is enabled + mPositionMode = GPS_POSITION_MODE_MS_BASED; + native_set_agps_server(type, (int)addr, port); + } + } catch (UnknownHostException e) { + Log.e(TAG, "unknown host for server " + host); + return false; + } + return true; + } + private class GpsEventThread extends Thread { public GpsEventThread() { @@ -797,8 +990,8 @@ public class GpsLocationProvider extends LocationProviderImpl { public void run() { if (Config.LOGD) Log.d(TAG, "GpsEventThread starting"); - // thread exits after disable() is called and navigation has stopped - while (mEnabled || mNavigating) { + // 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(); @@ -860,7 +1053,8 @@ public class GpsLocationProvider extends LocationProviderImpl { } } waitTime = getWaitTime(); - } while (!mDone && ((!mXtraDownloadRequested && !mSetSuplServer && waitTime > 0) + } while (!mDone && ((!mXtraDownloadRequested && + !mSetSuplServer && !mSetC2KServer && waitTime > 0) || !mNetworkAvailable)); if (Config.LOGD) Log.d(TAG, "NetworkThread out of wake loop"); @@ -887,26 +1081,15 @@ public class GpsLocationProvider extends LocationProviderImpl { } } - // Set the SUPL server address if we have not yet + // Set the AGPS server addresses if we have not yet if (mSetSuplServer) { - try { - InetAddress inetAddress = InetAddress.getByName(mSuplHost); - if (inetAddress != null) { - byte[] addrBytes = inetAddress.getAddress(); - long addr = 0; - for (int i = 0; i < addrBytes.length; i++) { - int temp = addrBytes[i]; - // signed -> unsigned - if (temp < 0) temp = 256 + temp; - addr = addr * 256 + temp; - } - // use MS-Based position mode if SUPL support is enabled - mPositionMode = GPS_POSITION_MODE_MS_BASED; - native_set_supl_server((int)addr, mSuplPort); - mSetSuplServer = false; - } - } catch (UnknownHostException e) { - Log.e(TAG, "unknown host for SUPL server " + mSuplHost); + if (setAGpsServer(AGPS_TYPE_SUPL, mSuplHost, mSuplPort)) { + mSetSuplServer = false; + } + } + if (mSetC2KServer) { + if (setAGpsServer(AGPS_TYPE_C2K, mC2KHost, mC2KPort)) { + mSetC2KServer = false; } } @@ -1000,7 +1183,9 @@ public class GpsLocationProvider extends LocationProviderImpl { private native boolean native_supports_xtra(); private native void native_inject_xtra_data(byte[] data, int length); - // SUPL Support - private native void native_set_supl_server(int addr, int port); - private native void native_set_supl_apn(String apn); + // 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(); + private native void native_set_agps_server(int type, int addr, int port); } diff --git a/location/java/com/android/internal/location/GpsXtraDownloader.java b/location/java/com/android/internal/location/GpsXtraDownloader.java index b8545a6..2a8be57 100644 --- a/location/java/com/android/internal/location/GpsXtraDownloader.java +++ b/location/java/com/android/internal/location/GpsXtraDownloader.java @@ -70,11 +70,11 @@ public class GpsXtraDownloader { if (server1 != null) mXtraServers[count++] = server1; if (server2 != null) mXtraServers[count++] = server2; if (server3 != null) mXtraServers[count++] = server3; - } - - // randomize first server - Random random = new Random(); - mNextServerIndex = random.nextInt(count); + + // randomize first server + Random random = new Random(); + mNextServerIndex = random.nextInt(count); + } } byte[] downloadXtraData() { diff --git a/location/java/com/android/internal/location/ILocationCollector.java b/location/java/com/android/internal/location/ILocationCollector.java deleted file mode 100644 index 8a7cdcc..0000000 --- a/location/java/com/android/internal/location/ILocationCollector.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2009 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.Location; -import android.net.wifi.ScanResult; - -import com.android.internal.location.CellState; - -import java.util.List; - -/** - * Listens for GPS and cell/wifi changes and anonymously uploads to server for - * improving quality of service of NetworkLocationProvider. This service is only enabled when - * the user has enabled the network location provider. - * - * {@hide} - */ -public interface ILocationCollector { - /** - * Updates GPS location if collection is enabled - * - * @param location location object - */ - abstract public void updateLocation(Location location); - - /** - * Updates wifi scan results if collection is enabled - * - * @param currentScanResults scan results - */ - abstract public void updateWifiScanResults(List<ScanResult> currentScanResults); - - /** - * Updates the status of the network location provider. - * - * @param enabled true if user has enabled network location based on Google's database - * of wifi points and cell towers. - */ - abstract public void updateNetworkProviderStatus(boolean enabled); - - /** - * Updates cell tower state. This is usually always up to date so should be uploaded - * each time a new location is available. - * - * @param newState cell state - */ - abstract public void updateCellState(CellState newState); - - /** - * Updates the battery health. Battery level is healthy if there is greater than - * {@link #MIN_BATTERY_LEVEL} percentage left or if the device is plugged in - * - * @param scale maximum scale for battery - * @param level current level - * @param plugged true if device is plugged in - */ - abstract public void updateBatteryState(int scale, int level, boolean plugged); -} diff --git a/location/java/com/android/internal/location/INetworkLocationProvider.java b/location/java/com/android/internal/location/INetworkLocationProvider.java deleted file mode 100644 index 730cb48..0000000 --- a/location/java/com/android/internal/location/INetworkLocationProvider.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2009 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.Address; -import android.location.Location; -import android.net.wifi.ScanResult; - -import com.google.common.io.protocol.ProtoBuf; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Locale; - -/** - * Interface for network location provider - * - * {@hide} - */ -public interface INetworkLocationProvider { - - public interface Callback { - - /** - * Callback function to notify of a received network location - * - * @param location location object that is received. may be null if not a valid location - * @param successful true if network query was successful, even if no location was found - */ - void locationReceived(Location location, boolean successful); - } - - /** - * Updates the current cell lock status. - * - * @param acquired true if a cell lock has been acquired - */ - abstract public void updateCellLockStatus(boolean acquired); - - /** - * Notifies the provider if Wifi has been enabled or disabled - * by the user - * - * @param enabled true if wifi is enabled; false otherwise - */ - abstract public void updateWifiEnabledState(boolean enabled); - - /** - * Notifies the provider that there are scan results available. - * - * @param scanResults list of wifi scan results - */ - abstract public void updateWifiScanResults(List<ScanResult> scanResults); - - /** - * Adds a list of application clients - * Only used by the NetworkLocationProvider - * - * @param applications list of package names - */ - abstract public void addListener(String[] applications); - - /** - * Removes a list of application clients - * Only used by the NetworkLocationProvider - * - * @param applications list of package names - */ - abstract public void removeListener(String[] applications); - - - abstract public String getFromLocation(double latitude, double longitude, int maxResults, - String language, String country, String variant, String appName, List<Address> addrs); - - abstract public String getFromLocationName(String locationName, - double lowerLeftLatitude, double lowerLeftLongitude, - double upperRightLatitude, double upperRightLongitude, int maxResults, - String language, String country, String variant, String appName, List<Address> addrs); - -} diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java new file mode 100644 index 0000000..b40cdca --- /dev/null +++ b/location/java/com/android/internal/location/LocationProviderProxy.java @@ -0,0 +1,251 @@ +/* + * Copyright (C) 2009 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.Address; +import android.location.ILocationProvider; +import android.location.Location; +import android.location.LocationManager; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.util.Log; + +import java.util.List; + +/** + * A class for proxying remote ILocationProvider implementations. + * + * {@hide} + */ +public class LocationProviderProxy implements IBinder.DeathRecipient { + + private static final String TAG = "LocationProviderProxy"; + + private final String mName; + private final ILocationProvider mProvider; + private boolean mLocationTracking = false; + private long mMinTime = 0; + private boolean mDead; + + public LocationProviderProxy(String name, ILocationProvider provider) { + mName = name; + mProvider = provider; + try { + provider.asBinder().linkToDeath(this, 0); + } catch (RemoteException e) { + Log.e(TAG, "linkToDeath failed", e); + mDead = true; + } + } + + 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); + return false; + } + } + + public boolean requiresSatellite() { + try { + return mProvider.requiresSatellite(); + } catch (RemoteException e) { + Log.e(TAG, "requiresSatellite failed", e); + return false; + } + } + + public boolean requiresCell() { + try { + return mProvider.requiresCell(); + } catch (RemoteException e) { + Log.e(TAG, "requiresCell failed", e); + return false; + } + } + + public boolean hasMonetaryCost() { + try { + return mProvider.hasMonetaryCost(); + } catch (RemoteException e) { + Log.e(TAG, "hasMonetaryCost failed", e); + return false; + } + } + + public boolean supportsAltitude() { + try { + return mProvider.supportsAltitude(); + } catch (RemoteException e) { + Log.e(TAG, "supportsAltitude failed", e); + return false; + } + } + + public boolean supportsSpeed() { + try { + return mProvider.supportsSpeed(); + } catch (RemoteException e) { + Log.e(TAG, "supportsSpeed failed", e); + return false; + } + } + + public boolean supportsBearing() { + try { + return mProvider.supportsBearing(); + } catch (RemoteException e) { + Log.e(TAG, "supportsBearing failed", e); + return false; + } + } + + public int getPowerRequirement() { + try { + return mProvider.getPowerRequirement(); + } catch (RemoteException e) { + Log.e(TAG, "getPowerRequirement failed", e); + return 0; + } + } + + public int getAccuracy() { + try { + return mProvider.getAccuracy(); + } catch (RemoteException e) { + Log.e(TAG, "getAccuracy failed", e); + return 0; + } + } + + public void enable() { + try { + mProvider.enable(); + } catch (RemoteException e) { + Log.e(TAG, "enable failed", e); + } + } + + public void disable() { + try { + mProvider.disable(); + } catch (RemoteException e) { + Log.e(TAG, "disable failed", e); + } + } + + public boolean isEnabled() { + try { + return mProvider.isEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "isEnabled failed", e); + return false; + } + } + + public int getStatus(Bundle extras) { + try { + return mProvider.getStatus(extras); + } catch (RemoteException e) { + Log.e(TAG, "getStatus failed", e); + return 0; + } + } + + public long getStatusUpdateTime() { + try { + return mProvider.getStatusUpdateTime(); + } catch (RemoteException e) { + Log.e(TAG, "getStatusUpdateTime failed", e); + return 0; + } + } + + public boolean isLocationTracking() { + return mLocationTracking; + } + + public void enableLocationTracking(boolean enable) { + mLocationTracking = enable; + try { + mProvider.enableLocationTracking(enable); + } catch (RemoteException e) { + Log.e(TAG, "enableLocationTracking failed", e); + } + } + + public long getMinTime() { + return mMinTime; + } + + public void setMinTime(long minTime) { + mMinTime = minTime; + try { + mProvider.setMinTime(minTime); + } catch (RemoteException e) { + Log.e(TAG, "setMinTime failed", e); + } + } + + public void updateNetworkState(int state) { + try { + mProvider.updateNetworkState(state); + } catch (RemoteException e) { + Log.e(TAG, "updateNetworkState failed", 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; + } + } + + public void addListener(int uid) { + try { + mProvider.addListener(uid); + } catch (RemoteException e) { + Log.e(TAG, "addListener failed", e); + } + } + + public void removeListener(int uid) { + try { + mProvider.removeListener(uid); + } catch (RemoteException e) { + Log.e(TAG, "removeListener failed", e); + } + } + + public void binderDied() { + Log.w(TAG, "Location Provider " + mName + " died"); + mDead = true; + } +} diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java new file mode 100644 index 0000000..f167a44 --- /dev/null +++ b/location/java/com/android/internal/location/MockProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2009 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.ILocationProvider; +import android.location.Location; +import android.location.LocationProvider; +import android.os.Bundle; +import android.os.RemoteException; +import android.util.Log; +import android.util.PrintWriterPrinter; + +import java.io.PrintWriter; + +/** + * A mock location provider used by LocationManagerService to implement test providers. + * + * {@hide} + */ +public class MockProvider extends ILocationProvider.Stub { + private final String mName; + 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 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) { + mName = name; + mLocationManager = locationManager; + mRequiresNetwork = requiresNetwork; + mRequiresSatellite = requiresSatellite; + mRequiresCell = requiresCell; + mHasMonetaryCost = hasMonetaryCost; + mSupportsAltitude = supportsAltitude; + mSupportsBearing = supportsBearing; + mSupportsSpeed = supportsSpeed; + mPowerRequirement = powerRequirement; + mAccuracy = accuracy; + mLocation = new Location(name); + } + + public void disable() { + mEnabled = false; + } + + public void enable() { + mEnabled = true; + } + + public int getStatus(Bundle extras) { + if (mHasStatus) { + extras.clear(); + extras.putAll(mExtras); + return mStatus; + } else { + return LocationProvider.AVAILABLE; + } + } + + public long getStatusUpdateTime() { + return mStatusUpdateTime; + } + + public boolean isEnabled() { + return mEnabled; + } + + 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 void setLocation(Location l) { + mLocation.set(l); + mHasLocation = true; + try { + mLocationManager.reportLocation(mLocation); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling reportLocation"); + } + } + + public void clearLocation() { + mHasLocation = false; + } + + public void setStatus(int status, Bundle extras, long updateTime) { + mStatus = status; + mStatusUpdateTime = updateTime; + mExtras.clear(); + if (extras != null) { + mExtras.putAll(extras); + } + mHasStatus = true; + } + + public void clearStatus() { + mHasStatus = false; + mStatusUpdateTime = 0; + } + + public void enableLocationTracking(boolean enable) { + } + + public void setMinTime(long minTime) { + } + + public void updateNetworkState(int state) { + } + + public boolean sendExtraCommand(String command, Bundle extras) { + return false; + } + + public void addListener(int uid) { + } + + public void removeListener(int uid) { + } + + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + mName); + pw.println(prefix + "mHasLocation=" + mHasLocation); + pw.println(prefix + "mLocation:"); + mLocation.dump(new PrintWriterPrinter(pw), prefix + " "); + pw.println(prefix + "mHasStatus=" + mHasStatus); + pw.println(prefix + "mStatus=" + mStatus); + pw.println(prefix + "mStatusUpdateTime=" + mStatusUpdateTime); + pw.println(prefix + "mExtras=" + mExtras); + } +} diff --git a/location/java/com/android/internal/location/TrackProvider.java b/location/java/com/android/internal/location/TrackProvider.java deleted file mode 100644 index 545d7dc..0000000 --- a/location/java/com/android/internal/location/TrackProvider.java +++ /dev/null @@ -1,720 +0,0 @@ -// Copyright 2007 The Android Open Source Project - -package com.android.internal.location; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; -import org.xmlpull.v1.XmlPullParserFactory; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; -import java.util.List; -import java.util.StringTokenizer; - -import android.location.Criteria; -import android.location.Location; -import android.location.LocationProviderImpl; -import android.os.Bundle; -import android.util.Config; -import android.util.Log; - -/** - * A dummy provider that returns positions interpolated from a sequence - * of caller-supplied waypoints. The waypoints are supplied as a - * String containing one or more numeric quadruples of the form: - * <br> - * <code> - * <time in millis> <latitude> <longitude> <altitude> - * </code> - * - * <p> The waypoints must be supplied in increasing timestamp order. - * - * <p> The time at which the provider is constructed is considered to - * be time 0, and further requests for positions will return a - * position that is linearly interpolated between the waypoints whose - * timestamps are closest to the amount of wall clock time that has - * elapsed since time 0. - * - * <p> Following the time of the last waypoint, the position of that - * waypoint will continue to be returned indefinitely. - * - * {@hide} - */ -public class TrackProvider extends LocationProviderImpl { - static final String LOG_TAG = "TrackProvider"; - - private static final long INTERVAL = 1000L; - - private boolean mEnabled = true; - - private double mLatitude; - private double mLongitude; - private boolean mHasAltitude; - private boolean mHasBearing; - private boolean mHasSpeed; - private double mAltitude; - private float mBearing; - private float mSpeed; - private Bundle mExtras; - - private long mBaseTime; - private long mLastTime = -1L; - private long mTime; - - private long mMinTime; - private long mMaxTime; - - private List<Waypoint> mWaypoints = new ArrayList<Waypoint>(); - private int mWaypointIndex = 0; - - private boolean mRequiresNetwork = false; - private boolean mRequiresSatellite = false; - private boolean mRequiresCell = false; - private boolean mHasMonetaryCost = false; - private boolean mSupportsAltitude = true; - private boolean mSupportsSpeed = true; - private boolean mSupportsBearing = true; - private boolean mRepeat = false; - private int mPowerRequirement = Criteria.POWER_LOW; - private int mAccuracy = Criteria.ACCURACY_COARSE; - - private float mTrackSpeed = 100.0f; // km/hr - default for kml tracks - - private Location mInitialLocation; - - private void close(Reader rdr) { - try { - if (rdr != null) { - rdr.close(); - } - } catch (IOException e) { - Log.w(LOG_TAG, "Exception closing reader", e); - } - } - - public void readTrack(File trackFile) { - BufferedReader br = null; - try { - br = new BufferedReader(new FileReader(trackFile), 8192); - String s; - - long lastTime = -Long.MAX_VALUE; - while ((s = br.readLine()) != null) { - String[] tokens = s.split("\\s+"); - if (tokens.length != 4 && tokens.length != 6) { - Log.e(LOG_TAG, "Got track \"" + s + - "\", wanted <time> <long> <lat> <alt> [<bearing> <speed>]"); - continue; - } - long time; - double longitude, latitude, altitude; - try { - time = Long.parseLong(tokens[0]); - longitude = Double.parseDouble(tokens[1]); - latitude = Double.parseDouble(tokens[2]); - altitude = Double.parseDouble(tokens[3]); - } catch (NumberFormatException e) { - Log.e(LOG_TAG, "Got track \"" + s + - "\", wanted <time> <long> <lat> <alt> " + - "[<bearing> <speed>]", e); - continue; - } - - Waypoint w = new Waypoint(getName(), time, latitude, longitude, altitude); - if (tokens.length >= 6) { - float bearing, speed; - try { - bearing = Float.parseFloat(tokens[4]); - speed = Float.parseFloat(tokens[5]); - w.setBearing(bearing); - w.setSpeed(speed); - } catch (NumberFormatException e) { - Log.e(LOG_TAG, "Ignoring bearing and speed \"" + - tokens[4] + "\", \"" + tokens[5] + "\"", e); - } - } - - if (mInitialLocation == null) { - mInitialLocation = w.getLocation(); - } - - // Ignore waypoints whose time is less than or equal to 0 or - // the time of the previous waypoint - if (time < 0) { - Log.e(LOG_TAG, "Ignoring waypoint at negative time=" + time); - continue; - } - if (time <= lastTime) { - Log.e(LOG_TAG, "Ignoring waypoint at time=" + time + - " (< " + lastTime + ")"); - continue; - } - - mWaypoints.add(w); - lastTime = time; - } - - setTimes(); - return; - } catch (IOException e) { - Log.e(LOG_TAG, "Exception reading track file", e); - mWaypoints.clear(); - } finally { - close(br); - } - } - - public void readKml(File kmlFile) { - FileReader kmlReader = null; - try { - kmlReader = new FileReader(kmlFile); - XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); - XmlPullParser xpp = factory.newPullParser(); - xpp.setInput(kmlReader); - - // Concatenate the text of each <coordinates> tag - boolean inCoordinates = false; - StringBuilder sb = new StringBuilder(); - int eventType = xpp.getEventType(); - do { - if (eventType == XmlPullParser.START_DOCUMENT) { - // do nothing - } else if (eventType == XmlPullParser.END_DOCUMENT) { - // do nothing - } else if (eventType == XmlPullParser.START_TAG) { - String startTagName = xpp.getName(); - if (startTagName.equals("coordinates")) { - inCoordinates = true; - } - } else if (eventType == XmlPullParser.END_TAG) { - String endTagName = xpp.getName(); - if (endTagName.equals("coordinates")) { - inCoordinates = false; - } - } else if (eventType == XmlPullParser.TEXT) { - if (inCoordinates) { - sb.append(xpp.getText()); - sb.append(' '); - } - } - eventType = xpp.next(); - } while (eventType != XmlPullParser.END_DOCUMENT); - - String coordinates = sb.toString(); - - // Parse the "lon,lat,alt" triples and supply times - // for each waypoint based on a constant speed - Location loc = null; - double KM_PER_HOUR = mTrackSpeed; - double KM_PER_METER = 1.0 / 1000.0; - double MILLIS_PER_HOUR = 60.0 * 60.0 * 1000.0; - double MILLIS_PER_METER = - (1.0 / KM_PER_HOUR) * (KM_PER_METER) * (MILLIS_PER_HOUR); - long time = 0L; - - StringTokenizer st = new StringTokenizer(coordinates, ", "); - while (st.hasMoreTokens()) { - try { - String lon = st.nextToken(); - String lat = st.nextToken(); - String alt = st.nextToken(); - if (Config.LOGD) { - Log.d(LOG_TAG, - "lon=" + lon + ", lat=" + lat + ", alt=" + alt); - } - - double nLongitude = Double.parseDouble(lon); - double nLatitude = Double.parseDouble(lat); - double nAltitude = Double.parseDouble(alt); - - Location nLoc = new Location(getName()); - nLoc.setLatitude(nLatitude); - nLoc.setLongitude(nLongitude); - if (loc != null) { - double distance = loc.distanceTo(nLoc); - if (Config.LOGD) { - Log.d(LOG_TAG, "distance = " + distance); - } - time += (long) (distance * MILLIS_PER_METER); - } - - Waypoint w = new Waypoint(getName(), time, - nLatitude, nLongitude, nAltitude); - if (supportsSpeed()) { - w.setSpeed(mTrackSpeed); - } - if (supportsBearing()) { - w.setBearing(0.0f); - } - mWaypoints.add(w); - - if (mInitialLocation == null) { - mInitialLocation = w.getLocation(); - } - - loc = nLoc; - } catch (NumberFormatException nfe) { - Log.e(LOG_TAG, "Got NumberFormatException reading KML data: " + - nfe, nfe); - } - } - - setTimes(); - return; - } catch (IOException ioe) { - mWaypoints.clear(); - Log.e(LOG_TAG, "Exception reading KML data: " + ioe, ioe); - // fall through - } catch (XmlPullParserException xppe) { - mWaypoints.clear(); - Log.e(LOG_TAG, "Exception reading KML data: " + xppe, xppe); - // fall through - } finally { - close(kmlReader); - } - } - - public void readNmea(String name, File file) { - BufferedReader br = null; - try { - br = new BufferedReader(new FileReader(file), 8192); - String s; - - String provider = getName(); - NmeaParser parser = new NmeaParser(name); - while ((s = br.readLine()) != null) { - boolean newWaypoint = parser.parseSentence(s); - if (newWaypoint) { - Location loc = parser.getLocation(); - Waypoint w = new Waypoint(loc); - mWaypoints.add(w); - // Log.i(TAG, "Got waypoint " + w); - } - } - - setTimes(); - return; - } catch (IOException ioe) { - Log.e(LOG_TAG, "Exception reading NMEA data: " + ioe); - mWaypoints.clear(); - } finally { - close(br); - } - } - - private static boolean booleanVal(String tf) { - return (tf == null) || (tf.equalsIgnoreCase("true")); - } - - private static int intVal(String val) { - try { - return (val == null) ? 0 : Integer.parseInt(val); - } catch (NumberFormatException nfe) { - return 0; - } - } - - private static float floatVal(String val) { - try { - return (val == null) ? 0 : Float.parseFloat(val); - } catch (NumberFormatException nfe) { - return 0.0f; - } - } - - public void readProperties(File propertiesFile) { - BufferedReader br = null; - if (!propertiesFile.exists()) { - return; - } - try { - if (Config.LOGD) { - Log.d(LOG_TAG, "Loading properties file " + - propertiesFile.getPath()); - } - br = new BufferedReader(new FileReader(propertiesFile), 8192); - - String s; - while ((s = br.readLine()) != null) { - StringTokenizer st = new StringTokenizer(s); - String command = null; - String value = null; - if (!st.hasMoreTokens()) { - continue; - } - command = st.nextToken(); - if (st.hasMoreTokens()) { - value = st.nextToken(); - } - - if (command.equalsIgnoreCase("requiresNetwork")) { - setRequiresNetwork(booleanVal(value)); - } else if (command.equalsIgnoreCase("requiresSatellite")) { - setRequiresSatellite(booleanVal(value)); - } else if (command.equalsIgnoreCase("requiresCell")) { - setRequiresCell(booleanVal(value)); - } else if (command.equalsIgnoreCase("hasMonetaryCost")) { - setHasMonetaryCost(booleanVal(value)); - } else if (command.equalsIgnoreCase("supportsAltitude")) { - setSupportsAltitude(booleanVal(value)); - } else if (command.equalsIgnoreCase("supportsBearing")) { - setSupportsBearing(booleanVal(value)); - } else if (command.equalsIgnoreCase("repeat")) { - setRepeat(booleanVal(value)); - } else if (command.equalsIgnoreCase("supportsSpeed")) { - setSupportsSpeed(booleanVal(value)); - } else if (command.equalsIgnoreCase("powerRequirement")) { - setPowerRequirement(intVal(value)); - } else if (command.equalsIgnoreCase("accuracy")) { - setAccuracy(intVal(value)); - } else if (command.equalsIgnoreCase("trackspeed")) { - setTrackSpeed(floatVal(value)); - } else { - Log.e(LOG_TAG, "Unknown command \"" + command + "\""); - } - } - } catch (IOException ioe) { - Log.e(LOG_TAG, "IOException reading properties file " + - propertiesFile.getPath(), ioe); - } finally { - try { - if (br != null) { - br.close(); - } - } catch (IOException e) { - Log.w(LOG_TAG, "IOException closing properties file " + - propertiesFile.getPath(), e); - } - } - } - - public TrackProvider(String name) { - super(name); - setTimes(); - } - - public TrackProvider(String name, File file) { - this(name); - - String filename = file.getName(); - if (filename.endsWith("kml")) { - readKml(file); - } else if (filename.endsWith("nmea")) { - readNmea(getName(), file); - } else if (filename.endsWith("track")) { - readTrack(file); - } else { - Log.e(LOG_TAG, "Can't initialize TrackProvider from file " + - filename + " (not *kml, *nmea, or *track)"); - } - setTimes(); - } - - private void setTimes() { - mBaseTime = System.currentTimeMillis(); - if (mWaypoints.size() >= 2) { - mMinTime = mWaypoints.get(0).getTime(); - mMaxTime = mWaypoints.get(mWaypoints.size() - 1).getTime(); - } else { - mMinTime = mMaxTime = 0; - } - } - - private double interp(double d0, double d1, float frac) { - return d0 + frac * (d1 - d0); - } - - private void update() { - // Don't update the position at all unless INTERVAL milliseconds - // have passed since the last request - long time = System.currentTimeMillis() - mBaseTime; - if (time - mLastTime < INTERVAL) { - return; - } - - List<Waypoint> waypoints = mWaypoints; - if (waypoints == null) { - return; - } - int size = waypoints.size(); - if (size < 2) { - return; - } - - long t = time; - if (t < mMinTime) { - t = mMinTime; - } - if (mRepeat) { - t -= mMinTime; - long deltaT = mMaxTime - mMinTime; - t %= 2 * deltaT; - if (t > deltaT) { - t = 2 * deltaT - t; - } - t += mMinTime; - } else if (t > mMaxTime) { - t = mMaxTime; - } - - // Locate the time interval for the current time - // We slide the window since we don't expect to move - // much between calls - - Waypoint w0 = waypoints.get(mWaypointIndex); - Waypoint w1 = waypoints.get(mWaypointIndex + 1); - - // If the right end of the current interval is too early, - // move forward to the next waypoint - while (t > w1.getTime()) { - w0 = w1; - w1 = waypoints.get(++mWaypointIndex + 1); - } - // If the left end of the current interval is too late, - // move back to the previous waypoint - while (t < w0.getTime()) { - w1 = w0; - w0 = waypoints.get(--mWaypointIndex); - } - - // Now we know that w0.mTime <= t <= w1.mTime - long w0Time = w0.getTime(); - long w1Time = w1.getTime(); - long dt = w1Time - w0Time; - - float frac = (dt == 0) ? 0 : ((float) (t - w0Time) / dt); - mLatitude = interp(w0.getLatitude(), w1.getLatitude(), frac); - mLongitude = interp(w0.getLongitude(), w1.getLongitude(), frac); - mHasAltitude = w0.hasAltitude() && w1.hasAltitude(); - if (mSupportsAltitude && mHasAltitude) { - mAltitude = interp(w0.getAltitude(), w1.getAltitude(), frac); - } - if (mSupportsBearing) { - mHasBearing = frac <= 0.5f ? w0.hasBearing() : w1.hasBearing(); - if (mHasBearing) { - mBearing = frac <= 0.5f ? w0.getBearing() : w1.getBearing(); - } - } - if (mSupportsSpeed) { - mHasSpeed = frac <= 0.5f ? w0.hasSpeed() : w1.hasSpeed(); - if (mHasSpeed) { - mSpeed = frac <= 0.5f ? w0.getSpeed() : w1.getSpeed(); - } - } - mLastTime = time; - mTime = time; - } - - public void setRequiresNetwork(boolean requiresNetwork) { - mRequiresNetwork = requiresNetwork; - } - - @Override public boolean requiresNetwork() { - return mRequiresNetwork; - } - - public void setRequiresSatellite(boolean requiresSatellite) { - mRequiresSatellite = requiresSatellite; - } - - @Override public boolean requiresSatellite() { - return mRequiresSatellite; - } - - public void setRequiresCell(boolean requiresCell) { - mRequiresCell = requiresCell; - } - - @Override public boolean requiresCell() { - return mRequiresCell; - } - - public void setHasMonetaryCost(boolean hasMonetaryCost) { - mHasMonetaryCost = hasMonetaryCost; - } - - @Override public boolean hasMonetaryCost() { - return mHasMonetaryCost; - } - - public void setSupportsAltitude(boolean supportsAltitude) { - mSupportsAltitude = supportsAltitude; - } - - @Override public boolean supportsAltitude() { - return mSupportsAltitude; - } - - public void setSupportsSpeed(boolean supportsSpeed) { - mSupportsSpeed = supportsSpeed; - } - - @Override public boolean supportsSpeed() { - return mSupportsSpeed; - } - - public void setSupportsBearing(boolean supportsBearing) { - mSupportsBearing = supportsBearing; - } - - @Override public boolean supportsBearing() { - return mSupportsBearing; - } - - public void setRepeat(boolean repeat) { - mRepeat = repeat; - } - - public void setPowerRequirement(int powerRequirement) { - if (powerRequirement < Criteria.POWER_LOW || - powerRequirement > Criteria.POWER_HIGH) { - throw new IllegalArgumentException("powerRequirement = " + - powerRequirement); - } - mPowerRequirement = powerRequirement; - } - - @Override public int getPowerRequirement() { - return mPowerRequirement; - } - - public void setAccuracy(int accuracy) { - mAccuracy = accuracy; - } - - @Override public int getAccuracy() { - return mAccuracy; - } - - public void setTrackSpeed(float trackSpeed) { - mTrackSpeed = trackSpeed; - } - - @Override public void enable() { - mEnabled = true; - } - - @Override public void disable() { - mEnabled = false; - } - - @Override public boolean isEnabled() { - return mEnabled; - } - - @Override public int getStatus(Bundle extras) { - return AVAILABLE; - } - - @Override public boolean getLocation(Location l) { - if (mEnabled) { - update(); - l.setProvider(getName()); - l.setTime(mTime + mBaseTime); - l.setLatitude(mLatitude); - l.setLongitude(mLongitude); - if (mSupportsAltitude && mHasAltitude) { - l.setAltitude(mAltitude); - } - if (mSupportsBearing && mHasBearing) { - l.setBearing(mBearing); - } - if (mSupportsSpeed && mHasSpeed) { - l.setSpeed(mSpeed); - } - if (mExtras != null) { - l.setExtras(mExtras); - } - return true; - } else { - return false; - } - } - - public Location getInitialLocation() { - return mInitialLocation; - } -} - -/** - * A simple tuple of (time stamp, latitude, longitude, altitude), plus optional - * extras. - * - * {@hide} - */ -class Waypoint { - public Location mLocation; - - public Waypoint(Location location) { - mLocation = location; - } - - public Waypoint(String providerName, long time, double latitude, double longitude, - double altitude) { - mLocation = new Location(providerName); - mLocation.setTime(time); - mLocation.setLatitude(latitude); - mLocation.setLongitude(longitude); - mLocation.setAltitude(altitude); - } - - public long getTime() { - return mLocation.getTime(); - } - - public double getLatitude() { - return mLocation.getLatitude(); - } - - public double getLongitude() { - return mLocation.getLongitude(); - } - - public boolean hasAltitude() { - return mLocation.hasAltitude(); - } - - public double getAltitude() { - return mLocation.getAltitude(); - } - - public boolean hasBearing() { - return mLocation.hasBearing(); - } - - public void setBearing(float bearing) { - mLocation.setBearing(bearing); - } - - public float getBearing() { - return mLocation.getBearing(); - } - - public boolean hasSpeed() { - return mLocation.hasSpeed(); - } - - public void setSpeed(float speed) { - mLocation.setSpeed(speed); - } - - public float getSpeed() { - return mLocation.getSpeed(); - } - - public Bundle getExtras() { - return mLocation.getExtras(); - } - - public Location getLocation() { - return new Location(mLocation); - } - - @Override public String toString() { - return "Waypoint[mLocation=" + mLocation + "]"; - } -} |