From 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: auto import from //depot/cupcake/@135843 --- location/java/android/location/Address.aidl | 19 + location/java/android/location/Address.java | 516 ++++++++ location/java/android/location/Criteria.aidl | 19 + location/java/android/location/Criteria.java | 242 ++++ .../android/location/DummyLocationProvider.java | 168 +++ location/java/android/location/Geocoder.java | 242 ++++ location/java/android/location/GpsSatellite.java | 117 ++ location/java/android/location/GpsStatus.java | 200 +++ .../java/android/location/IGpsStatusListener.aidl | 32 + .../java/android/location/ILocationListener.aidl | 32 + .../java/android/location/ILocationManager.aidl | 76 ++ location/java/android/location/Location.aidl | 19 + location/java/android/location/Location.java | 741 ++++++++++++ .../java/android/location/LocationListener.java | 82 ++ .../java/android/location/LocationManager.java | 1268 ++++++++++++++++++++ .../java/android/location/LocationProvider.java | 160 +++ .../android/location/LocationProviderImpl.java | 261 ++++ location/java/android/location/package.html | 12 + 18 files changed, 4206 insertions(+) create mode 100644 location/java/android/location/Address.aidl create mode 100644 location/java/android/location/Address.java create mode 100644 location/java/android/location/Criteria.aidl create mode 100644 location/java/android/location/Criteria.java create mode 100644 location/java/android/location/DummyLocationProvider.java create mode 100644 location/java/android/location/Geocoder.java create mode 100644 location/java/android/location/GpsSatellite.java create mode 100644 location/java/android/location/GpsStatus.java create mode 100644 location/java/android/location/IGpsStatusListener.aidl create mode 100644 location/java/android/location/ILocationListener.aidl create mode 100644 location/java/android/location/ILocationManager.aidl create mode 100644 location/java/android/location/Location.aidl create mode 100644 location/java/android/location/Location.java create mode 100644 location/java/android/location/LocationListener.java create mode 100644 location/java/android/location/LocationManager.java create mode 100644 location/java/android/location/LocationProvider.java create mode 100644 location/java/android/location/LocationProviderImpl.java create mode 100644 location/java/android/location/package.html (limited to 'location/java/android') diff --git a/location/java/android/location/Address.aidl b/location/java/android/location/Address.aidl new file mode 100644 index 0000000..5be1498 --- /dev/null +++ b/location/java/android/location/Address.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +parcelable Address; diff --git a/location/java/android/location/Address.java b/location/java/android/location/Address.java new file mode 100644 index 0000000..3551363 --- /dev/null +++ b/location/java/android/location/Address.java @@ -0,0 +1,516 @@ +/* + * 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 java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * A class representing an Address, i.e, a set of Strings describing a location. + * + * The addres format is a simplified version of xAL (eXtensible Address Language) + * http://www.oasis-open.org/committees/ciq/ciq.html#6 + */ +public class Address implements Parcelable { + + private Locale mLocale; + + private String mFeatureName; + private HashMap mAddressLines; + private int mMaxAddressLineIndex = -1; + private String mAdminArea; + private String mSubAdminArea; + private String mLocality; + private String mThoroughfare; + private String mPostalCode; + private String mCountryCode; + private String mCountryName; + private double mLatitude; + private double mLongitude; + private boolean mHasLatitude = false; + private boolean mHasLongitude = false; + private String mPhone; + private String mUrl; + private Bundle mExtras = null; + + /** + * Constructs a new Address object set to the given Locale and with all + * other fields initialized to null or false. + */ + public Address(Locale locale) { + mLocale = locale; + } + + /** + * Returns the Locale associated with this address. + */ + public Locale getLocale() { + return mLocale; + } + + /** + * Returns the largest index currently in use to specify an address line. + * If no address lines are specified, -1 is returned. + */ + public int getMaxAddressLineIndex() { + return mMaxAddressLineIndex; + } + + /** + * Returns a line of the address numbered by the given index + * (starting at 0), or null if no such line is present. + * + * @throws IllegalArgumentException if index < 0 + */ + public String getAddressLine(int index) { + if (index < 0) { + throw new IllegalArgumentException("index = " + index + " < 0"); + } + return mAddressLines == null? null : mAddressLines.get(index); + } + + /** + * Sets the line of the address numbered by index (starting at 0) to the + * given String, which may be null. + * + * @throws IllegalArgumentException if index < 0 + */ + public void setAddressLine(int index, String line) { + if (index < 0) { + throw new IllegalArgumentException("index = " + index + " < 0"); + } + if (mAddressLines == null) { + mAddressLines = new HashMap(); + } + mAddressLines.put(index, line); + + if (line == null) { + // We've eliminated a line, recompute the max index + mMaxAddressLineIndex = -1; + for (Integer i : mAddressLines.keySet()) { + mMaxAddressLineIndex = Math.max(mMaxAddressLineIndex, i); + } + } else { + mMaxAddressLineIndex = Math.max(mMaxAddressLineIndex, index); + } + } + + /** + * Returns the feature name of the address, for example, "Golden Gate Bridge", or null + * if it is unknown + */ + public String getFeatureName() { + return mFeatureName; + } + + /** + * Sets the feature name of the address to the given String, which may be null + */ + public void setFeatureName(String featureName) { + mFeatureName = featureName; + } + + /** + * Returns the administrative area name of the address, for example, "CA", or null if + * it is unknown + */ + public String getAdminArea() { + return mAdminArea; + } + + /** + * Sets the administrative area name of the address to the given String, which may be null + */ + public void setAdminArea(String adminArea) { + this.mAdminArea = adminArea; + } + + /** + * Returns the sub-administrative area name of the address, for example, "Santa Clara County", + * or null if it is unknown + */ + public String getSubAdminArea() { + return mSubAdminArea; + } + + /** + * Sets the sub-administrative area name of the address to the given String, which may be null + */ + public void setSubAdminArea(String subAdminArea) { + this.mSubAdminArea = subAdminArea; + } + + /** + * Returns the locality of the address, for example "Mountain View", or null if it is unknown. + */ + public String getLocality() { + return mLocality; + } + + /** + * Sets the locality of the address to the given String, which may be null. + */ + public void setLocality(String locality) { + mLocality = locality; + } + + /** + * Returns the thoroughfare name of the address, for example, "1600 Ampitheater Parkway", + * which may be null + */ + public String getThoroughfare() { + return mThoroughfare; + } + + /** + * Sets the thoroughfare name of the address, which may be null. + */ + public void setThoroughfare(String thoroughfare) { + this.mThoroughfare = thoroughfare; + } + + /** + * Returns the postal code of the address, for example "94110", + * or null if it is unknown. + */ + public String getPostalCode() { + return mPostalCode; + } + + /** + * Sets the postal code of the address to the given String, which may + * be null. + */ + public void setPostalCode(String postalCode) { + mPostalCode = postalCode; + } + + /** + * Returns the country code of the address, for example "US", + * or null if it is unknown. + */ + public String getCountryCode() { + return mCountryCode; + } + + /** + * Sets the country code of the address to the given String, which may + * be null. + */ + public void setCountryCode(String countryCode) { + mCountryCode = countryCode; + } + + /** + * Returns the localized country name of the address, for example "Iceland", + * or null if it is unknown. + */ + public String getCountryName() { + return mCountryName; + } + + /** + * Sets the country name of the address to the given String, which may + * be null. + */ + public void setCountryName(String countryName) { + mCountryName = countryName; + } + + /** + * Returns true if a latitude has been assigned to this Address, + * false otherwise. + */ + public boolean hasLatitude() { + return mHasLatitude; + } + + /** + * Returns the latitude of the address if known. + * + * @throws IllegalStateException if this Address has not been assigned + * a latitude. + */ + public double getLatitude() { + if (mHasLatitude) { + return mLatitude; + } else { + throw new IllegalStateException(); + } + } + + /** + * Sets the latitude associated with this address. + */ + public void setLatitude(double latitude) { + mLatitude = latitude; + mHasLatitude = true; + } + + /** + * Removes any latitude associated with this address. + */ + public void clearLatitude() { + mHasLatitude = false; + } + + /** + * Returns true if a longitude has been assigned to this Address, + * false otherwise. + */ + public boolean hasLongitude() { + return mHasLongitude; + } + + /** + * Returns the longitude of the address if known. + * + * @throws IllegalStateException if this Address has not been assigned + * a longitude. + */ + public double getLongitude() { + if (mHasLongitude) { + return mLongitude; + } else { + throw new IllegalStateException(); + } + } + + /** + * Sets the longitude associated with this address. + */ + public void setLongitude(double longitude) { + mLongitude = longitude; + mHasLongitude = true; + } + + /** + * Removes any longitude associated with this address. + */ + public void clearLongitude() { + mHasLongitude = false; + } + + /** + * Returns the phone number of the address if known, + * or null if it is unknown. + * + * @throws IllegalStateException if this Address has not been assigned + * a latitude. + */ + public String getPhone() { + return mPhone; + } + + /** + * Sets the phone number associated with this address. + */ + public void setPhone(String phone) { + mPhone = phone; + } + + /** + * Returns the public URL for the address if known, + * or null if it is unknown. + */ + public String getUrl() { + return mUrl; + } + + /** + * Sets the public URL associated with this address. + */ + public void setUrl(String Url) { + mUrl = Url; + } + + /** + * Returns additional provider-specific information about the + * address as a Bundle. The keys and values are determined + * by the provider. If no additional information is available, + * null is returned. + * + * + */ + public Bundle getExtras() { + return mExtras; + } + + /** + * Sets the extra information associated with this fix to the + * given Bundle. + */ + public void setExtras(Bundle extras) { + mExtras = (extras == null) ? null : new Bundle(extras); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Address[addressLines=["); + for (int i = 0; i <= mMaxAddressLineIndex; i++) { + if (i > 0) { + sb.append(','); + } + sb.append(i); + sb.append(':'); + String line = mAddressLines.get(i); + if (line == null) { + sb.append("null"); + } else { + sb.append('\"'); + sb.append(line); + sb.append('\"'); + } + } + sb.append(']'); + sb.append(",feature="); + sb.append(mFeatureName); + sb.append(",admin="); + sb.append(mAdminArea); + sb.append(",sub-admin="); + sb.append(mSubAdminArea); + sb.append(",locality="); + sb.append(mLocality); + sb.append(",thoroughfare="); + sb.append(mThoroughfare); + sb.append(",postalCode="); + sb.append(mPostalCode); + sb.append(",countryCode="); + sb.append(mCountryCode); + sb.append(",countryName="); + sb.append(mCountryName); + sb.append(",hasLatitude="); + sb.append(mHasLatitude); + sb.append(",latitude="); + sb.append(mLatitude); + sb.append(",hasLongitude="); + sb.append(mHasLongitude); + sb.append(",longitude="); + sb.append(mLongitude); + sb.append(",phone="); + sb.append(mPhone); + sb.append(",url="); + sb.append(mUrl); + sb.append(",extras="); + sb.append(mExtras); + sb.append(']'); + return sb.toString(); + } + + public static final Parcelable.Creator
CREATOR = + new Parcelable.Creator
() { + public Address createFromParcel(Parcel in) { + String language = in.readString(); + String country = in.readString(); + Locale locale = country.length() > 0 ? + new Locale(language, country) : + new Locale(language); + Address a = new Address(locale); + + int N = in.readInt(); + if (N > 0) { + a.mAddressLines = new HashMap(N); + for (int i = 0; i < N; i++) { + int index = in.readInt(); + String line = in.readString(); + a.mAddressLines.put(index, line); + a.mMaxAddressLineIndex = + Math.max(a.mMaxAddressLineIndex, index); + } + } else { + a.mAddressLines = null; + a.mMaxAddressLineIndex = -1; + } + a.mFeatureName = in.readString(); + a.mAdminArea = in.readString(); + a.mSubAdminArea = in.readString(); + a.mLocality = in.readString(); + a.mThoroughfare = in.readString(); + a.mPostalCode = in.readString(); + a.mCountryCode = in.readString(); + a.mCountryName = in.readString(); + a.mHasLatitude = in.readInt() == 0 ? false : true; + if (a.mHasLatitude) { + a.mLatitude = in.readDouble(); + } + a.mHasLongitude = in.readInt() == 0 ? false : true; + if (a.mHasLongitude) { + a.mLongitude = in.readDouble(); + } + a.mPhone = in.readString(); + a.mUrl = in.readString(); + a.mExtras = in.readBundle(); + return a; + } + + public Address[] newArray(int size) { + return new Address[size]; + } + }; + + public int describeContents() { + return (mExtras != null) ? mExtras.describeContents() : 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mLocale.getLanguage()); + parcel.writeString(mLocale.getCountry()); + if (mAddressLines == null) { + parcel.writeInt(0); + } else { + Set> entries = mAddressLines.entrySet(); + parcel.writeInt(entries.size()); + for (Map.Entry e : entries) { + parcel.writeInt(e.getKey()); + parcel.writeString(e.getValue()); + } + } + parcel.writeString(mFeatureName); + parcel.writeString(mAdminArea); + parcel.writeString(mSubAdminArea); + parcel.writeString(mLocality); + parcel.writeString(mThoroughfare); + parcel.writeString(mPostalCode); + parcel.writeString(mCountryCode); + parcel.writeString(mCountryName); + parcel.writeInt(mHasLatitude ? 1 : 0); + if (mHasLatitude) { + parcel.writeDouble(mLatitude); + } + parcel.writeInt(mHasLongitude ? 1 : 0); + if (mHasLongitude){ + parcel.writeDouble(mLongitude); + } + parcel.writeString(mPhone); + parcel.writeString(mUrl); + parcel.writeBundle(mExtras); + } +} diff --git a/location/java/android/location/Criteria.aidl b/location/java/android/location/Criteria.aidl new file mode 100644 index 0000000..b9a8879 --- /dev/null +++ b/location/java/android/location/Criteria.aidl @@ -0,0 +1,19 @@ +/* + * 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; + +parcelable Criteria; diff --git a/location/java/android/location/Criteria.java b/location/java/android/location/Criteria.java new file mode 100644 index 0000000..9d258d0 --- /dev/null +++ b/location/java/android/location/Criteria.java @@ -0,0 +1,242 @@ +/* + * 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 android.os.Parcel; +import android.os.Parcelable; + +/** + * A class indicating the application criteria for selecting a + * location provider. Providers maybe ordered according to accuracy, + * power usage, ability to report altitude, speed, + * and bearing, and monetary cost. + */ +public class Criteria implements Parcelable { + /** + * A constant indicating that the application does not choose to + * place requirement on a particular feature. + */ + public static final int NO_REQUIREMENT = 0; + + /** + * A constant indicating a low power requirement. + */ + public static final int POWER_LOW = 1; + + /** + * A constant indicating a medium power requirement. + */ + public static final int POWER_MEDIUM = 2; + + /** + * A constant indicating a high power requirement. + */ + public static final int POWER_HIGH = 3; + + /** + * A constant indicating a finer location accuracy requirement + */ + public static final int ACCURACY_FINE = 1; + + /** + * A constant indicating an approximate accuracy requirement + */ + public static final int ACCURACY_COARSE = 2; + + private int mAccuracy = NO_REQUIREMENT; + private int mPowerRequirement = NO_REQUIREMENT; +// private int mPreferredResponseTime = NO_REQUIREMENT; + private boolean mAltitudeRequired = false; + private boolean mBearingRequired = false; + private boolean mSpeedRequired = false; + private boolean mCostAllowed = false; + + /** + * Constructs a new Criteria object. The new object will have no + * requirements on accuracy, power, or response time; will not + * require altitude, speed, or bearing; and will not allow monetary + * cost. + */ + public Criteria() {} + + /** + * Constructs a new Criteria object that is a copy of the given criteria. + */ + public Criteria(Criteria criteria) { + mAccuracy = criteria.mAccuracy; + mPowerRequirement = criteria.mPowerRequirement; +// mPreferredResponseTime = criteria.mPreferredResponseTime; + mAltitudeRequired = criteria.mAltitudeRequired; + mBearingRequired = criteria.mBearingRequired; + mSpeedRequired = criteria.mSpeedRequired; + mCostAllowed = criteria.mCostAllowed; + } + + /** + * Indicates the desired accuracy for latitude and longitude. Accuracy + * may be {@link #ACCURACY_FINE} if desired location + * is fine, else it can be {@link #ACCURACY_COARSE}. + * More accurate location usually consumes more power and may take + * longer. + * + * @throws IllegalArgumentException if accuracy is negative + */ + public void setAccuracy(int accuracy) { + if (accuracy < NO_REQUIREMENT && accuracy > ACCURACY_COARSE) { + throw new IllegalArgumentException("accuracy=" + accuracy); + } + mAccuracy = accuracy; + } + + /** + * Returns a constant indicating desired accuracy of location + * Accuracy may be {@link #ACCURACY_FINE} if desired location + * is fine, else it can be {@link #ACCURACY_COARSE}. + */ + public int getAccuracy() { + return mAccuracy; + } + + /** + * Indicates the desired maximum power level. The level parameter + * must be one of NO_REQUIREMENT, POWER_LOW, POWER_MEDIUM, or + * POWER_HIGH. + */ + public void setPowerRequirement(int level) { + if (level < NO_REQUIREMENT || level > POWER_HIGH) { + throw new IllegalArgumentException("level=" + level); + } + mPowerRequirement = level; + } + + /** + * Returns a constant indicating the desired power requirement. The + * returned + */ + public int getPowerRequirement() { + return mPowerRequirement; + } + +// /** +// * Indicates the preferred response time of the provider, in milliseconds. +// */ +// public void setPreferredResponseTime(int time) { +// mPreferredResponseTime = time; +// } +// +// /** +// * Returns the preferred response time of the provider, in milliseconds. +// */ +// public int getPreferredResponseTime() { +// return mPreferredResponseTime; +// } + + /** + * Indicates whether the provider is allowed to incur monetary cost. + */ + public void setCostAllowed(boolean costAllowed) { + mCostAllowed = costAllowed; + } + + /** + * Returns whether the provider is allowed to incur monetary cost. + */ + public boolean isCostAllowed() { + return mCostAllowed; + } + + /** + * Indicates whether the provider must provide altitude information. + * Not all fixes are guaranteed to contain such information. + */ + public void setAltitudeRequired(boolean altitudeRequired) { + mAltitudeRequired = altitudeRequired; + } + + /** + * Returns whether the provider must provide altitude information. + * Not all fixes are guaranteed to contain such information. + */ + public boolean isAltitudeRequired() { + return mAltitudeRequired; + } + + /** + * Indicates whether the provider must provide speed information. + * Not all fixes are guaranteed to contain such information. + */ + public void setSpeedRequired(boolean speedRequired) { + mSpeedRequired = speedRequired; + } + + /** + * Returns whether the provider must provide speed information. + * Not all fixes are guaranteed to contain such information. + */ + public boolean isSpeedRequired() { + return mSpeedRequired; + } + + /** + * Indicates whether the provider must provide bearing information. + * Not all fixes are guaranteed to contain such information. + */ + public void setBearingRequired(boolean bearingRequired) { + mBearingRequired = bearingRequired; + } + + /** + * Returns whether the provider must provide bearing information. + * Not all fixes are guaranteed to contain such information. + */ + public boolean isBearingRequired() { + return mBearingRequired; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Criteria createFromParcel(Parcel in) { + Criteria c = new Criteria(); + c.mAccuracy = in.readInt(); + c.mPowerRequirement = in.readInt(); +// c.mPreferredResponseTime = in.readInt(); + c.mAltitudeRequired = in.readInt() != 0; + c.mBearingRequired = in.readInt() != 0; + c.mSpeedRequired = in.readInt() != 0; + c.mCostAllowed = in.readInt() != 0; + return c; + } + + public Criteria[] newArray(int size) { + return new Criteria[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(mAccuracy); + parcel.writeInt(mPowerRequirement); +// parcel.writeInt(mPreferredResponseTime); + parcel.writeInt(mAltitudeRequired ? 1 : 0); + parcel.writeInt(mBearingRequired ? 1 : 0); + parcel.writeInt(mSpeedRequired ? 1 : 0); + parcel.writeInt(mCostAllowed ? 1 : 0); + } +} diff --git a/location/java/android/location/DummyLocationProvider.java b/location/java/android/location/DummyLocationProvider.java new file mode 100644 index 0000000..e1cd4e9 --- /dev/null +++ b/location/java/android/location/DummyLocationProvider.java @@ -0,0 +1,168 @@ +/* + * 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; + +/** + * A stub implementation of LocationProvider used by LocationManager. + * A DummyLocationProvider may be queried to determine the properties + * of the provider whcih it shadows, but does not actually provide location + * data. + * + * {@hide} + */ +class DummyLocationProvider extends LocationProvider { + + private static final String TAG = "DummyLocationProvider"; + + String mName; + boolean mRequiresNetwork; + boolean mRequiresSatellite; + boolean mRequiresCell; + boolean mHasMonetaryCost; + boolean mSupportsAltitude; + boolean mSupportsSpeed; + boolean mSupportsBearing; + int mPowerRequirement; + int mAccuracy; + + /* package */ DummyLocationProvider(String name) { + super(name); + } + + public void setRequiresNetwork(boolean requiresNetwork) { + mRequiresNetwork = requiresNetwork; + } + + public void setRequiresSatellite(boolean requiresSatellite) { + mRequiresSatellite = requiresSatellite; + } + + public void setRequiresCell(boolean requiresCell) { + mRequiresCell = requiresCell; + } + + public void setHasMonetaryCost(boolean hasMonetaryCost) { + mHasMonetaryCost = hasMonetaryCost; + } + + public void setSupportsAltitude(boolean supportsAltitude) { + mSupportsAltitude = supportsAltitude; + } + + public void setSupportsSpeed(boolean supportsSpeed) { + mSupportsSpeed = supportsSpeed; + } + + public void setSupportsBearing(boolean supportsBearing) { + mSupportsBearing = supportsBearing; + } + + public void setPowerRequirement(int powerRequirement) { + mPowerRequirement = powerRequirement; + } + + public void setAccuracy(int accuracy) { + mAccuracy = accuracy; + } + + /** + * Returns true if the provider requires access to a + * data network (e.g., the Internet), false otherwise. + */ + public boolean requiresNetwork() { + return mRequiresNetwork; + } + + /** + * Returns true if the provider requires access to a + * satellite-based positioning system (e.g., GPS), false + * otherwise. + */ + public boolean requiresSatellite() { + return mRequiresSatellite; + } + + /** + * Returns true if the provider requires access to an appropriate + * cellular network (e.g., to make use of cell tower IDs), false + * otherwise. + */ + public boolean requiresCell() { + return mRequiresCell; + } + + /** + * Returns true if the use of this provider may result in a + * monetary charge to the user, false if use is free. It is up to + * each provider to give accurate information. + */ + public boolean hasMonetaryCost() { + return mHasMonetaryCost; + } + + /** + * Returns true if the provider is able to provide altitude + * information, false otherwise. A provider that reports altitude + * under most circumstances but may occassionally not report it + * should return true. + */ + public boolean supportsAltitude() { + return mSupportsAltitude; + } + + /** + * Returns true if the provider is able to provide speed + * information, false otherwise. A provider that reports speed + * under most circumstances but may occassionally not report it + * should return true. + */ + public boolean supportsSpeed() { + return mSupportsSpeed; + } + + /** + * Returns true if the provider is able to provide bearing + * information, false otherwise. A provider that reports bearing + * under most circumstances but may occassionally not report it + * should return true. + */ + public boolean supportsBearing() { + return mSupportsBearing; + } + + /** + * Returns the power requirement for this provider. + * + * @return the power requirement for this provider, as one of the + * constants Criteria.POWER_REQUIREMENT_*. + */ + public int getPowerRequirement() { + return mPowerRequirement; + } + + /** + * Returns a constant describing the horizontal accuracy returned + * by this provider. + * + * @return the horizontal accuracy for this provider, as one of the + * constants Criteria.ACCURACY_*. + */ + public int getAccuracy() { + return mAccuracy; + } +} + diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java new file mode 100644 index 0000000..709ad23 --- /dev/null +++ b/location/java/android/location/Geocoder.java @@ -0,0 +1,242 @@ +/* + * 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 android.content.Context; +import android.location.Address; +import android.os.RemoteException; +import android.os.IBinder; +import android.os.ServiceManager; +import android.util.Log; + +import java.io.IOException; +import java.util.Locale; +import java.util.ArrayList; +import java.util.List; + +/** + * A class for handling geocoding and reverse geocoding. Geocoding is + * the process of transforming a street address or other description + * of a location into a (latitude, longitude) coordinate. Reverse + * geocoding is the process of transforming a (latitude, longitude) + * 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. + */ +public final class Geocoder { + private static final String TAG = "Geocoder"; + + private String mLanguage; + private String mCountry; + private String mVariant; + private String mAppName; + private ILocationManager mService; + + /** + * Constructs a Geocoder whose responses will be localized for the + * given Locale. + * + * @param context the Context of the calling Activity + * @param locale the desired Locale for the query results + * + * @throws NullPointerException if Locale is null + */ + public Geocoder(Context context, Locale locale) { + if (locale == null) { + throw new NullPointerException("locale == null"); + } + mLanguage = locale.getLanguage(); + mCountry = locale.getCountry(); + mVariant = locale.getVariant(); + mAppName = context.getPackageName(); + + IBinder b = ServiceManager.getService(Context.LOCATION_SERVICE); + mService = ILocationManager.Stub.asInterface(b); + } + + /** + * Constructs a Geocoder whose responses will be localized for the + * default system Locale. + * + * @param context the Context of the calling Activity + */ + public Geocoder(Context context) { + this(context, Locale.getDefault()); + } + + /** + * Returns an array of Addresses that are known to describe the + * area immediately surrounding the given latitude and longitude. + * The returned addresses will be localized for the locale + * provided to this class's constructor. + * + *

The returned values may be obtained by means of a network lookup. + * The results are a best guess and are not guaranteed to be meaningful or + * correct. It may be useful to call this method from a thread separate from your + * primary UI thread. + * + * @param latitude the latitude a point for the search + * @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. + * + * @throws IllegalArgumentException if latitude is + * less than -90 or greater than 90 + * @throws IllegalArgumentException if longitude is + * less than -180 or greater than 180 + * @throws IOException if the network is unavailable or any other + * I/O problem occurs + */ + public List

getFromLocation(double latitude, double longitude, int maxResults) + throws IOException { + if (latitude < -90.0 || latitude > 90.0) { + throw new IllegalArgumentException("latitude == " + latitude); + } + if (longitude < -180.0 || longitude > 180.0) { + throw new IllegalArgumentException("longitude == " + longitude); + } + try { + List
results = new ArrayList
(); + String ex = mService.getFromLocation(latitude, longitude, maxResults, + mLanguage, mCountry, mVariant, mAppName, results); + if (ex != null) { + throw new IOException(ex); + } else { + return results; + } + } catch (RemoteException e) { + Log.e(TAG, "getFromLocation: got RemoteException", e); + return null; + } + } + + /** + * Returns an array of Addresses that are known to describe the + * named location, which may be a place name such as "Dalvik, + * Iceland", an address such as "1600 Amphitheatre Parkway, + * Mountain View, CA", an airport code such as "SFO", etc.. The + * returned addresses will be localized for the locale provided to + * this class's constructor. + * + *

The query will block and returned values will be obtained by means of a network lookup. + * The results are a best guess and are not guaranteed to be meaningful or + * correct. It may be useful to call this method from a thread separate from your + * primary UI thread. + * + * @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. + * + * @throws IllegalArgumentException if locationName is null + * @throws IOException if the network is unavailable or any other + * I/O problem occurs + */ + public List

getFromLocationName(String locationName, int maxResults) throws IOException { + if (locationName == null) { + throw new IllegalArgumentException("locationName == null"); + } + try { + List
results = new ArrayList
(); + String ex = mService.getFromLocationName(locationName, + 0, 0, 0, 0, maxResults, mLanguage, mCountry, mVariant, mAppName, results); + if (ex != null) { + throw new IOException(ex); + } else { + return results; + } + } catch (RemoteException e) { + Log.e(TAG, "getFromLocationName: got RemoteException", e); + return null; + } + } + + /** + * Returns an array of Addresses that are known to describe the + * named location, which may be a place name such as "Dalvik, + * Iceland", an address such as "1600 Amphitheatre Parkway, + * Mountain View, CA", an airport code such as "SFO", etc.. The + * returned addresses will be localized for the locale provided to + * this class's constructor. + * + *

You may specify a bounding box for the search results by including + * the Latitude and Longitude of the Lower Left point and Upper Right + * point of the box. + * + *

The query will block and returned values will be obtained by means of a network lookup. + * The results are a best guess and are not guaranteed to be meaningful or + * correct. It may be useful to call this method from a thread separate from your + * primary UI thread. + * + * @param locationName a user-supplied description of a location + * @param maxResults max number of addresses to return. Smaller numbers (1 to 5) are recommended + * @param lowerLeftLatitude the latitude of the lower left corner of the bounding box + * @param lowerLeftLongitude the longitude of the lower left corner of the bounding box + * @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. + * + * @throws IllegalArgumentException if locationName is null + * @throws IllegalArgumentException if any latitude is + * less than -90 or greater than 90 + * @throws IllegalArgumentException if any longitude is + * less than -180 or greater than 180 + * @throws IOException if the network is unavailable or any other + * I/O problem occurs + */ + public List

getFromLocationName(String locationName, int maxResults, + double lowerLeftLatitude, double lowerLeftLongitude, + double upperRightLatitude, double upperRightLongitude) throws IOException { + if (locationName == null) { + throw new IllegalArgumentException("locationName == null"); + } + if (lowerLeftLatitude < -90.0 || lowerLeftLatitude > 90.0) { + throw new IllegalArgumentException("lowerLeftLatitude == " + + lowerLeftLatitude); + } + if (lowerLeftLongitude < -180.0 || lowerLeftLongitude > 180.0) { + throw new IllegalArgumentException("lowerLeftLongitude == " + + lowerLeftLongitude); + } + if (upperRightLatitude < -90.0 || upperRightLatitude > 90.0) { + throw new IllegalArgumentException("upperRightLatitude == " + + upperRightLatitude); + } + if (upperRightLongitude < -180.0 || upperRightLongitude > 180.0) { + throw new IllegalArgumentException("upperRightLongitude == " + + upperRightLongitude); + } + try { + ArrayList
result = new ArrayList
(); + String ex = mService.getFromLocationName(locationName, + lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude, + maxResults, mLanguage, mCountry, mVariant, mAppName, result); + if (ex != null) { + throw new IOException(ex); + } else { + return result; + } + } catch (RemoteException e) { + Log.e(TAG, "getFromLocationName: got RemoteException", e); + return null; + } + } +} diff --git a/location/java/android/location/GpsSatellite.java b/location/java/android/location/GpsSatellite.java new file mode 100644 index 0000000..17af4a6 --- /dev/null +++ b/location/java/android/location/GpsSatellite.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2008 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; + +/** + * This class represents the current state of a GPS satellite. + * This class is used in conjunction with the {@link GpsStatus} class. + */ +public final class GpsSatellite { + /* These package private values are modified by the GpsStatus class */ + boolean mValid; + boolean mHasEphemeris; + boolean mHasAlmanac; + boolean mUsedInFix; + int mPrn; + float mSnr; + float mElevation; + float mAzimuth; + + GpsSatellite(int prn) { + mPrn = prn; + } + + /** + * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's + * cached GpsStatus instance to the client's copy. + */ + void setStatus(GpsSatellite satellite) { + mValid = satellite.mValid; + mHasEphemeris = satellite.mHasEphemeris; + mHasAlmanac = satellite.mHasAlmanac; + mUsedInFix = satellite.mUsedInFix; + mSnr = satellite.mSnr; + mElevation = satellite.mElevation; + mAzimuth = satellite.mAzimuth; + } + + /** + * Returns the PRN (pseudo-random number) for the satellite. + * + * @return PRN number + */ + public int getPrn() { + return mPrn; + } + + /** + * Returns the signal to noise ratio for the satellite. + * + * @return the signal to noise ratio + */ + public float getSnr() { + return mSnr; + } + + /** + * Returns the elevation of the satellite in degrees. + * The elevation can vary between 0 and 90. + * + * @return the elevation in degrees + */ + public float getElevation() { + return mElevation; + } + + /** + * Returns the azimuth of the satellite in degrees. + * The azimuth can vary between 0 and 360. + * + * @return the azimuth in degrees + */ + public float getAzimuth() { + return mAzimuth; + } + + /** + * Returns true if the GPS engine has ephemeris data for the satellite. + * + * @return true if the satellite has ephemeris data + */ + public boolean hasEphemeris() { + return mHasEphemeris; + } + + /** + * Returns true if the GPS engine has almanac data for the satellite. + * + * @return true if the satellite has almanac data + */ + public boolean hasAlmanac() { + return mHasAlmanac; + } + + /** + * Returns true if the satellite was used by the GPS engine when + * calculating the most recent GPS fix. + * + * @return true if the satellite was used to compute the most recent fix. + */ + public boolean usedInFix() { + return mUsedInFix; + } +} diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java new file mode 100644 index 0000000..a40b1fb --- /dev/null +++ b/location/java/android/location/GpsStatus.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2008 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 java.util.Iterator; +import java.util.NoSuchElementException; + + +/** + * This class represents the current state of the GPS engine. + * This class is used in conjunction with the {@link Listener} interface. + */ +public final class GpsStatus { + private static final int NUM_SATELLITES = 32; + + /* These package private values are modified by the LocationManager class */ + private int mTimeToFirstFix; + private GpsSatellite mSatellites[] = new GpsSatellite[NUM_SATELLITES]; + + private final class SatelliteIterator implements Iterator { + + private GpsSatellite[] mSatellites; + int mIndex = 0; + + SatelliteIterator(GpsSatellite[] satellites) { + mSatellites = satellites; + } + + public boolean hasNext() { + for (int i = mIndex; i < mSatellites.length; i++) { + if (mSatellites[i].mValid) { + return true; + } + } + return false; + } + + public GpsSatellite next() { + while (mIndex < mSatellites.length) { + GpsSatellite satellite = mSatellites[mIndex++]; + if (satellite.mValid) { + return satellite; + } + } + throw new NoSuchElementException(); + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + + private Iterable mSatelliteList = new Iterable() { + public Iterator iterator() { + return new SatelliteIterator(mSatellites); + } + }; + + /** + * Event sent when the GPS system has started. + */ + public static final int GPS_EVENT_STARTED = 1; + + /** + * Event sent when the GPS system has stopped. + */ + public static final int GPS_EVENT_STOPPED = 2; + + /** + * Event sent when the GPS system has received its first fix since starting. + * Call {@link #getTimeToFirstFix()} to find the time from start to first fix. + */ + public static final int GPS_EVENT_FIRST_FIX = 3; + + /** + * Event sent periodically to report GPS satellite status. + * Call {@link #getSatellites()} to retrieve the status for each satellite. + */ + public static final int GPS_EVENT_SATELLITE_STATUS = 4; + + /** + * Used for receiving notifications when GPS status has changed. + */ + public interface Listener { + /** + * Called to report changes in the GPS status. + * The event number is one of: + *
    + *
  • {@link GpsStatus#GPS_EVENT_STARTED} + *
  • {@link GpsStatus#GPS_EVENT_STOPPED} + *
  • {@link GpsStatus#GPS_EVENT_FIRST_FIX} + *
  • {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS} + *
+ * + * When this method is called, the client should call + * {@link LocationManager#getGpsStatus} to get additional + * status information. + * + * @param event event number for this notification + */ + void onGpsStatusChanged(int event); + } + + GpsStatus() { + for (int i = 0; i < mSatellites.length; i++) { + mSatellites[i] = new GpsSatellite(i + 1); + } + } + + /** + * Used internally within {@link LocationManager} to copy GPS status + * data from the Location Manager Service to its cached GpsStatus instance. + * Is synchronized to ensure that GPS status updates are atomic. + */ + synchronized void setStatus(int svCount, int[] prns, float[] snrs, + float[] elevations, float[] azimuths, int ephemerisMask, + int almanacMask, int usedInFixMask) { + int i; + + for (i = 0; i < mSatellites.length; i++) { + mSatellites[i].mValid = false; + } + + for (i = 0; i < svCount; i++) { + int prn = prns[i] - 1; + int prnShift = (1 << prn); + GpsSatellite satellite = mSatellites[prn]; + + satellite.mValid = true; + satellite.mSnr = snrs[i]; + satellite.mElevation = elevations[i]; + satellite.mAzimuth = azimuths[i]; + satellite.mHasEphemeris = ((ephemerisMask & prnShift) != 0); + satellite.mHasAlmanac = ((almanacMask & prnShift) != 0); + satellite.mUsedInFix = ((usedInFixMask & prnShift) != 0); + } + } + + /** + * Used by {@link LocationManager#getGpsStatus} to copy LocationManager's + * cached GpsStatus instance to the client's copy. + * Since this method is only used within {@link LocationManager#getGpsStatus}, + * it does not need to be synchronized. + */ + void setStatus(GpsStatus status) { + mTimeToFirstFix = status.getTimeToFirstFix(); + + for (int i = 0; i < mSatellites.length; i++) { + mSatellites[i].setStatus(status.mSatellites[i]); + } + } + + void setTimeToFirstFix(int ttff) { + mTimeToFirstFix = ttff; + } + + /** + * Returns the time required to receive the first fix since the most recent + * restart of the GPS engine. + * + * @return time to first fix in milliseconds + */ + public int getTimeToFirstFix() { + return mTimeToFirstFix; + } + + /** + * Returns an array of {@link GpsSatellite} objects, which represent the + * current state of the GPS engine. + * + * @return the list of satellites + */ + public Iterable getSatellites() { + return mSatelliteList; + } + + /** + * Returns the maximum number of satellites that can be in the satellite + * list that can be returned by {@link #getSatellites()}. + * + * @return the maximum number of satellites + */ + public int getMaxSatellites() { + return NUM_SATELLITES; + } +} diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl new file mode 100644 index 0000000..5dc0fe8 --- /dev/null +++ b/location/java/android/location/IGpsStatusListener.aidl @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.location; + +import android.location.Location; + +/** + * {@hide} + */ +oneway interface IGpsStatusListener +{ + void onGpsStarted(); + void onGpsStopped(); + void onFirstFix(int ttff); + void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, + in float[] elevations, in float[] azimuths, + int ephemerisMask, int almanacMask, int usedInFixMask); +} diff --git a/location/java/android/location/ILocationListener.aidl b/location/java/android/location/ILocationListener.aidl new file mode 100644 index 0000000..7627cf6 --- /dev/null +++ b/location/java/android/location/ILocationListener.aidl @@ -0,0 +1,32 @@ +/* //device/java/android/android/location/ILocationListener.aidl +** +** Copyright 2008, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.location; + +import android.location.Location; +import android.os.Bundle; + +/** + * {@hide} + */ +oneway interface ILocationListener +{ + void onLocationChanged(in Location location); + void onStatusChanged(String provider, int status, in Bundle extras); + void onProviderEnabled(String provider); + void onProviderDisabled(String provider); +} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl new file mode 100644 index 0000000..69c404a --- /dev/null +++ b/location/java/android/location/ILocationManager.aidl @@ -0,0 +1,76 @@ +/* + * 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 android.app.PendingIntent; +import android.location.Address; +import android.location.IGpsStatusListener; +import android.location.ILocationListener; +import android.location.Location; +import android.os.Bundle; + +/** + * System private API for talking with the location service. + * + * {@hide} + */ +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, + in PendingIntent intent); + void removeUpdates(in ILocationListener listener); + void removeUpdatesPI(in PendingIntent intent); + + boolean addGpsStatusListener(IGpsStatusListener listener); + void removeGpsStatusListener(IGpsStatusListener listener); + + boolean sendExtraCommand(String provider, String command, inout Bundle extras); + + void addProximityAlert(double latitude, double longitude, float distance, + long expiration, in PendingIntent intent); + void removeProximityAlert(in PendingIntent intent); + + Bundle getProviderInfo(String provider); + boolean isProviderEnabled(String provider); + + Location getLastKnownLocation(String provider); + + String getFromLocation(double latitude, double longitude, int maxResults, + String language, String country, String variant, String appName, out List
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
addrs); + + void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, + boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, + boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy); + void removeTestProvider(String provider); + void setTestProviderLocation(String provider, in Location loc); + void clearTestProviderLocation(String provider); + void setTestProviderEnabled(String provider, boolean enabled); + void clearTestProviderEnabled(String provider); + void setTestProviderStatus(String provider, int status, in Bundle extras, long updateTime); + void clearTestProviderStatus(String provider); +} diff --git a/location/java/android/location/Location.aidl b/location/java/android/location/Location.aidl new file mode 100644 index 0000000..f47b488 --- /dev/null +++ b/location/java/android/location/Location.aidl @@ -0,0 +1,19 @@ +/* + * 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; + +parcelable Location; diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java new file mode 100644 index 0000000..aacf857 --- /dev/null +++ b/location/java/android/location/Location.java @@ -0,0 +1,741 @@ +/* + * 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 android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Printer; + +import java.text.DecimalFormat; +import java.util.StringTokenizer; + +/** + * A class representing a geographic location sensed at a particular + * time (a "fix"). A location consists of a latitude and longitude, a + * UTC timestamp. and optionally information on altitude, speed, and + * bearing. + * + *

Information specific to a particular provider or class of + * providers may be communicated to the application using getExtras, + * which returns a Bundle of key/value pairs. Each provider will only + * provide those entries for which information is available. + */ +public class Location implements Parcelable { + /** + * Constant used to specify formatting of a latitude or longitude + * in the form "[+-]DDD.DDDDD where D indicates degrees. + */ + public static final int FORMAT_DEGREES = 0; + + /** + * Constant used to specify formatting of a latitude or longitude + * in the form "[+-]DDD:MM.MMMMM" where D indicates degrees and + * M indicates minutes of arc (1 minute = 1/60th of a degree). + */ + public static final int FORMAT_MINUTES = 1; + + /** + * Constant used to specify formatting of a latitude or longitude + * in the form "DDD:MM:SS.SSSSS" where D indicates degrees, M + * indicates minutes of arc, and S indicates seconds of arc (1 + * minute = 1/60th of a degree, 1 second = 1/3600th of a degree). + */ + public static final int FORMAT_SECONDS = 2; + + private String mProvider; + private long mTime = 0; + private double mLatitude = 0.0; + private double mLongitude = 0.0; + private boolean mHasAltitude = false; + private double mAltitude = 0.0f; + private boolean mHasSpeed = false; + private float mSpeed = 0.0f; + private boolean mHasBearing = false; + private float mBearing = 0.0f; + private boolean mHasAccuracy = false; + private float mAccuracy = 0.0f; + private Bundle mExtras = null; + + // Cache the inputs and outputs of computeDistanceAndBearing + // so calls to distanceTo() and bearingTo() can share work + private double mLat1 = 0.0; + private double mLon1 = 0.0; + private double mLat2 = 0.0; + private double mLon2 = 0.0; + private float mDistance = 0.0f; + private float mInitialBearing = 0.0f; + // Scratchpad + private float[] mResults = new float[2]; + + public void dump(Printer pw, String prefix) { + pw.println(prefix + "mProvider=" + mProvider + " mTime=" + mTime); + pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude); + pw.println(prefix + "mHasAltitude=" + mHasAltitude + " mAltitude=" + mAltitude); + pw.println(prefix + "mHasSpeed=" + mHasSpeed + " mSpeed=" + mSpeed); + pw.println(prefix + "mHasBearing=" + mHasBearing + " mBearing=" + mBearing); + pw.println(prefix + "mHasAccuracy=" + mHasAccuracy + " mAccuracy=" + mAccuracy); + pw.println(prefix + "mExtras=" + mExtras); + } + + /** + * Constructs a new Location. By default, time, latitude, + * longitude, and numSatellites are 0; hasAltitude, hasSpeed, and + * hasBearing are false; and there is no extra information. + * + * @param provider the name of the location provider that generated this + * location fix. + */ + public Location(String provider) { + mProvider = provider; + } + + /** + * Constructs a new Location object that is a copy of the given + * location. + */ + public Location(Location l) { + set(l); + } + + /** + * Sets the contents of the location to the values from the given location. + */ + public void set(Location l) { + mProvider = l.mProvider; + mTime = l.mTime; + mLatitude = l.mLatitude; + mLongitude = l.mLongitude; + mHasAltitude = l.mHasAltitude; + mAltitude = l.mAltitude; + mHasSpeed = l.mHasSpeed; + mSpeed = l.mSpeed; + mHasBearing = l.mHasBearing; + mBearing = l.mBearing; + mHasAccuracy = l.mHasAccuracy; + mAccuracy = l.mAccuracy; + mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras); + } + + /** + * Clears the contents of the location. + */ + public void reset() { + mProvider = null; + mTime = 0; + mLatitude = 0; + mLongitude = 0; + mHasAltitude = false; + mAltitude = 0; + mHasSpeed = false; + mSpeed = 0; + mHasBearing = false; + mBearing = 0; + mHasAccuracy = false; + mAccuracy = 0; + mExtras = null; + } + + /** + * Converts a coordinate to a String representation. The outputType + * may be one of FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS. + * The coordinate must be a valid double between -180.0 and 180.0. + * + * @throws IllegalArgumentException if coordinate is less than + * -180.0, greater than 180.0, or is not a number. + * @throws IllegalArgumentException if outputType is not one of + * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS. + */ + public static String convert(double coordinate, int outputType) { + if (coordinate < -180.0 || coordinate > 180.0 || + Double.isNaN(coordinate)) { + throw new IllegalArgumentException("coordinate=" + coordinate); + } + if ((outputType != FORMAT_DEGREES) && + (outputType != FORMAT_MINUTES) && + (outputType != FORMAT_SECONDS)) { + throw new IllegalArgumentException("outputType=" + outputType); + } + + StringBuilder sb = new StringBuilder(); + + // Handle negative values + if (coordinate < 0) { + sb.append('-'); + coordinate = -coordinate; + } + + DecimalFormat df = new DecimalFormat("###.#####"); + if (outputType == FORMAT_MINUTES || outputType == FORMAT_SECONDS) { + int degrees = (int) Math.floor(coordinate); + sb.append(degrees); + sb.append(':'); + coordinate -= degrees; + coordinate *= 60.0; + if (outputType == FORMAT_SECONDS) { + int minutes = (int) Math.floor(coordinate); + sb.append(minutes); + sb.append(':'); + coordinate -= minutes; + coordinate *= 60.0; + } + } + sb.append(df.format(coordinate)); + return sb.toString(); + } + + /** + * Converts a String in one of the formats described by + * FORMAT_DEGREES, FORMAT_MINUTES, or FORMAT_SECONDS into a + * double. + * + * @throws NullPointerException if coordinate is null + * @throws IllegalArgumentException if the coordinate is not + * in one of the valid formats. + */ + public static double convert(String coordinate) { + // IllegalArgumentException if bad syntax + if (coordinate == null) { + throw new NullPointerException("coordinate"); + } + + boolean negative = false; + if (coordinate.charAt(0) == '-') { + coordinate = coordinate.substring(1); + negative = true; + } + + StringTokenizer st = new StringTokenizer(coordinate, ":"); + int tokens = st.countTokens(); + if (tokens < 1) { + throw new IllegalArgumentException("coordinate=" + coordinate); + } + try { + String degrees = st.nextToken(); + double val; + if (tokens == 1) { + val = Double.parseDouble(degrees); + return negative ? -val : val; + } + + String minutes = st.nextToken(); + int deg = Integer.parseInt(degrees); + double min; + double sec = 0.0; + + if (st.hasMoreTokens()) { + min = Integer.parseInt(minutes); + String seconds = st.nextToken(); + sec = Double.parseDouble(seconds); + } else { + min = Double.parseDouble(minutes); + } + + boolean isNegative180 = negative && (deg == 180) && + (min == 0) && (sec == 0); + + // deg must be in [0, 179] except for the case of -180 degrees + if ((deg < 0.0) || (deg > 179 && !isNegative180)) { + throw new IllegalArgumentException("coordinate=" + coordinate); + } + if (min < 0 || min > 59) { + throw new IllegalArgumentException("coordinate=" + + coordinate); + } + if (sec < 0 || sec > 59) { + throw new IllegalArgumentException("coordinate=" + + coordinate); + } + + val = deg*3600.0 + min*60.0 + sec; + val /= 3600.0; + return negative ? -val : val; + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException("coordinate=" + coordinate); + } + } + + private static void computeDistanceAndBearing(double lat1, double lon1, + double lat2, double lon2, float[] results) { + // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf + // using the "Inverse Formula" (section 4) + + int MAXITERS = 20; + // Convert lat/long to radians + lat1 *= Math.PI / 180.0; + lat2 *= Math.PI / 180.0; + lon1 *= Math.PI / 180.0; + lon2 *= Math.PI / 180.0; + + double a = 6378137.0; // WGS84 major axis + double b = 6356752.3142; // WGS84 semi-major axis + double f = (a - b) / a; + double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b); + + double L = lon2 - lon1; + double A = 0.0; + double U1 = Math.atan((1.0 - f) * Math.tan(lat1)); + double U2 = Math.atan((1.0 - f) * Math.tan(lat2)); + + double cosU1 = Math.cos(U1); + double cosU2 = Math.cos(U2); + double sinU1 = Math.sin(U1); + double sinU2 = Math.sin(U2); + double cosU1cosU2 = cosU1 * cosU2; + double sinU1sinU2 = sinU1 * sinU2; + + double sigma = 0.0; + double deltaSigma = 0.0; + double cosSqAlpha = 0.0; + double cos2SM = 0.0; + double cosSigma = 0.0; + double sinSigma = 0.0; + double cosLambda = 0.0; + double sinLambda = 0.0; + + double lambda = L; // initial guess + for (int iter = 0; iter < MAXITERS; iter++) { + double lambdaOrig = lambda; + cosLambda = Math.cos(lambda); + sinLambda = Math.sin(lambda); + double t1 = cosU2 * sinLambda; + double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda; + double sinSqSigma = t1 * t1 + t2 * t2; // (14) + sinSigma = Math.sqrt(sinSqSigma); + cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15) + sigma = Math.atan2(sinSigma, cosSigma); // (16) + double sinAlpha = (sinSigma == 0) ? 0.0 : + cosU1cosU2 * sinLambda / sinSigma; // (17) + cosSqAlpha = 1.0 - sinAlpha * sinAlpha; + cos2SM = (cosSqAlpha == 0) ? 0.0 : + cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18) + + double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn + A = 1 + (uSquared / 16384.0) * // (3) + (4096.0 + uSquared * + (-768 + uSquared * (320.0 - 175.0 * uSquared))); + double B = (uSquared / 1024.0) * // (4) + (256.0 + uSquared * + (-128.0 + uSquared * (74.0 - 47.0 * uSquared))); + double C = (f / 16.0) * + cosSqAlpha * + (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10) + double cos2SMSq = cos2SM * cos2SM; + deltaSigma = B * sinSigma * // (6) + (cos2SM + (B / 4.0) * + (cosSigma * (-1.0 + 2.0 * cos2SMSq) - + (B / 6.0) * cos2SM * + (-3.0 + 4.0 * sinSigma * sinSigma) * + (-3.0 + 4.0 * cos2SMSq))); + + lambda = L + + (1.0 - C) * f * sinAlpha * + (sigma + C * sinSigma * + (cos2SM + C * cosSigma * + (-1.0 + 2.0 * cos2SM * cos2SM))); // (11) + + double delta = (lambda - lambdaOrig) / lambda; + if (Math.abs(delta) < 1.0e-12) { + break; + } + } + + float distance = (float) (b * A * (sigma - deltaSigma)); + results[0] = distance; + if (results.length > 1) { + float initialBearing = (float) Math.atan2(cosU2 * sinLambda, + cosU1 * sinU2 - sinU1 * cosU2 * cosLambda); + initialBearing *= 180.0 / Math.PI; + results[1] = initialBearing; + if (results.length > 2) { + float finalBearing = (float) Math.atan2(cosU1 * sinLambda, + -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda); + finalBearing *= 180.0 / Math.PI; + results[2] = finalBearing; + } + } + } + + /** + * Computes the approximate distance in meters between two + * locations, and optionally the initial and final bearings of the + * shortest path between them. Distance and bearing are defined using the + * WGS84 ellipsoid. + * + *

The computed distance is stored in results[0]. If results has length + * 2 or greater, the initial bearing is stored in results[1]. If results has + * length 3 or greater, the final bearing is stored in results[2]. + * + * @param startLatitude the starting latitude + * @param startLongitude the starting longitude + * @param endLatitude the ending latitude + * @param endLongitude the ending longitude + * @param results an array of floats to hold the results + * + * @throws IllegalArgumentException if results is null or has length < 1 + */ + public static void distanceBetween(double startLatitude, double startLongitude, + double endLatitude, double endLongitude, float[] results) { + if (results == null || results.length < 1) { + throw new IllegalArgumentException("results is null or has length < 1"); + } + computeDistanceAndBearing(startLatitude, startLongitude, + endLatitude, endLongitude, results); + } + + /** + * Returns the approximate distance in meters between this + * location and the given location. Distance is defined using + * the WGS84 ellipsoid. + * + * @param dest the destination location + * @return the approximate distance in meters + */ + public float distanceTo(Location dest) { + // See if we already have the result + synchronized (mResults) { + if (mLatitude != mLat1 || mLongitude != mLon1 || + dest.mLatitude != mLat2 || dest.mLongitude != mLon2) { + computeDistanceAndBearing(mLatitude, mLongitude, + dest.mLatitude, dest.mLongitude, mResults); + mLat1 = mLatitude; + mLon1 = mLongitude; + mLat2 = dest.mLatitude; + mLon2 = dest.mLongitude; + mDistance = mResults[0]; + mInitialBearing = mResults[1]; + } + return mDistance; + } + } + + /** + * Returns the approximate initial bearing in degrees East of true + * North when traveling along the shortest path between this + * location and the given location. The shortest path is defined + * using the WGS84 ellipsoid. Locations that are (nearly) + * antipodal may produce meaningless results. + * + * @param dest the destination location + * @return the initial bearing in degrees + */ + public float bearingTo(Location dest) { + synchronized (mResults) { + // See if we already have the result + if (mLatitude != mLat1 || mLongitude != mLon1 || + dest.mLatitude != mLat2 || dest.mLongitude != mLon2) { + computeDistanceAndBearing(mLatitude, mLongitude, + dest.mLatitude, dest.mLongitude, mResults); + mLat1 = mLatitude; + mLon1 = mLongitude; + mLat2 = dest.mLatitude; + mLon2 = dest.mLongitude; + mDistance = mResults[0]; + mInitialBearing = mResults[1]; + } + return mInitialBearing; + } + } + + /** + * Returns the name of the provider that generated this fix, + * or null if it is not associated with a provider. + */ + public String getProvider() { + return mProvider; + } + + /** + * Sets the name of the provider that generated this fix. + */ + public void setProvider(String provider) { + mProvider = provider; + } + + /** + * Returns the UTC time of this fix, in milliseconds since January 1, + * 1970. + */ + public long getTime() { + return mTime; + } + + /** + * Sets the UTC time of this fix, in milliseconds since January 1, + * 1970. + */ + public void setTime(long time) { + mTime = time; + } + + /** + * Returns the latitude of this fix. + */ + public double getLatitude() { + return mLatitude; + } + + /** + * Sets the latitude of this fix. + */ + public void setLatitude(double latitude) { + mLatitude = latitude; + } + + /** + * Returns the longitude of this fix. + */ + public double getLongitude() { + return mLongitude; + } + + /** + * Sets the longitude of this fix. + */ + public void setLongitude(double longitude) { + mLongitude = longitude; + } + + /** + * Returns true if this fix contains altitude information, false + * otherwise. + */ + public boolean hasAltitude() { + return mHasAltitude; + } + + /** + * Returns the altitude of this fix. If {@link #hasAltitude} is false, + * 0.0f is returned. + */ + public double getAltitude() { + return mAltitude; + } + + /** + * Sets the altitude of this fix. Following this call, + * hasAltitude() will return true. + */ + public void setAltitude(double altitude) { + mAltitude = altitude; + mHasAltitude = true; + } + + /** + * Clears the altitude of this fix. Following this call, + * hasAltitude() will return false. + */ + public void removeAltitude() { + mAltitude = 0.0f; + mHasAltitude = false; + } + + /** + * Returns true if this fix contains speed information, false + * otherwise. The default implementation returns false. + */ + public boolean hasSpeed() { + return mHasSpeed; + } + + /** + * Returns the speed of the device over ground in meters/second. + * If hasSpeed() is false, 0.0f is returned. + */ + public float getSpeed() { + return mSpeed; + } + + /** + * Sets the speed of this fix, in meters/second. Following this + * call, hasSpeed() will return true. + */ + public void setSpeed(float speed) { + mSpeed = speed; + mHasSpeed = true; + } + + /** + * Clears the speed of this fix. Following this call, hasSpeed() + * will return false. + */ + public void removeSpeed() { + mSpeed = 0.0f; + mHasSpeed = false; + } + + /** + * Returns true if the provider is able to report bearing information, + * false otherwise. The default implementation returns false. + */ + public boolean hasBearing() { + return mHasBearing; + } + + /** + * Returns the direction of travel in degrees East of true + * North. If hasBearing() is false, 0.0 is returned. + */ + public float getBearing() { + return mBearing; + } + + /** + * Sets the bearing of this fix. Following this call, hasBearing() + * will return true. + */ + public void setBearing(float bearing) { + while (bearing < 0.0f) { + bearing += 360.0f; + } + while (bearing >= 360.0f) { + bearing -= 360.0f; + } + mBearing = bearing; + mHasBearing = true; + } + + /** + * Clears the bearing of this fix. Following this call, hasBearing() + * will return false. + */ + public void removeBearing() { + mBearing = 0.0f; + mHasBearing = false; + } + + /** + * Returns true if the provider is able to report accuracy information, + * false otherwise. The default implementation returns false. + */ + public boolean hasAccuracy() { + return mHasAccuracy; + } + + /** + * Returns the accuracy of the fix in meters. If hasAccuracy() is false, + * 0.0 is returned. + */ + public float getAccuracy() { + return mAccuracy; + } + + /** + * Sets the accuracy of this fix. Following this call, hasAccuracy() + * will return true. + */ + public void setAccuracy(float accuracy) { + mAccuracy = accuracy; + mHasAccuracy = true; + } + + /** + * Clears the accuracy of this fix. Following this call, hasAccuracy() + * will return false. + */ + public void removeAccuracy() { + mAccuracy = 0.0f; + mHasAccuracy = false; + } + + /** + * Returns additional provider-specific information about the + * location fix as a Bundle. The keys and values are determined + * by the provider. If no additional information is available, + * null is returned. + * + *

A number of common key/value pairs are listed + * below. Providers that use any of the keys on this list must + * provide the corresponding value as described below. + * + *

    + *
  • satellites - the number of satellites used to derive the fix + *
+ */ + public Bundle getExtras() { + return mExtras; + } + + /** + * Sets the extra information associated with this fix to the + * given Bundle. + */ + public void setExtras(Bundle extras) { + mExtras = (extras == null) ? null : new Bundle(extras); + } + + @Override public String toString() { + return "Location[mProvider=" + mProvider + + ",mTime=" + mTime + + ",mLatitude=" + mLatitude + + ",mLongitude=" + mLongitude + + ",mHasAltitude=" + mHasAltitude + + ",mAltitude=" + mAltitude + + ",mHasSpeed=" + mHasSpeed + + ",mSpeed=" + mSpeed + + ",mHasBearing=" + mHasBearing + + ",mBearing=" + mBearing + + ",mHasAccuracy=" + mHasAccuracy + + ",mAccuracy=" + mAccuracy + + ",mExtras=" + mExtras + "]"; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public Location createFromParcel(Parcel in) { + String provider = in.readString(); + Location l = new Location(provider); + l.mTime = in.readLong(); + l.mLatitude = in.readDouble(); + l.mLongitude = in.readDouble(); + l.mHasAltitude = in.readInt() != 0; + l.mAltitude = in.readDouble(); + l.mHasSpeed = in.readInt() != 0; + l.mSpeed = in.readFloat(); + l.mHasBearing = in.readInt() != 0; + l.mBearing = in.readFloat(); + l.mHasAccuracy = in.readInt() != 0; + l.mAccuracy = in.readFloat(); + l.mExtras = in.readBundle(); + return l; + } + + public Location[] newArray(int size) { + return new Location[size]; + } + }; + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeString(mProvider); + parcel.writeLong(mTime); + parcel.writeDouble(mLatitude); + parcel.writeDouble(mLongitude); + parcel.writeInt(mHasAltitude ? 1 : 0); + parcel.writeDouble(mAltitude); + parcel.writeInt(mHasSpeed ? 1 : 0); + parcel.writeFloat(mSpeed); + parcel.writeInt(mHasBearing ? 1 : 0); + parcel.writeFloat(mBearing); + parcel.writeInt(mHasAccuracy ? 1 : 0); + parcel.writeFloat(mAccuracy); + parcel.writeBundle(mExtras); + } +} diff --git a/location/java/android/location/LocationListener.java b/location/java/android/location/LocationListener.java new file mode 100644 index 0000000..0f5f388 --- /dev/null +++ b/location/java/android/location/LocationListener.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2008 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; + +/** + * Used for receiving notifications from the LocationManager when + * the location has changed. These methods are called if the + * LocationListener has been registered with the location manager service + * using the {@link LocationManager#requestLocationUpdates(String, long, float, LocationListener)} + * method. + */ +public interface LocationListener { + + /** + * Called when the location has changed. + * + *

There are no restrictions on the use of the supplied Location object. + * + * @param location The new location, as a Location object. + */ + void onLocationChanged(Location location); + + /** + * Called when the provider status changes. This method is called when + * a provider is unable to fetch a location or if the provider has recently + * become available after a period of unavailability. + * + * @param provider the name of the location provider associated with this + * update. + * @param status {@link LocationProvider#OUT_OF_SERVICE} if the + * provider is out of service, and this is not expected to change in the + * near future; {@link LocationProvider#TEMPORARILY_UNAVAILABLE} if + * the provider is temporarily unavailable but is expected to be available + * shortly; and {@link LocationProvider#AVAILABLE} if the + * provider is currently available. + * @param extras an optional Bundle which will contain provider specific + * status variables. + * + *

A number of common key/value pairs for the extras Bundle are listed + * below. Providers that use any of the keys on this list must + * provide the corresponding value as described below. + * + *

    + *
  • satellites - the number of satellites used to derive the fix + *
+ */ + void onStatusChanged(String provider, int status, Bundle extras); + + /** + * Called when the provider is enabled by the user. + * + * @param provider the name of the location provider associated with this + * update. + */ + void onProviderEnabled(String provider); + + /** + * Called when the provider is disabled by the user. If requestLocationUpdates + * is called on an already disabled provider, this method is called + * immediately. + * + * @param provider the name of the location provider associated with this + * update. + */ + void onProviderDisabled(String provider); +} diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java new file mode 100644 index 0000000..022ee25 --- /dev/null +++ b/location/java/android/location/LocationManager.java @@ -0,0 +1,1268 @@ +/* + * 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 android.app.PendingIntent; +import android.content.Intent; +import android.os.Bundle; +import android.os.Looper; +import android.os.RemoteException; +import android.os.Handler; +import android.os.Message; +import android.util.Config; +import android.util.Log; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + +/** + * This class provides access to the system location services. These + * services allow applications to obtain periodic updates of the + * device's geographical location, or to fire an application-specified + * {@link Intent} when the device enters the proximity of a given + * geographical location. + * + *

You do not + * instantiate this class directly; instead, retrieve it through + * {@link android.content.Context#getSystemService + * Context.getSystemService(Context.LOCATION_SERVICE)}. + */ +public class LocationManager { + private static final String TAG = "LocationManager"; + private ILocationManager mService; + private final HashMap mGpsStatusListeners = + new HashMap(); + private final GpsStatus mGpsStatus = new GpsStatus(); + + /** + * Name of the network location provider. This provider determines location based on + * availability of cell tower and WiFi access points. Results are retrieved + * by means of a network lookup. + * + * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION + * or android.permission.ACCESS_FINE_LOCATION. + */ + public static final String NETWORK_PROVIDER = "network"; + + /** + * Name of the GPS location provider. This provider determines location using + * satellites. Depending on conditions, this provider may take a while to return + * a location fix. + * + * Requires the permission android.permissions.ACCESS_FINE_LOCATION. + * + *

The extras Bundle for the GPS location provider can contain the + * following key/value pairs: + * + *

    + *
  • satellites - the number of satellites used to derive the fix + *
+ */ + public static final String GPS_PROVIDER = "gps"; + + /** + * Key used for the Bundle extra holding a boolean indicating whether + * a proximity alert is entering (true) or exiting (false).. + */ + public static final String KEY_PROXIMITY_ENTERING = "entering"; + + /** + * Key used for a Bundle extra holding an Integer status value + * when a status change is broadcast using a PendingIntent. + */ + public static final String KEY_STATUS_CHANGED = "status"; + + /** + * Key used for a Bundle extra holding an Boolean status value + * when a provider enabled/disabled event is broadcast using a PendingIntent. + */ + public static final String KEY_PROVIDER_ENABLED = "providerEnabled"; + + /** + * Key used for a Bundle extra holding a Location value + * when a location change is broadcast using a PendingIntent. + */ + 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"; + + // Map from LocationListeners to their associated ListenerTransport objects + private HashMap mListeners = + new HashMap(); + + private class ListenerTransport extends ILocationListener.Stub { + private static final int TYPE_LOCATION_CHANGED = 1; + private static final int TYPE_STATUS_CHANGED = 2; + private static final int TYPE_PROVIDER_ENABLED = 3; + private static final int TYPE_PROVIDER_DISABLED = 4; + + private LocationListener mListener; + private final Handler mListenerHandler; + + ListenerTransport(LocationListener listener, Looper looper) { + mListener = listener; + + if (looper == null) { + mListenerHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + _handleMessage(msg); + } + }; + } else { + mListenerHandler = new Handler(looper) { + @Override + public void handleMessage(Message msg) { + _handleMessage(msg); + } + }; + } + } + + public void onLocationChanged(Location location) { + Message msg = Message.obtain(); + msg.what = TYPE_LOCATION_CHANGED; + msg.obj = location; + mListenerHandler.sendMessage(msg); + } + + public void onStatusChanged(String provider, int status, Bundle extras) { + Message msg = Message.obtain(); + msg.what = TYPE_STATUS_CHANGED; + Bundle b = new Bundle(); + b.putString("provider", provider); + b.putInt("status", status); + if (extras != null) { + b.putBundle("extras", extras); + } + msg.obj = b; + mListenerHandler.sendMessage(msg); + } + + public void onProviderEnabled(String provider) { + Message msg = Message.obtain(); + msg.what = TYPE_PROVIDER_ENABLED; + msg.obj = provider; + mListenerHandler.sendMessage(msg); + } + + public void onProviderDisabled(String provider) { + Message msg = Message.obtain(); + msg.what = TYPE_PROVIDER_DISABLED; + msg.obj = provider; + mListenerHandler.sendMessage(msg); + } + + private void _handleMessage(Message msg) { + switch (msg.what) { + case TYPE_LOCATION_CHANGED: + Location location = new Location((Location) msg.obj); + mListener.onLocationChanged(location); + break; + case TYPE_STATUS_CHANGED: + Bundle b = (Bundle) msg.obj; + String provider = b.getString("provider"); + int status = b.getInt("status"); + Bundle extras = b.getBundle("extras"); + mListener.onStatusChanged(provider, status, extras); + break; + case TYPE_PROVIDER_ENABLED: + mListener.onProviderEnabled((String) msg.obj); + break; + case TYPE_PROVIDER_DISABLED: + mListener.onProviderDisabled((String) msg.obj); + break; + } + } + } + /** + * @hide - hide this constructor because it has a parameter + * of type ILocationManager, which is a system private class. The + * right way to create an instance of this class is using the + * factory Context.getSystemService. + */ + public LocationManager(ILocationManager service) { + if (Config.LOGD) { + Log.d(TAG, "Constructor: service = " + service); + } + mService = service; + } + + private LocationProvider createProvider(String name, Bundle info) { + DummyLocationProvider provider = + new DummyLocationProvider(name); + provider.setRequiresNetwork(info.getBoolean("network")); + provider.setRequiresSatellite(info.getBoolean("satellite")); + provider.setRequiresCell(info.getBoolean("cell")); + provider.setHasMonetaryCost(info.getBoolean("cost")); + provider.setSupportsAltitude(info.getBoolean("altitude")); + provider.setSupportsSpeed(info.getBoolean("speed")); + provider.setSupportsBearing(info.getBoolean("bearing")); + provider.setPowerRequirement(info.getInt("power")); + provider.setAccuracy(info.getInt("accuracy")); + return provider; + } + + /** + * Returns a list of the names of all known location providers. All + * providers are returned, including ones that are not permitted to be + * accessed by the calling activity or are currently disabled. + * + * @return list of Strings containing names of the providers + */ + public List getAllProviders() { + if (Config.LOGD) { + Log.d(TAG, "getAllProviders"); + } + try { + return mService.getAllProviders(); + } catch (RemoteException ex) { + Log.e(TAG, "getAllProviders: RemoteException", ex); + } + return null; + } + + /** + * Returns a list of the names of location providers. Only providers that + * are permitted to be accessed by the calling activity will be returned. + * + * @param enabledOnly if true then only the providers which are currently + * enabled are returned. + * @return list of Strings containing names of the providers + */ + public List getProviders(boolean enabledOnly) { + try { + return mService.getProviders(enabledOnly); + } catch (RemoteException ex) { + Log.e(TAG, "getProviders: RemoteException", ex); + } + return null; + } + + /** + * Returns the information associated with the location provider of the + * given name, or null if no provider exists by that name. + * + * @param name the provider name + * @return a LocationProvider, or null + * + * @throws IllegalArgumentException if name is null + * @throws SecurityException if the caller is not permitted to access the + * given provider. + */ + public LocationProvider getProvider(String name) { + if (name == null) { + throw new IllegalArgumentException("name==null"); + } + try { + Bundle info = mService.getProviderInfo(name); + if (info == null) { + return null; + } + return createProvider(name, info); + } catch (RemoteException ex) { + Log.e(TAG, "getProvider: RemoteException", ex); + } + return null; + } + + /** + * Returns a list of the names of LocationProviders that satisfy the given + * criteria, or null if none do. Only providers that are permitted to be + * accessed by the calling activity will be returned. + * + * @param criteria the criteria that the returned providers must match + * @param enabledOnly if true then only the providers which are currently + * enabled are returned. + * @return list of Strings containing names of the providers + */ + public List getProviders(Criteria criteria, boolean enabledOnly) { + List goodProviders = Collections.emptyList(); + List providers = getProviders(enabledOnly); + for (String providerName : providers) { + LocationProvider provider = getProvider(providerName); + if (provider.meetsCriteria(criteria)) { + if (goodProviders.isEmpty()) { + goodProviders = new ArrayList(); + } + goodProviders.add(providerName); + } + } + return goodProviders; + } + + /** + * 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 + */ + private int nextPower(int power) { + switch (power) { + case Criteria.POWER_LOW: + return Criteria.POWER_MEDIUM; + case Criteria.POWER_MEDIUM: + return Criteria.POWER_HIGH; + case Criteria.POWER_HIGH: + return Criteria.NO_REQUIREMENT; + case Criteria.NO_REQUIREMENT: + default: + return Criteria.NO_REQUIREMENT; + } + } + + /** + * Returns the next looser accuracy requirement, in the sequence: + * + * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT + */ + private int nextAccuracy(int accuracy) { + if (accuracy == Criteria.ACCURACY_FINE) { + return Criteria.ACCURACY_COARSE; + } else { + return Criteria.NO_REQUIREMENT; + } + } + + private abstract class LpComparator implements Comparator { + + public int compare(int a1, int a2) { + if (a1 < a2) { + return -1; + } else if (a1 > a2) { + return 1; + } else { + return 0; + } + } + + public int compare(float a1, float a2) { + if (a1 < a2) { + return -1; + } else if (a1 > a2) { + return 1; + } else { + return 0; + } + } + } + + private class LpPowerComparator extends LpComparator { + public int compare(LocationProvider l1, LocationProvider l2) { + int a1 = l1.getPowerRequirement(); + int a2 = l2.getPowerRequirement(); + return compare(a1, a2); // Smaller is better + } + + public boolean equals(LocationProvider l1, LocationProvider l2) { + int a1 = l1.getPowerRequirement(); + int a2 = l2.getPowerRequirement(); + return a1 == a2; + } + } + + private class LpAccuracyComparator extends LpComparator { + public int compare(LocationProvider l1, LocationProvider l2) { + int a1 = l1.getAccuracy(); + int a2 = l2.getAccuracy(); + return compare(a1, a2); // Smaller is better + } + + public boolean equals(LocationProvider l1, LocationProvider l2) { + int a1 = l1.getAccuracy(); + int a2 = l2.getAccuracy(); + return a1 == a2; + } + } + + private class LpCapabilityComparator extends LpComparator { + + private static final int ALTITUDE_SCORE = 4; + private static final int BEARING_SCORE = 4; + private static final int SPEED_SCORE = 4; + + private int score(LocationProvider p) { + return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) + + (p.supportsBearing() ? BEARING_SCORE : 0) + + (p.supportsSpeed() ? SPEED_SCORE : 0); + } + + public int compare(LocationProvider l1, LocationProvider l2) { + int a1 = score(l1); + int a2 = score(l2); + return compare(-a1, -a2); // Bigger is better + } + + public boolean equals(LocationProvider l1, LocationProvider l2) { + int a1 = score(l1); + int a2 = score(l2); + return a1 == a2; + } + } + + private LocationProvider best(List providerNames) { + List providers = new ArrayList(providerNames.size()); + for (String name : providerNames) { + providers.add(getProvider(name)); + } + + if (providers.size() < 2) { + return providers.get(0); + } + + // First, sort by power requirement + Collections.sort(providers, new LpPowerComparator()); + int power = providers.get(0).getPowerRequirement(); + if (power < providers.get(1).getPowerRequirement()) { + return providers.get(0); + } + + int idx, size; + + List tmp = new ArrayList(); + idx = 0; + size = providers.size(); + while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) { + tmp.add(providers.get(idx)); + idx++; + } + + // Next, sort by accuracy + Collections.sort(tmp, new LpAccuracyComparator()); + int acc = tmp.get(0).getAccuracy(); + if (acc < tmp.get(1).getAccuracy()) { + return tmp.get(0); + } + + List tmp2 = new ArrayList(); + idx = 0; + size = tmp.size(); + while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) { + tmp2.add(tmp.get(idx)); + idx++; + } + + // Finally, sort by capability "score" + Collections.sort(tmp2, new LpCapabilityComparator()); + return tmp2.get(0); + } + + /** + * Returns the name of the provider that best meets the given criteria. Only providers + * that are permitted to be accessed by the calling activity will be + * returned. If several providers meet the criteria, the one with the best + * accuracy is returned. If no provider meets the criteria, + * the criteria are loosened in the following sequence: + * + *
    + *
  • power requirement + *
  • accuracy + *
  • bearing + *
  • speed + *
  • altitude + *
+ * + *

Note that the requirement on monetary cost is not removed + * in this process. + * + * @param criteria the criteria that need to be matched + * @param enabledOnly if true then only a provider that is currently enabled is returned + * @return name of the provider that best matches the requirements + */ + public String getBestProvider(Criteria criteria, boolean enabledOnly) { + List goodProviders = getProviders(criteria, enabledOnly); + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + + // Make a copy of the criteria that we can modify + criteria = new Criteria(criteria); + + // Loosen power requirement + int power = criteria.getPowerRequirement(); + while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) { + power = nextPower(power); + criteria.setPowerRequirement(power); + goodProviders = getProviders(criteria, enabledOnly); + } + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + +// // Loosen response time requirement +// int responseTime = criteria.getPreferredResponseTime(); +// while (goodProviders.isEmpty() && +// (responseTime != Criteria.NO_REQUIREMENT)) { +// responseTime += 1000; +// if (responseTime > 60000) { +// responseTime = Criteria.NO_REQUIREMENT; +// } +// criteria.setPreferredResponseTime(responseTime); +// goodProviders = getProviders(criteria); +// } +// if (!goodProviders.isEmpty()) { +// return best(goodProviders); +// } + + // Loosen accuracy requirement + int accuracy = criteria.getAccuracy(); + while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) { + accuracy = nextAccuracy(accuracy); + criteria.setAccuracy(accuracy); + goodProviders = getProviders(criteria, enabledOnly); + } + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + + // Remove bearing requirement + criteria.setBearingRequired(false); + goodProviders = getProviders(criteria, enabledOnly); + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + + // Remove speed requirement + criteria.setSpeedRequired(false); + goodProviders = getProviders(criteria, enabledOnly); + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + + // Remove altitude requirement + criteria.setAltitudeRequired(false); + goodProviders = getProviders(criteria, enabledOnly); + if (!goodProviders.isEmpty()) { + return best(goodProviders).getName(); + } + + return null; + } + + /** + * Registers the current activity to be notified periodically by + * the named provider. Periodically, the supplied LocationListener will + * be called with the current Location or with status updates. + * + *

It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + *

In case the provider is disabled by the user, updates will stop, + * and the {@link LocationListener#onProviderDisabled(String)} + * method will be called. As soon as the provider is enabled again, + * the {@link LocationListener#onProviderEnabled(String)} method will + * be called and location updates will start again. + * + *

The frequency of notification may be controlled using the + * minTime and minDistance parameters. If minTime is greater than 0, + * the LocationManager could potentially rest for minTime milliseconds + * between location updates to conserve power. If minDistance is greater than 0, + * a location will only be broadcasted if the device moves by minDistance meters. + * To obtain notifications as frequently as possible, set both parameters to 0. + * + *

Background services should be careful about setting a sufficiently high + * minTime so that the device doesn't consume too much power by keeping the + * GPS or wireless radios on all the time. In particular, values under 60000ms + * are not recommended. + * + *

The calling thread must be a {@link android.os.Looper} thread such as + * the main thread of the calling Activity. + * + * @param provider the name of the provider with which to register + * @param minTime the minimum time interval for notifications, in + * milliseconds. This field is only used as a hint to conserve power, and actual + * time between location updates may be greater or lesser than this value. + * @param minDistance the minimum distance interval for notifications, + * in meters + * @param listener a {#link LocationListener} whose + * {@link LocationListener#onLocationChanged} method will be called for + * each location update + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if listener is null + * @throws RuntimeException if the calling thread has no Looper + * @throws SecurityException if no suitable permission is present for the provider. + */ + public void requestLocationUpdates(String provider, + long minTime, float minDistance, LocationListener listener) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener==null"); + } + _requestLocationUpdates(provider, minTime, minDistance, listener, null); + } + + /** + * Registers the current activity to be notified periodically by + * the named provider. Periodically, the supplied LocationListener will + * be called with the current Location or with status updates. + * + *

It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + *

In case the provider is disabled by the user, updates will stop, + * and the {@link LocationListener#onProviderDisabled(String)} + * method will be called. As soon as the provider is enabled again, + * the {@link LocationListener#onProviderEnabled(String)} method will + * be called and location updates will start again. + * + *

The frequency of notification may be controlled using the + * minTime and minDistance parameters. If minTime is greater than 0, + * the LocationManager could potentially rest for minTime milliseconds + * between location updates to conserve power. If minDistance is greater than 0, + * a location will only be broadcasted if the device moves by minDistance meters. + * To obtain notifications as frequently as possible, set both parameters to 0. + * + *

Background services should be careful about setting a sufficiently high + * minTime so that the device doesn't consume too much power by keeping the + * GPS or wireless radios on all the time. In particular, values under 60000ms + * are not recommended. + * + *

The supplied Looper is used to implement the callback mechanism. + * + * @param provider the name of the provider with which to register + * @param minTime the minimum time interval for notifications, in + * milliseconds. This field is only used as a hint to conserve power, and actual + * time between location updates may be greater or lesser than this value. + * @param minDistance the minimum distance interval for notifications, + * in meters + * @param listener a {#link LocationListener} whose + * {@link LocationListener#onLocationChanged} method will be called for + * each location update + * @param looper a Looper object whose message queue will be used to + * implement the callback mechanism. + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if listener is null + * @throws IllegalArgumentException if looper is null + * @throws SecurityException if no suitable permission is present for the provider. + */ + public void requestLocationUpdates(String provider, + long minTime, float minDistance, LocationListener listener, + Looper looper) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + if (listener == null) { + throw new IllegalArgumentException("listener==null"); + } + if (looper == null) { + throw new IllegalArgumentException("looper==null"); + } + _requestLocationUpdates(provider, minTime, minDistance, listener, looper); + } + + private void _requestLocationUpdates(String provider, + long minTime, float minDistance, LocationListener listener, + Looper looper) { + if (minTime < 0L) { + minTime = 0L; + } + if (minDistance < 0.0f) { + minDistance = 0.0f; + } + + try { + synchronized (mListeners) { + ListenerTransport transport = mListeners.get(listener); + if (transport == null) { + transport = new ListenerTransport(listener, looper); + } + mListeners.put(listener, transport); + mService.requestLocationUpdates(provider, minTime, minDistance, transport); + } + } catch (RemoteException ex) { + Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex); + } + } + + /** + * Registers the current activity to be notified periodically by + * the named provider. Periodically, the supplied PendingIntent will + * be broadcast with the current Location or with status updates. + * + *

Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value. + * + *

It may take a while to receive the most recent location. If + * an immediate location is required, applications may use the + * {@link #getLastKnownLocation(String)} method. + * + *

The frequency of notification or new locations may be controlled using the + * minTime and minDistance parameters. If minTime is greater than 0, + * the LocationManager could potentially rest for minTime milliseconds + * between location updates to conserve power. If minDistance is greater than 0, + * a location will only be broadcast if the device moves by minDistance meters. + * To obtain notifications as frequently as possible, set both parameters to 0. + * + *

Background services should be careful about setting a sufficiently high + * minTime so that the device doesn't consume too much power by keeping the + * GPS or wireless radios on all the time. In particular, values under 60000ms + * are not recommended. + * + *

In case the provider is disabled by the user, updates will stop, + * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value + * of false. If the provider is re-enabled, an intent will be sent with an + * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will + * start again. + * + *

If the provider's status changes, an intent will be sent with an extra with key + * KEY_STATUS_CHANGED and an integer value indicating the new status. Any extras associated + * with the status update will be sent as well. + * + * @param provider the name of the provider with which to register + * @param minTime the minimum time interval for notifications, in + * milliseconds. This field is only used as a hint to conserve power, and actual + * time between location updates may be greater or lesser than this value. + * @param minDistance the minimum distance interval for notifications, + * in meters + * @param intent a {#link PendingIntet} to be sent for each location update + * + * @throws IllegalArgumentException if provider is null or doesn't exist + * @throws IllegalArgumentException if intent is null + * @throws SecurityException if no suitable permission is present for the provider. + */ + public void requestLocationUpdates(String provider, + long minTime, float minDistance, PendingIntent intent) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + if (intent == null) { + throw new IllegalArgumentException("intent==null"); + } + _requestLocationUpdates(provider, minTime, minDistance, intent); + } + + private void _requestLocationUpdates(String provider, + long minTime, float minDistance, PendingIntent intent) { + if (minTime < 0L) { + minTime = 0L; + } + if (minDistance < 0.0f) { + minDistance = 0.0f; + } + + try { + mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent); + } catch (RemoteException ex) { + Log.e(TAG, "requestLocationUpdates: RemoteException", ex); + } + } + + /** + * Removes any current registration for location updates of the current activity + * with the given LocationListener. Following this call, updates will no longer + * occur for this listener. + * + * @param listener {#link LocationListener} object that no longer needs location updates + * @throws IllegalArgumentException if listener is null + */ + public void removeUpdates(LocationListener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener==null"); + } + if (Config.LOGD) { + Log.d(TAG, "removeUpdates: listener = " + listener); + } + try { + ListenerTransport transport = mListeners.remove(listener); + if (transport != null) { + mService.removeUpdates(transport); + } + } catch (RemoteException ex) { + Log.e(TAG, "removeUpdates: DeadObjectException", ex); + } + } + + /** + * Removes any current registration for location updates of the current activity + * with the given PendingIntent. Following this call, updates will no longer + * occur for this intent. + * + * @param intent {#link PendingIntent} object that no longer needs location updates + * @throws IllegalArgumentException if intent is null + */ + public void removeUpdates(PendingIntent intent) { + if (intent == null) { + throw new IllegalArgumentException("intent==null"); + } + if (Config.LOGD) { + Log.d(TAG, "removeUpdates: intent = " + intent); + } + try { + mService.removeUpdatesPI(intent); + } catch (RemoteException ex) { + Log.e(TAG, "removeUpdates: RemoteException", ex); + } + } + + /** + * Sets a proximity alert for the location given by the position + * (latitude, longitude) and the given radius. When the device + * detects that it has entered or exited the area surrounding the + * location, the given PendingIntent will be used to create an Intent + * to be fired. + * + *

The fired Intent will have a boolean extra added with key + * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is + * entering the proximity region; if false, it is exiting. + * + *

Due to the approximate nature of position estimation, if the + * device passes through the given area briefly, it is possible + * that no Intent will be fired. Similarly, an Intent could be + * fired if the device passes very close to the given area but + * does not actually enter it. + * + *

After the number of milliseconds given by the expiration + * parameter, the location manager will delete this proximity + * alert and no longer monitor it. A value of -1 indicates that + * there should be no expiration time. + * + *

In case the screen goes to sleep, checks for proximity alerts + * happen only once every 4 minutes. This conserves battery life by + * ensuring that the device isn't perpetually awake. + * + *

Internally, this method uses both {@link #NETWORK_PROVIDER} + * and {@link #GPS_PROVIDER}. + * + * @param latitude the latitude of the central point of the + * alert region + * @param longitude the longitude of the central point of the + * alert region + * @param radius the radius of the central point of the + * alert region, in meters + * @param expiration time for this proximity alert, in milliseconds, + * or -1 to indicate no expiration + * @param intent a PendingIntent that will be used to generate an Intent to + * fire when entry to or exit from the alert region is detected + * + * @throws SecurityException if no permission exists for the required + * providers. + */ + public void addProximityAlert(double latitude, double longitude, + float radius, long expiration, PendingIntent intent) { + if (Config.LOGD) { + Log.d(TAG, "addProximityAlert: latitude = " + latitude + + ", longitude = " + longitude + ", radius = " + radius + + ", expiration = " + expiration + + ", intent = " + intent); + } + try { + mService.addProximityAlert(latitude, longitude, radius, + expiration, intent); + } catch (RemoteException ex) { + Log.e(TAG, "addProximityAlert: RemoteException", ex); + } + } + + /** + * Removes the proximity alert with the given PendingIntent. + * + * @param intent the PendingIntent that no longer needs to be notified of + * proximity alerts + */ + public void removeProximityAlert(PendingIntent intent) { + if (Config.LOGD) { + Log.d(TAG, "removeProximityAlert: intent = " + intent); + } + try { + mService.removeProximityAlert(intent); + } catch (RemoteException ex) { + Log.e(TAG, "removeProximityAlert: RemoteException", ex); + } + } + + /** + * Returns the current enabled/disabled status of the given provider. If the + * user has enabled this provider in the Settings menu, true is returned + * otherwise false is returned + * + * @param provider the name of the provider + * @return true if the provider is enabled + * + * @throws SecurityException if no suitable permission is present for the provider. + * @throws IllegalArgumentException if provider is null or doesn't exist + */ + public boolean isProviderEnabled(String provider) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + try { + return mService.isProviderEnabled(provider); + } catch (RemoteException ex) { + Log.e(TAG, "isProviderEnabled: RemoteException", ex); + return false; + } + } + + /** + * Returns a Location indicating the data from the last known + * location fix obtained from the given provider. This can be done + * without starting the provider. Note that this location could + * be out-of-date, for example if the device was turned off and + * moved to another location. + * + *

If the provider is currently disabled, null is returned. + * + * @param provider the name of the provider + * @return the last known location for the provider, or null + * + * @throws SecurityException if no suitable permission is present for the provider. + * @throws IllegalArgumentException if provider is null or doesn't exist + */ + public Location getLastKnownLocation(String provider) { + if (provider == null) { + throw new IllegalArgumentException("provider==null"); + } + try { + return mService.getLastKnownLocation(provider); + } catch (RemoteException ex) { + Log.e(TAG, "getLastKnowLocation: RemoteException", ex); + return null; + } + } + + // Mock provider support + + /** + * Creates a mock location provider and adds it to the set of active providers. + * + * @param name the provider name + * @param requiresNetwork + * @param requiresSatellite + * @param requiresCell + * @param hasMonetaryCost + * @param supportsAltitude + * @param supportsSpeed + * @param supportsBearing + * @param powerRequirement + * @param accuracy + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled + * @throws IllegalArgumentException if a provider with the given name already exists + */ + public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, + boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, + boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) { + try { + mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell, + hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement, + accuracy); + } catch (RemoteException ex) { + Log.e(TAG, "addTestProvider: RemoteException", ex); + } + } + + /** + * Removes the mock location provider with the given name. + * + * @param provider the provider name + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void removeTestProvider(String provider) { + try { + mService.removeTestProvider(provider); + } catch (RemoteException ex) { + Log.e(TAG, "removeTestProvider: RemoteException", ex); + } + } + + /** + * Sets a mock location for the given provider. This location will be used in place + * of any actual location from the provider. + * + * @param provider the provider name + * @param loc the mock location + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void setTestProviderLocation(String provider, Location loc) { + try { + mService.setTestProviderLocation(provider, loc); + } catch (RemoteException ex) { + Log.e(TAG, "setTestProviderLocation: RemoteException", ex); + } + } + + /** + * Removes any mock location associated with the given provider. + * + * @param provider the provider name + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void clearTestProviderLocation(String provider) { + try { + mService.clearTestProviderLocation(provider); + } catch (RemoteException ex) { + Log.e(TAG, "clearTestProviderLocation: RemoteException", ex); + } + } + + /** + * Sets a mock enabled value for the given provider. This value will be used in place + * of any actual value from the provider. + * + * @param provider the provider name + * @param enabled the mock enabled value + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void setTestProviderEnabled(String provider, boolean enabled) { + try { + mService.setTestProviderEnabled(provider, enabled); + } catch (RemoteException ex) { + Log.e(TAG, "setTestProviderEnabled: RemoteException", ex); + } + } + + /** + * Removes any mock enabled value associated with the given provider. + * + * @param provider the provider name + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void clearTestProviderEnabled(String provider) { + try { + mService.clearTestProviderEnabled(provider); + } catch (RemoteException ex) { + Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex); + } + + } + + /** + * Sets mock status values for the given provider. These values will be used in place + * of any actual values from the provider. + * + * @param provider the provider name + * @param status the mock status + * @param extras a Bundle containing mock extras + * @param updateTime the mock update time + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { + try { + mService.setTestProviderStatus(provider, status, extras, updateTime); + } catch (RemoteException ex) { + Log.e(TAG, "setTestProviderStatus: RemoteException", ex); + } + } + + /** + * Removes any mock status values associated with the given provider. + * + * @param provider the provider name + * + * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present + * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION + * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled + * @throws IllegalArgumentException if no provider with the given name exists + */ + public void clearTestProviderStatus(String provider) { + try { + mService.clearTestProviderStatus(provider); + } catch (RemoteException ex) { + Log.e(TAG, "clearTestProviderStatus: RemoteException", ex); + } + } + + // GPS-specific support + + // This class is used to send GPS status events to the client's main thread. + private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { + + private final GpsStatus.Listener mListener; + + GpsStatusListenerTransport(GpsStatus.Listener listener) { + mListener = listener; + } + + public void onGpsStarted() { + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_STARTED; + mGpsHandler.sendMessage(msg); + } + + public void onGpsStopped() { + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_STOPPED; + mGpsHandler.sendMessage(msg); + } + + public void onFirstFix(int ttff) { + mGpsStatus.setTimeToFirstFix(ttff); + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_FIRST_FIX; + mGpsHandler.sendMessage(msg); + } + + public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, + float[] elevations, float[] azimuths, int ephemerisMask, + int almanacMask, int usedInFixMask) { + mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, + ephemerisMask, almanacMask, usedInFixMask); + + Message msg = Message.obtain(); + msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; + // remove any SV status messages already in the queue + mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); + mGpsHandler.sendMessage(msg); + } + + private final Handler mGpsHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + // synchronize on mGpsStatus to ensure the data is copied atomically. + synchronized(mGpsStatus) { + mListener.onGpsStatusChanged(msg.what); + } + } + }; + } + + /** + * Adds a GPS status listener. + * + * @param listener GPS status listener object to register + * + * @return true if the listener was successfully added + * + * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present + */ + public boolean addGpsStatusListener(GpsStatus.Listener listener) { + boolean result; + + if (mGpsStatusListeners.get(listener) != null) { + // listener is already registered + return true; + } + try { + GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener); + result = mService.addGpsStatusListener(transport); + if (result) { + mGpsStatusListeners.put(listener, transport); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e); + result = false; + } + + return result; + } + + /** + * Removes a GPS status listener. + * + * @param listener GPS status listener object to remove + */ + public void removeGpsStatusListener(GpsStatus.Listener listener) { + try { + GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener); + if (transport != null) { + mService.removeGpsStatusListener(transport); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e); + } + } + + /** + * Retrieves information about the current status of the GPS engine. + * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged} + * callback to ensure that the data is copied atomically. + * + * The caller may either pass in a {@link GpsStatus} object to set with the latest + * status information, or pass null to create a new {@link GpsStatus} object. + * + * @param status object containing GPS status details, or null. + * @return status object containing updated GPS status. + */ + public GpsStatus getGpsStatus(GpsStatus status) { + if (status == null) { + status = new GpsStatus(); + } + status.setStatus(mGpsStatus); + return status; + } + + /** + * Sends additional commands to a location provider. + * Can be used to support provider specific extensions to the Location Manager API + * + * @param provider name of the location provider. + * @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 provider, String command, Bundle extras) { + try { + return mService.sendExtraCommand(provider, command, extras); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in sendExtraCommand: ", e); + return false; + } + } +} diff --git a/location/java/android/location/LocationProvider.java b/location/java/android/location/LocationProvider.java new file mode 100644 index 0000000..b1670d5 --- /dev/null +++ b/location/java/android/location/LocationProvider.java @@ -0,0 +1,160 @@ +/* + * 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; + +/** + * An abstract superclass for location providers. A location provider + * provides periodic reports on the geographical location of the + * device. + * + *

Each provider has a set of criteria under which it may be used; + * for example, some providers require GPS hardware and visibility to + * a number of satellites; others require the use of the cellular + * radio, or access to a specific carrier's network, or to the + * internet. They may also have different battery consumption + * characteristics or monetary costs to the user. The {@link + * Criteria} class allows providers to be selected based on + * user-specified criteria. + */ +public abstract class LocationProvider { + private static final String TAG = "LocationProvider"; + // A regular expression matching characters that may not appear + // in the name of a LocationProvider. + static final String BAD_CHARS_REGEX = "[^a-zA-Z0-9]"; + + private String mName; + + public static final int OUT_OF_SERVICE = 0; + public static final int TEMPORARILY_UNAVAILABLE = 1; + public static final int AVAILABLE = 2; + + /** + * Constructs a LocationProvider with the given name. Provider names must + * consist only of the characters [a-zA-Z0-9]. + * + * @throws IllegalArgumentException if name contains an illegal character + */ + LocationProvider(String name) { + if (name.matches(BAD_CHARS_REGEX)) { + throw new IllegalArgumentException("name " + name + + " contains an illegal character"); + } + // Log.d(TAG, "Constructor: name = " + name); + mName = name; + } + + /** + * Returns the name of this provider. + */ + public String getName() { + return mName; + } + + /** + * Returns true if this provider meets the given criteria, + * false otherwise. + */ + public boolean meetsCriteria(Criteria criteria) { + if ((criteria.getAccuracy() != Criteria.NO_REQUIREMENT) && + (criteria.getAccuracy() < getAccuracy())) { + return false; + } + int criteriaPower = criteria.getPowerRequirement(); + if ((criteriaPower != Criteria.NO_REQUIREMENT) && + (criteriaPower < getPowerRequirement())) { + return false; + } + if (criteria.isAltitudeRequired() && !supportsAltitude()) { + return false; + } + if (criteria.isSpeedRequired() && !supportsSpeed()) { + return false; + } + if (criteria.isBearingRequired() && !supportsBearing()) { + return false; + } + return true; + } + + /** + * Returns true if the provider requires access to a + * data network (e.g., the Internet), false otherwise. + */ + public abstract boolean requiresNetwork(); + + /** + * Returns true if the provider requires access to a + * satellite-based positioning system (e.g., GPS), false + * otherwise. + */ + public abstract boolean requiresSatellite(); + + /** + * Returns true if the provider requires access to an appropriate + * cellular network (e.g., to make use of cell tower IDs), false + * otherwise. + */ + public abstract boolean requiresCell(); + + /** + * Returns true if the use of this provider may result in a + * monetary charge to the user, false if use is free. It is up to + * each provider to give accurate information. + */ + public abstract boolean hasMonetaryCost(); + + /** + * Returns true if the provider is able to provide altitude + * information, false otherwise. A provider that reports altitude + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean supportsAltitude(); + + /** + * Returns true if the provider is able to provide speed + * information, false otherwise. A provider that reports speed + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean supportsSpeed(); + + /** + * Returns true if the provider is able to provide bearing + * information, false otherwise. A provider that reports bearing + * under most circumstances but may occassionally not report it + * should return true. + */ + public abstract boolean supportsBearing(); + + /** + * Returns the power requirement for this provider. + * + * @return the power requirement for this provider, as one of the + * constants Criteria.POWER_REQUIREMENT_*. + */ + public abstract int getPowerRequirement(); + + /** + * Returns a constant describing horizontal accuracy of this provider. + * If the provider returns finer grain or exact location, + * {@link Criteria#ACCURACY_FINE} is returned, otherwise if the + * location is only approximate then {@link Criteria#ACCURACY_COARSE} + * is returned. + */ + public abstract int getAccuracy(); +} diff --git a/location/java/android/location/LocationProviderImpl.java b/location/java/android/location/LocationProviderImpl.java new file mode 100644 index 0000000..0962992 --- /dev/null +++ b/location/java/android/location/LocationProviderImpl.java @@ -0,0 +1,261 @@ +/* + * 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 sProviders = + new ArrayList(); + private static HashMap sProvidersByName + = new HashMap(); + + 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 getProviders() { + return new ArrayList(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. + * + *

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/android/location/package.html b/location/java/android/location/package.html new file mode 100644 index 0000000..bbaeb42 --- /dev/null +++ b/location/java/android/location/package.html @@ -0,0 +1,12 @@ + + + + + + + + +

Classes defining Android location-based and related services.

+ + + -- cgit v1.1