summaryrefslogtreecommitdiffstats
path: root/location/java/android
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:31:44 -0800
commit9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch)
treed88beb88001f2482911e3d28e43833b50e4b4e97 /location/java/android
parentd83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff)
downloadframeworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.zip
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.gz
frameworks_base-9066cfe9886ac131c34d59ed0e2d287b0e3c0087.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'location/java/android')
-rw-r--r--location/java/android/location/Address.aidl19
-rw-r--r--location/java/android/location/Address.java516
-rw-r--r--location/java/android/location/Criteria.aidl19
-rw-r--r--location/java/android/location/Criteria.java242
-rw-r--r--location/java/android/location/DummyLocationProvider.java168
-rw-r--r--location/java/android/location/Geocoder.java242
-rw-r--r--location/java/android/location/GpsSatellite.java117
-rw-r--r--location/java/android/location/GpsStatus.java200
-rw-r--r--location/java/android/location/IGpsStatusListener.aidl32
-rw-r--r--location/java/android/location/ILocationListener.aidl32
-rw-r--r--location/java/android/location/ILocationManager.aidl76
-rw-r--r--location/java/android/location/Location.aidl19
-rw-r--r--location/java/android/location/Location.java741
-rw-r--r--location/java/android/location/LocationListener.java82
-rw-r--r--location/java/android/location/LocationManager.java1268
-rw-r--r--location/java/android/location/LocationProvider.java160
-rw-r--r--location/java/android/location/LocationProviderImpl.java261
-rw-r--r--location/java/android/location/package.html12
18 files changed, 4206 insertions, 0 deletions
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<Integer, String> 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<Integer, String>();
+ }
+ 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.
+ *
+ * <!--
+ * <p> 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.
+ *
+ * <ul>
+ * </ul>
+ * -->
+ */
+ 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<Address> CREATOR =
+ new Parcelable.Creator<Address>() {
+ 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<Integer, String>(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<Map.Entry<Integer, String>> entries = mAddressLines.entrySet();
+ parcel.writeInt(entries.size());
+ for (Map.Entry<Integer, String> 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<Criteria> CREATOR =
+ new Parcelable.Creator<Criteria>() {
+ 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.
+ *
+ * <p> 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<Address> 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<Address> results = new ArrayList<Address>();
+ 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.
+ *
+ * <p> 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<Address> getFromLocationName(String locationName, int maxResults) throws IOException {
+ if (locationName == null) {
+ throw new IllegalArgumentException("locationName == null");
+ }
+ try {
+ List<Address> results = new ArrayList<Address>();
+ 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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<Address> 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<Address> result = new ArrayList<Address>();
+ 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<GpsSatellite> {
+
+ 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<GpsSatellite> mSatelliteList = new Iterable<GpsSatellite>() {
+ public Iterator<GpsSatellite> 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:
+ * <ul>
+ * <li> {@link GpsStatus#GPS_EVENT_STARTED}
+ * <li> {@link GpsStatus#GPS_EVENT_STOPPED}
+ * <li> {@link GpsStatus#GPS_EVENT_FIRST_FIX}
+ * <li> {@link GpsStatus#GPS_EVENT_SATELLITE_STATUS}
+ * </ul>
+ *
+ * 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<GpsSatellite> 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<Address> addrs);
+ String getFromLocationName(String locationName,
+ double lowerLeftLatitude, double lowerLeftLongitude,
+ double upperRightLatitude, double upperRightLongitude, int maxResults,
+ String language, String country, String variant, String appName, out List<Address> addrs);
+
+ 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <ul>
+ * <li> satellites - the number of satellites used to derive the fix
+ * </ul>
+ */
+ 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<Location> CREATOR =
+ new Parcelable.Creator<Location>() {
+ 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <ul>
+ * <li> satellites - the number of satellites used to derive the fix
+ * </ul>
+ */
+ 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.
+ *
+ * <p>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<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
+ new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
+ 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.
+ *
+ * <p> The extras Bundle for the GPS location provider can contain the
+ * following key/value pairs:
+ *
+ * <ul>
+ * <li> satellites - the number of satellites used to derive the fix
+ * </ul>
+ */
+ 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<LocationListener,ListenerTransport> mListeners =
+ new HashMap<LocationListener,ListenerTransport>();
+
+ 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<String> 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<String> 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<String> getProviders(Criteria criteria, boolean enabledOnly) {
+ List<String> goodProviders = Collections.emptyList();
+ List<String> providers = getProviders(enabledOnly);
+ for (String providerName : providers) {
+ LocationProvider provider = getProvider(providerName);
+ if (provider.meetsCriteria(criteria)) {
+ if (goodProviders.isEmpty()) {
+ goodProviders = new ArrayList<String>();
+ }
+ 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<LocationProvider> {
+
+ 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<String> providerNames) {
+ List<LocationProvider> providers = new ArrayList<LocationProvider>(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<LocationProvider> tmp = new ArrayList<LocationProvider>();
+ 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<LocationProvider> tmp2 = new ArrayList<LocationProvider>();
+ 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:
+ *
+ * <ul>
+ * <li> power requirement
+ * <li> accuracy
+ * <li> bearing
+ * <li> speed
+ * <li> altitude
+ * </ul>
+ *
+ * <p> 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<String> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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<LocationProviderImpl> sProviders =
+ new ArrayList<LocationProviderImpl>();
+ private static HashMap<String, LocationProviderImpl> sProvidersByName
+ = new HashMap<String, LocationProviderImpl>();
+
+ private boolean mLocationTracking = false;
+ private long mMinTime = 0;
+
+ protected LocationProviderImpl(String name) {
+ super(name);
+ }
+
+ public static void addProvider(LocationProviderImpl provider) {
+ sProviders.add(provider);
+ sProvidersByName.put(provider.getName(), provider);
+ }
+
+ public static void removeProvider(LocationProviderImpl provider) {
+ sProviders.remove(provider);
+ sProvidersByName.remove(provider.getName());
+ }
+
+ public static List<LocationProviderImpl> getProviders() {
+ return new ArrayList<LocationProviderImpl>(sProviders);
+ }
+
+ public static LocationProviderImpl getProvider(String name) {
+ return sProvidersByName.get(name);
+ }
+
+ public static LocationProviderImpl loadFromClass(File classFile) {
+ if (!classFile.exists()) {
+ return null;
+ }
+ if (Config.LOGD) {
+ Log.d(TAG, "Loading class specifier file " + classFile.getPath());
+ }
+ String className = null;
+ try {
+ BufferedReader br =
+ new BufferedReader(new FileReader(classFile), 8192);
+ className = br.readLine();
+ br.close();
+ Class providerClass = Class.forName(className);
+ if (Config.LOGD) {
+ Log.d(TAG, "Loading provider class " + providerClass.getName());
+ }
+ LocationProviderImpl provider =
+ (LocationProviderImpl) providerClass.newInstance();
+ if (Config.LOGD) {
+ Log.d(TAG, "Got provider instance " + provider);
+ }
+
+ return provider;
+ } catch (IOException ioe) {
+ Log.e(TAG, "IOException loading config file " +
+ classFile.getPath(), ioe);
+ } catch (IllegalAccessException iae) {
+ Log.e(TAG, "IllegalAccessException loading class " +
+ className, iae);
+ } catch (InstantiationException ie) {
+ Log.e(TAG, "InstantiationException loading class " +
+ className, ie);
+ } catch (ClassNotFoundException cnfe) {
+ Log.e(TAG, "ClassNotFoundException loading class " +
+ className, cnfe);
+ } catch (ClassCastException cce) {
+ Log.e(TAG, "ClassCastException loading class " +
+ className, cce);
+ }
+ return null;
+ }
+
+ /**
+ * Enables this provider. When enabled, calls to {@link #getStatus()}
+ * and {@link #getLocation} must be handled. Hardware may be started up
+ * when the provider is enabled.
+ */
+ public abstract void enable();
+
+ /**
+ * Disables this provider. When disabled, calls to {@link #getStatus()}
+ * and {@link #getLocation} need not be handled. Hardware may be shut
+ * down while the provider is disabled.
+ */
+ public abstract void disable();
+
+ /**
+ * Returns true if this provider is enabled, false otherwise;
+ */
+ public abstract boolean isEnabled();
+
+ /**
+ * Returns a information on the status of this provider.
+ * {@link #OUT_OF_SERVICE} is returned if the provider is
+ * out of service, and this is not expected to change in the near
+ * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
+ * the provider is temporarily unavailable but is expected to be
+ * available shortly; and {@link #AVAILABLE} is returned
+ * if the provider is currently available.
+ */
+ public int getStatus() {
+ return getStatus(null);
+ }
+
+ /**
+ * Returns a information on the status of this provider.
+ * {@link #OUT_OF_SERVICE} is returned if the provider is
+ * out of service, and this is not expected to change in the near
+ * future; {@link #TEMPORARILY_UNAVAILABLE} is returned if
+ * the provider is temporarily unavailable but is expected to be
+ * available shortly; and {@link #AVAILABLE} is returned
+ * if the provider is currently available.
+ *
+ * <p> If extras is non-null, additional status information may be
+ * added to it in the form of provider-specific key/value pairs.
+ */
+ public abstract int getStatus(Bundle extras);
+
+ /**
+ * Returns the time at which the status was last updated. It is the
+ * responsibility of the provider to appropriately set this value
+ * using {@link android.os.SystemClock.elapsedRealtime()} each time
+ * there is a status update that it wishes to broadcast to all its
+ * listeners. The provider should be careful not to broadcast
+ * the same status again.
+ *
+ * @return time of last status update in millis since last reboot
+ */
+ public long getStatusUpdateTime() {
+ return 0;
+ }
+
+ /**
+ * Sets a Location object with the information gathered
+ * during the most recent fix.
+ *
+ * @param l location object to set
+ * @return true if a location fix is available
+ */
+ public abstract boolean getLocation(Location l);
+
+ /**
+ * Notifies the location provider that clients are listening for locations.
+ * Called with enable set to true when the first client is added and
+ * called with enable set to false when the last client is removed.
+ * This allows the provider to prepare for receiving locations,
+ * and to shut down when no clients are remaining.
+ *
+ * @param enable true if location tracking should be enabled.
+ */
+ public void enableLocationTracking(boolean enable) {
+ mLocationTracking = enable;
+ }
+
+ /**
+ * Returns true if the provider has any listeners
+ *
+ * @return true if provider is being tracked
+ */
+ public boolean isLocationTracking() {
+ return mLocationTracking;
+ }
+
+ /**
+ * Notifies the location provider of the smallest minimum time between updates amongst
+ * all clients that are listening for locations. This allows the provider to reduce
+ * the frequency of updates to match the requested frequency.
+ *
+ * @param minTime the smallest minTime value over all listeners for this provider.
+ */
+ public void setMinTime(long minTime) {
+ mMinTime = minTime;
+ }
+
+ /**
+ * Gets the smallest minimum time between updates amongst all the clients listening
+ * for locations. By default this value is 0 (as frqeuently as possible)
+ *
+ * @return the smallest minTime value over all listeners for this provider
+ */
+ public long getMinTime() {
+ return mMinTime;
+ }
+
+ /**
+ * Updates the network state for the given provider. This function must
+ * be overwritten if {@link #requiresNetwork} returns true. The state is
+ * {@link #TEMPORARILY_UNAVAILABLE} (disconnected), OR {@link #AVAILABLE}
+ * (connected or connecting).
+ *
+ * @param state data state
+ */
+ public void updateNetworkState(int state) {
+ }
+
+ /**
+ * Updates the cell state for the given provider. This function must be
+ * overwritten if {@link #requiresCell} returns true.
+ *
+ * @param state cell state
+ */
+ public void updateCellState(CellState state) {
+ }
+
+ /**
+ * Implements addditional location provider specific additional commands.
+ *
+ * @param command name of the command to send to the provider.
+ * @param extras optional arguments for the command (or null).
+ * The provider may optionally fill the extras Bundle with results from the command.
+ *
+ * @return true if the command succeeds.
+ */
+ public boolean sendExtraCommand(String command, Bundle extras) {
+ return false;
+ }
+}
diff --git a/location/java/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 @@
+<html>
+<head>
+<script type="text/javascript" src="http://www.corp.google.com/style/prettify.js"></script>
+<script src="http://www.corp.google.com/eng/techpubs/include/navbar.js" type="text/javascript"></script>
+</head>
+
+<body>
+
+<p>Classes defining Android location-based and related services.</p>
+
+</body>
+</html>