diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:43 -0800 |
commit | f013e1afd1e68af5e3b868c26a653bbfb39538f8 (patch) | |
tree | 7ad6c8fd9c7b55f4b4017171dec1cb760bbd26bf /location/java | |
parent | e70cfafe580c6f2994c4827cd8a534aabf3eb05c (diff) | |
download | frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.zip frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.gz frameworks_base-f013e1afd1e68af5e3b868c26a653bbfb39538f8.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'location/java')
14 files changed, 834 insertions, 233 deletions
diff --git a/location/java/android/location/Geocoder.java b/location/java/android/location/Geocoder.java index 92a19e4..709ad23 100644 --- a/location/java/android/location/Geocoder.java +++ b/location/java/android/location/Geocoder.java @@ -228,7 +228,7 @@ public final class Geocoder { ArrayList<Address> result = new ArrayList<Address>(); String ex = mService.getFromLocationName(locationName, lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude, - maxResults, mLanguage, mCountry, mVariant, mAppName, new ArrayList<Address>()); + maxResults, mLanguage, mCountry, mVariant, mAppName, result); if (ex != null) { throw new IOException(ex); } else { 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/GpsStatusListener.java b/location/java/android/location/GpsStatusListener.java deleted file mode 100644 index e494887..0000000 --- a/location/java/android/location/GpsStatusListener.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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; - -/** - * Used for receiving notifications from the SensorManager when - * sensor values have changed. - * - * @hide - */ -public interface GpsStatusListener { - - /** - * Called when the GPS has started. - */ - void onGpsStarted(); - - /** - * Called when the GPS has stopped. - */ - void onGpsStopped(); - - /** - * Called when the GPS status has received its first fix since starting. - * - * @param ttff Time to first fix in milliseconds. - */ - void onFirstFix(int ttff); - - /** - * Called when the GPS SV status has changed. - * - * @param svCount The number of visible SVs - * @param prns Array of SV prns. Length of array is svCount. - * @param snrs Array of signal to noise ratios for SVs, in 1/10 dB units. Length of array is svCount. - * @param elevations Array of SV elevations in degrees. Length of array is svCount. - * @param azimuths Array of SV azimuths in degrees. Length of array is svCount. - * @param ephemerisMask Bit mask indicating which SVs the GPS has ephemeris data for. - * @param almanacMask Bit mask indicating which SVs the GPS has almanac data for. - * @param usedInFixMask Bit mask indicating which SVs were used in the most recent GPS fix. - */ - public void onSvStatusChanged(int svCount, int[] prns, float[] snrs, float[] elevations, - float[] azimuths, int ephemerisMask, int almanacMask, int usedInFixMask); -} diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index d3eefeb..69c404a 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -37,7 +37,10 @@ interface ILocationManager 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); diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index b5adb33..022ee25 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -47,8 +47,9 @@ import java.util.List; public class LocationManager { private static final String TAG = "LocationManager"; private ILocationManager mService; - private HashMap<GpsStatusListener, GpsStatusListenerTransport> mGpsStatusListeners = - new HashMap<GpsStatusListener, GpsStatusListenerTransport>(); + 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 @@ -82,6 +83,24 @@ public class LocationManager { */ 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"; @@ -180,7 +199,7 @@ public class LocationManager { /** * @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 + * right way to create an instance of this class is using the * factory Context.getSystemService. */ public LocationManager(ILocationManager service) { @@ -686,11 +705,9 @@ public class LocationManager { ListenerTransport transport = mListeners.get(listener); if (transport == null) { transport = new ListenerTransport(listener, looper); - mListeners.put(listener, transport); } mListeners.put(listener, transport); - mService.requestLocationUpdates(provider, minTime, minDistance, - transport); + mService.requestLocationUpdates(provider, minTime, minDistance, transport); } } catch (RemoteException ex) { Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex); @@ -698,6 +715,78 @@ public class LocationManager { } /** + * 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. @@ -723,6 +812,28 @@ public class LocationManager { } /** + * 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 @@ -865,9 +976,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite, boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude, @@ -887,9 +998,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void removeTestProvider(String provider) { try { @@ -907,9 +1018,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void setTestProviderLocation(String provider, Location loc) { try { @@ -925,9 +1036,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void clearTestProviderLocation(String provider) { try { @@ -945,9 +1056,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void setTestProviderEnabled(String provider, boolean enabled) { try { @@ -963,9 +1074,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void clearTestProviderEnabled(String provider) { try { @@ -986,9 +1097,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) { try { @@ -1004,9 +1115,9 @@ public class LocationManager { * @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 - * - * {@hide} */ public void clearTestProviderStatus(String provider) { try { @@ -1021,102 +1132,65 @@ public class LocationManager { // This class is used to send GPS status events to the client's main thread. private class GpsStatusListenerTransport extends IGpsStatusListener.Stub { - private GpsStatusListener mListener; - private int mTTFF; - private int mSvCount; - private int[] mPrns; - private float[] mSnrs; - private float[] mElevations; - private float[] mAzimuths; - private int mEphemerisMask; - private int mAlmanacMask; - private int mUsedInFixMask; - - private static final int GPS_STARTED = 0; - private static final int GPS_STOPPED = 1; - private static final int GPS_FIRST_FIX = 2; - private static final int GPS_SV_STATUS = 3; - - GpsStatusListenerTransport(GpsStatusListener listener) { + private final GpsStatus.Listener mListener; + + GpsStatusListenerTransport(GpsStatus.Listener listener) { mListener = listener; } public void onGpsStarted() { Message msg = Message.obtain(); - msg.what = GPS_STARTED; + msg.what = GpsStatus.GPS_EVENT_STARTED; mGpsHandler.sendMessage(msg); } public void onGpsStopped() { Message msg = Message.obtain(); - msg.what = GPS_STOPPED; + msg.what = GpsStatus.GPS_EVENT_STOPPED; mGpsHandler.sendMessage(msg); } public void onFirstFix(int ttff) { - mTTFF = ttff; + mGpsStatus.setTimeToFirstFix(ttff); Message msg = Message.obtain(); - msg.what = GPS_FIRST_FIX; + 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) { - // synchronize here to ensure SV count matches data in the arrays - synchronized(this) { - mSvCount = svCount; - mPrns = prns; - mSnrs = snrs; - mElevations = elevations; - mAzimuths = azimuths; - mEphemerisMask = ephemerisMask; - mAlmanacMask = almanacMask; - mUsedInFixMask = usedInFixMask; - } + mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths, + ephemerisMask, almanacMask, usedInFixMask); Message msg = Message.obtain(); - msg.what = GPS_SV_STATUS; + msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS; // remove any SV status messages already in the queue - mGpsHandler.removeMessages(GPS_SV_STATUS); + mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS); mGpsHandler.sendMessage(msg); } private final Handler mGpsHandler = new Handler() { @Override public void handleMessage(Message msg) { - switch (msg.what) { - case GPS_STARTED: - mListener.onGpsStarted(); - break; - case GPS_STOPPED: - mListener.onGpsStopped(); - break; - case GPS_FIRST_FIX: - mListener.onFirstFix(mTTFF); - break; - case GPS_SV_STATUS: - // synchronize here to ensure SV count matches data in the arrays - synchronized(this) { - mListener.onSvStatusChanged(mSvCount, mPrns, mSnrs, mElevations, - mAzimuths, mEphemerisMask, mAlmanacMask, mUsedInFixMask); - break; - } + // synchronize on mGpsStatus to ensure the data is copied atomically. + synchronized(mGpsStatus) { + mListener.onGpsStatusChanged(msg.what); } } }; } /** - * Registers a GPS status listener. + * Adds a GPS status listener. * - * @param listener GPS status listener object to register. + * @param listener GPS status listener object to register * - * @return true if the listener was successfully registered. - * - * {@hide} + * @return true if the listener was successfully added + * + * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present */ - public boolean registerGpsStatusListener(GpsStatusListener listener) { + public boolean addGpsStatusListener(GpsStatus.Listener listener) { boolean result; if (mGpsStatusListeners.get(listener) != null) { @@ -1138,13 +1212,11 @@ public class LocationManager { } /** - * Unegisters a GPS status listener. - * - * @param listener GPS status listener object to unregister. + * Removes a GPS status listener. * - * {@hide} + * @param listener GPS status listener object to remove */ - public void unregisterGpsStatusListener(GpsStatusListener listener) { + public void removeGpsStatusListener(GpsStatus.Listener listener) { try { GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener); if (transport != null) { @@ -1154,7 +1226,26 @@ public class LocationManager { 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 @@ -1164,9 +1255,7 @@ public class LocationManager { * @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. - * - * {@hide} + * @return true if the command succeeds. */ public boolean sendExtraCommand(String provider, String command, Bundle extras) { try { diff --git a/location/java/com/android/internal/location/CellState.java b/location/java/com/android/internal/location/CellState.java index 697fa92..8f6ca1f 100644 --- a/location/java/com/android/internal/location/CellState.java +++ b/location/java/com/android/internal/location/CellState.java @@ -17,10 +17,16 @@ package com.android.internal.location; import android.telephony.CellLocation; -import android.telephony.ServiceState; +import android.telephony.TelephonyManager; +import android.telephony.NeighboringCellInfo; import android.telephony.gsm.GsmCellLocation; +import android.util.Log; + import com.android.internal.telephony.TelephonyProperties; +import java.util.List; +import java.util.ArrayList; + import android.os.SystemProperties; /** @@ -45,53 +51,148 @@ public class CellState { private String mCarrier = null; private int mRadioType = -1; private long mTime = 0; + private int mSignalStrength = -1; + + private List<NeighborCell> mNeighbors; public CellState() { // constructor for invalid cell location } - public CellState(ServiceState service, CellLocation location) { + public CellState(TelephonyManager telephonyManager, CellLocation location, int signalStrength) { GsmCellLocation loc = (GsmCellLocation)location; mLac = loc.getLac(); // example: 6032 mCid = loc.getCid(); // example: 31792 mTime = System.currentTimeMillis(); // Get radio type - String radioType = SystemProperties.get(TelephonyProperties.PROPERTY_DATA_NETWORK_TYPE); - if (radioType != null && (radioType.equals("GPRS") || radioType.equals("EDGE"))) { + int radioType = telephonyManager.getNetworkType(); + if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || + radioType == TelephonyManager.NETWORK_TYPE_EDGE) { mRadioType = RADIO_TYPE_GPRS; - } else if (radioType != null && radioType.equals("UMTS")) { + } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { mRadioType = RADIO_TYPE_WCDMA; } + // Get neighboring cells + mNeighbors = new ArrayList<NeighborCell>(); + List<NeighboringCellInfo> neighboringCells = telephonyManager.getNeighboringCellInfo(); + if (neighboringCells != null) { + for (NeighboringCellInfo n : neighboringCells) { + if (n.getCid() == NeighboringCellInfo.UNKNOWN_CID) { + continue; + } + + if (mRadioType == RADIO_TYPE_WCDMA) { + mNeighbors.add(new NeighborCell(-1, -1, n.getCid(), n.getRssi())); + } else if (mRadioType == RADIO_TYPE_GPRS) { + try { + String hexCidLac = Integer.toHexString(n.getCid()); + int l = hexCidLac.length(); + if (l > 8) { + Log.w(TAG, "Unable to parse 2G Cell \"" + hexCidLac + "\""); + continue; + } + if (l < 8) { + for (int i = 0; i < (8-l); i++) { + hexCidLac = "0" + hexCidLac; + } + } + int lac = Integer.valueOf(hexCidLac.substring(0, 4), 16); + int cid = Integer.valueOf(hexCidLac.substring(4), 16); + mNeighbors.add(new NeighborCell(cid, lac, -1, n.getRssi())); + + } catch (Exception e) { + Log.e(TAG, "Error parsing 2G Cell \"" + n.getCid() + "\"", e); + } + } + } + } + // Get MCC/MNC - String operator = service.getOperatorNumeric(); + String operator = telephonyManager.getNetworkOperator(); if (operator != null && !operator.equals("")) { - String mcc = operator.substring(0, 3); - String mnc = operator.substring(3); - - mMcc = Integer.parseInt(mcc); - mMnc = Integer.parseInt(mnc); + // Use a try/catch block to detect index out of bounds or number format exceptions. + // If an error occurs, both mMcc and mMnc will be equal to -1. + try { + String mcc = operator.substring(0, 3); + String mnc = operator.substring(3); + int mccTmp = Integer.parseInt(mcc); + int mncTmp = Integer.parseInt(mnc); + + // Parsing succeeded, update the instance variables together + mMcc = mccTmp; + mMnc = mncTmp; + } catch (Exception e) { + Log.e(TAG, "Error parsing MCC/MNC from operator \"" + operator + "\"", e); + } } // Get Home MCC/MNC - String homeOperator = SystemProperties.get(TelephonyProperties.PROPERTY_SIM_OPERATOR_NUMERIC); + String homeOperator = telephonyManager.getSimOperator(); if (homeOperator != null && !homeOperator.equals("")) { - String mcc = homeOperator.substring(0, 3); - String mnc = homeOperator.substring(3); - - mHomeMcc = Integer.parseInt(mcc); - mHomeMnc = Integer.parseInt(mnc); + // Use a try/catch block to detect index out of bounds or number format exceptions. + // If an error occurs, both mHomeMcc and mHomeMnc will be equal to -1. + try { + String mcc = homeOperator.substring(0, 3); + String mnc = homeOperator.substring(3); + int mccTmp = Integer.parseInt(mcc); + int mncTmp = Integer.parseInt(mnc); + + // Parsing succeeded, update the instance variables together + mHomeMcc = mccTmp; + mHomeMnc = mncTmp; + } catch (Exception e) { + Log.e(TAG, "Error parsing MCC/MNC from home operator \"" + homeOperator + "\"", e); + } } // Get Carrier - String carrier = service.getOperatorAlphaLong(); + String carrier = telephonyManager.getNetworkOperatorName(); if (carrier != null && !carrier.equals("")) { mCarrier = carrier; } - //Log.d(TAG, mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + mHomeMcc + "," + - // mHomeMnc + "," + mCarrier + "," + mRadioType); + // Initial signal strength + mSignalStrength = signalStrength; + + if (Log.isLoggable(TAG, Log.VERBOSE)) { + String neighbors = "["; + for (NeighborCell n : mNeighbors) { + neighbors += n.toString() + ","; + } + neighbors += "]"; + Log.d(TAG, "CellState(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + + mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + + mSignalStrength + "," + neighbors); + } + } + + public void updateRadioType(TelephonyManager telephonyManager) { + // Get radio type + int radioType = telephonyManager.getNetworkType(); + if (radioType == TelephonyManager.NETWORK_TYPE_GPRS || + radioType == TelephonyManager.NETWORK_TYPE_EDGE) { + mRadioType = RADIO_TYPE_GPRS; + } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) { + mRadioType = RADIO_TYPE_WCDMA; + } + + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.d(TAG, "updateRadioType(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + + mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + + mSignalStrength); + } + } + + public void updateSignalStrength(int signalStrength) { + mSignalStrength = signalStrength; + + if (Log.isLoggable(TAG, Log.VERBOSE)) { + Log.d(TAG, "updateSignal(): " + mLac +"," + mCid + "," + mMnc +"," + mMcc + "," + + mHomeMcc + "," + mHomeMnc + "," + mCarrier + "," + mRadioType + "," + + mSignalStrength); + } } public int getCid() { @@ -142,6 +243,14 @@ public class CellState { return mTime; } + public int getSignalStrength() { + return mSignalStrength; + } + + public List<NeighborCell> getNeighbors() { + return mNeighbors; + } + public boolean equals(CellState other) { return (mCid == other.mCid && mLac == other.mLac); } @@ -149,4 +258,42 @@ public class CellState { public boolean isValid() { return (mCid != -1 && mLac != -1); } + + public static class NeighborCell { + private int mCid = -1; + private int mLac = -1; + private int mPsc = -1; + private int mRssi = -1; + + NeighborCell(int cid, int lac, int psc, int rssi) { + mCid = cid; + mLac = lac; + mPsc = psc; + mRssi = rssi; + } + + public int getCid() { + return mCid; + } + + public int getLac() { + return mLac; + } + + public int getPsc() { + return mPsc; + } + + public int getRssi() { + return mRssi; + } + + public String toString() { + if (mPsc != -1) { + return String.valueOf(mPsc) + "@" + mRssi; + } else { + return mCid + ":" + mLac + "@" + mRssi; + } + } + } } diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java index d0e4f49..7c47081 100644 --- a/location/java/com/android/internal/location/GpsLocationProvider.java +++ b/location/java/com/android/internal/location/GpsLocationProvider.java @@ -16,12 +16,6 @@ package com.android.internal.location; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Properties; - import android.content.Context; import android.content.Intent; import android.location.Criteria; @@ -38,6 +32,12 @@ import android.os.SystemClock; import android.util.Config; import android.util.Log; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Properties; + /** * A GPS implementation of LocationProvider used by LocationManager. * @@ -470,8 +470,7 @@ public class GpsLocationProvider extends LocationProviderImpl { for (int i = 0; i < size && l == null; i++) { Listener test = mListeners.get(i); if (binder.equals(test.mListener.asBinder())) { - // listener already added - return; + l = test; } } @@ -872,7 +871,8 @@ public class GpsLocationProvider extends LocationProviderImpl { // mask[0] is ephemeris mask and mask[1] is almanac mask private native int native_read_sv_status(int[] svs, float[] snrs, float[] elevations, float[] azimuths, int[] masks); - + + // XTRA Support private native void native_inject_time(long time, long timeReference, int uncertainty); private native boolean native_supports_xtra(); private native void native_inject_xtra_data(byte[] data, int length); diff --git a/location/java/com/android/internal/location/LocationCache.java b/location/java/com/android/internal/location/LocationCache.java index f0928f9..545d8c9 100644 --- a/location/java/com/android/internal/location/LocationCache.java +++ b/location/java/com/android/internal/location/LocationCache.java @@ -98,7 +98,7 @@ public class LocationCache { mCellCentroid.reset(); mWifiCentroid.reset(); - if (cellState != null) { + if (cellState != null && cellState.isValid()) { String primaryCellKey = getCellCacheKey(cellState.getMcc(), cellState.getMnc(), cellState.getLac(), cellState.getCid()); Record record = mCellCache.lookup(primaryCellKey); @@ -173,20 +173,44 @@ public class LocationCache { Log.d(TAG, "cellAccuracy:" + cellAccuracy+ ", wifiAccuracy:" + wifiAccuracy); } - if (mCellCentroid.getNumber() != 0 && cellAccuracy <= MAX_ACCURACY_ALLOWED && - (mWifiCentroid.getNumber() == 0 || cellConfidence >= wifiConfidence || - cellAccuracy < wifiAccuracy)) { + if ((mCellCentroid.getNumber() == 0 || cellAccuracy > MAX_ACCURACY_ALLOWED) && + (mWifiCentroid.getNumber() == 0 || wifiAccuracy > MAX_ACCURACY_ALLOWED)) { + // Return invalid location if neither location is valid + result.setAccuracy(-1); + + // don't make server request + return true; + } + + float[] distance = new float[1]; + Location.distanceBetween(mCellCentroid.getCentroidLat(), mCellCentroid.getCentroidLng(), + mWifiCentroid.getCentroidLat(), mWifiCentroid.getCentroidLng(), + distance); + + boolean consistent = distance[0] <= (cellAccuracy + wifiAccuracy); + + boolean useCell = true; + + if (consistent) { + // If consistent locations, use one with greater accuracy + useCell = (cellAccuracy <= wifiAccuracy); + } else { + // If inconsistent locations, use one with greater confidence + useCell = (cellConfidence >= wifiConfidence); + } + + if (useCell) { // Use cell results result.setAccuracy(cellAccuracy); result.setLatitude(mCellCentroid.getCentroidLat()); result.setLongitude(mCellCentroid.getCentroidLng()); result.setTime(now); - + Bundle extras = result.getExtras() == null ? new Bundle() : result.getExtras(); extras.putString(EXTRA_KEY_LOCATION_TYPE, EXTRA_VALUE_LOCATION_TYPE_CELL); result.setExtras(extras); - } else if (mWifiCentroid.getNumber() != 0 && wifiAccuracy <= MAX_ACCURACY_ALLOWED) { + } else { // Use wifi results result.setAccuracy(wifiAccuracy); result.setLatitude(mWifiCentroid.getCentroidLat()); @@ -197,9 +221,6 @@ public class LocationCache { extras.putString(EXTRA_KEY_LOCATION_TYPE, EXTRA_VALUE_LOCATION_TYPE_WIFI); result.setExtras(extras); - } else { - // Return invalid location - result.setAccuracy(-1); } // don't make a server request @@ -459,7 +480,7 @@ public class LocationCache { double mLatSum = 0; double mLngSum = 0; int mNumber = 0; - int mConfidenceSum = 0; + int mConfidence = 0; double mCentroidLat = 0; double mCentroidLng = 0; @@ -478,7 +499,7 @@ public class LocationCache { mLatSum = 0; mLngSum = 0; mNumber = 0; - mConfidenceSum = 0; + mConfidence = 0; mCentroidLat = 0; mCentroidLng = 0; @@ -494,7 +515,9 @@ public class LocationCache { if (mNumber < MAX_SIZE && accuracy <= MAX_ACCURACY_ALLOWED) { mLatSum += lat; mLngSum += lng; - mConfidenceSum += confidence; + if (confidence > mConfidence) { + mConfidence = confidence; + } mLats[mNumber] = lat; mLngs[mNumber] = lng; @@ -522,11 +545,7 @@ public class LocationCache { } public int getConfidence() { - if (mNumber != 0) { - return mConfidenceSum/mNumber; - } else { - return 0; - } + return mConfidence; } public int getAccuracy() { diff --git a/location/java/com/android/internal/location/LocationCollector.java b/location/java/com/android/internal/location/LocationCollector.java index 3d2f6bf..39f432f 100644 --- a/location/java/com/android/internal/location/LocationCollector.java +++ b/location/java/com/android/internal/location/LocationCollector.java @@ -350,14 +350,14 @@ public class LocationCollector { * is healthy. * * Additionally, data collection will *never* happen if the system - * property ro.com.google.enable_google_location_features is not set. + * property ro.com.google.locationfeatures is not set. * * @return true if anonymous location collection is enabled */ private boolean isCollectionEnabled() { // This class provides a Google-specific location feature, so it's enabled only - // when the system property ro.com.google.enable_google_location_features is set. - if (!SystemProperties.get("ro.com.google.enable_google_location_features").equals("1")) { + // when the system property ro.com.google.locationfeatures is set. + if (!SystemProperties.get("ro.com.google.locationfeatures").equals("1")) { return false; } return mBatteryLevelIsHealthy && mNetworkProviderIsEnabled; diff --git a/location/java/com/android/internal/location/LocationMasfClient.java b/location/java/com/android/internal/location/LocationMasfClient.java index ed9f3d6..4efcdd5 100644 --- a/location/java/com/android/internal/location/LocationMasfClient.java +++ b/location/java/com/android/internal/location/LocationMasfClient.java @@ -64,6 +64,7 @@ import android.os.SystemClock; import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import android.telephony.NeighboringCellInfo; /** * Service to communicate to the Google Location Server (GLS) via MASF server @@ -128,6 +129,12 @@ public class LocationMasfClient { private static final String EXTRA_VALUE_LOCATION_SOURCE_CACHED = "cached"; private static final String EXTRA_VALUE_LOCATION_SOURCE_SERVER = "server"; + // Maximum accuracy tolerated for a valid location + private static final int MAX_ACCURACY_ALLOWED = 5000; // 5km + + // Indicates whether this is the first message after a device restart + private boolean mDeviceRestart = true; + /** * Initializes the MobileServiceMux. Must be called before using any other function in the * class. @@ -204,10 +211,16 @@ public class LocationMasfClient { ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT); // Debug profile + ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE); + requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile); + + if (mDeviceRestart) { + debugProfile.setBool(GDebugProfile.DEVICE_RESTART, true); + mDeviceRestart = false; + } + if (trigger != -1) { - ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE); debugProfile.setInt(GDebugProfile.TRIGGER, trigger); - requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile); } // Cellular profile @@ -226,6 +239,11 @@ public class LocationMasfClient { primaryCell.setInt(GCell.MCC, mCellState.getMcc()); primaryCell.setInt(GCell.MNC, mCellState.getMnc()); } + + if (mCellState.getSignalStrength() != -1) { + primaryCell.setInt(GCell.RSSI, mCellState.getSignalStrength()); + } + cellularProfile.setProtoBuf(GCellularProfile.PRIMARY_CELL, primaryCell); // History of cells @@ -237,10 +255,18 @@ public class LocationMasfClient { pastCell.setInt(GCell.MCC, c.getMcc()); pastCell.setInt(GCell.MNC, c.getMnc()); } + + if (c.getSignalStrength() != -1) { + pastCell.setInt(GCell.RSSI, c.getSignalStrength()); + } + pastCell.setInt(GCell.AGE, (int)(mCellState.getTime() - c.getTime())); cellularProfile.addProtoBuf(GCellularProfile.HISTORICAL_CELLS, pastCell); } + // Neighboring Cells + addNeighborsToCellProfile(mCellState, cellularProfile); + requestElement.setProtoBuf(GLocRequestElement.CELLULAR_PROFILE, cellularProfile); } @@ -344,13 +370,6 @@ public class LocationMasfClient { } ProtoBuf replyElement = response.getProtoBuf(GLocReply.REPLY_ELEMENTS); - int status2 = replyElement.getInt(GLocReplyElement.STATUS); - if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS && - status2 != ResponseCodes.STATUS_STATUS_FAILED) { - Log.e(TAG, "getNetworkLocation(): GLS failed with status " + status2); - return false; - } - // Get prefetched data to add to the device cache Log.d(TAG, "getNetworkLocation(): Number of prefetched entries " + replyElement.getCount(GLocReplyElement.DEVICE_LOCATION)); @@ -404,6 +423,13 @@ public class LocationMasfClient { mLocationCache.save(); + int status2 = replyElement.getInt(GLocReplyElement.STATUS); + if (status2 != ResponseCodes.STATUS_STATUS_SUCCESS && + status2 != ResponseCodes.STATUS_STATUS_FAILED) { + Log.e(TAG, "getNetworkLocation(): GLS failed with status " + status2); + return false; + } + // For consistent results for user, always return cache computed location boolean foundInCache = mLocationCache.lookup(mCellState, mCellHistory, mWifiScanResults, mLocation); @@ -447,6 +473,11 @@ public class LocationMasfClient { accuracy = location.getInt(GLocation.ACCURACY); } + if (accuracy > MAX_ACCURACY_ALLOWED) { + Log.e(TAG, "getNetworkLocation(): accuracy is too high " + accuracy); + return false; + } + mLocation.setLatitude(lat); mLocation.setLongitude(lng); mLocation.setTime(System.currentTimeMillis()); @@ -738,11 +769,16 @@ public class LocationMasfClient { ProtoBuf requestElement = new ProtoBuf(LocserverMessageTypes.GLOC_REQUEST_ELEMENT); // Include debug profile + ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE); + requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile); + + if (mDeviceRestart) { + debugProfile.setBool(GDebugProfile.DEVICE_RESTART, true); + mDeviceRestart = false; + } + if (trigger != -1) { - ProtoBuf debugProfile = new ProtoBuf(GdebugprofileMessageTypes.GDEBUG_PROFILE); debugProfile.setInt(GDebugProfile.TRIGGER, trigger); - requestElement.setProtoBuf(GLocRequestElement.DEBUG_PROFILE, debugProfile); - EventLog.writeEvent(COLLECTION_EVENT_LOG_TAG, trigger); } @@ -760,7 +796,15 @@ public class LocationMasfClient { primaryCell.setInt(GCell.MNC, cellState.getMnc()); } + if (cellState.getSignalStrength() != -1) { + primaryCell.setInt(GCell.RSSI, cellState.getSignalStrength()); + } + cellularProfile.setProtoBuf(GCellularProfile.PRIMARY_CELL, primaryCell); + + // Cell neighbors + addNeighborsToCellProfile(cellState, cellularProfile); + requestElement.setProtoBuf(GLocRequestElement.CELLULAR_PROFILE, cellularProfile); } @@ -818,8 +862,28 @@ public class LocationMasfClient { platformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE, cellularPlatform); } + mCurrentCollectionRequest.setProtoBuf(GLocRequest.PLATFORM_PROFILE, platformProfile); + + } else { + + ProtoBuf platformProfile = + mCurrentCollectionRequest.getProtoBuf(GLocRequest.PLATFORM_PROFILE); + if (platformProfile == null) { + platformProfile = createPlatformProfile(); + mCurrentCollectionRequest.setProtoBuf( + GLocRequest.PLATFORM_PROFILE, platformProfile); + } + + // Add cellular platform profile is not already included + if (platformProfile.getProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE) == null && + cellState != null && cellState.isValid()) { + ProtoBuf cellularPlatform = createCellularPlatformProfile(cellState); + platformProfile.setProtoBuf(GPlatformProfile.CELLULAR_PLATFORM_PROFILE, + cellularPlatform); + } } + mCurrentCollectionRequest.addProtoBuf(GLocRequest.REQUEST_ELEMENTS, requestElement); // Immediately upload collection events if buffer exceeds certain size @@ -990,32 +1054,33 @@ public class LocationMasfClient { } private ProtoBuf createCellularPlatformProfile(CellState cellState) { - if (mCellularPlatformProfile == null) { - // Radio type - int radioType = -1; - if (cellState.getRadioType() == CellState.RADIO_TYPE_GPRS) { - radioType = GCellularPlatformProfile.RADIO_TYPE_GPRS; - } else if (cellState.getRadioType() == CellState.RADIO_TYPE_CDMA) { - radioType = GCellularPlatformProfile.RADIO_TYPE_CDMA; - } else if (cellState.getRadioType() == CellState.RADIO_TYPE_WCDMA) { - radioType = GCellularPlatformProfile.RADIO_TYPE_WCDMA; - } + // Radio type + int radioType = -1; + if (cellState.getRadioType() == CellState.RADIO_TYPE_GPRS) { + radioType = GCellularPlatformProfile.RADIO_TYPE_GPRS; + } else if (cellState.getRadioType() == CellState.RADIO_TYPE_CDMA) { + radioType = GCellularPlatformProfile.RADIO_TYPE_CDMA; + } else if (cellState.getRadioType() == CellState.RADIO_TYPE_WCDMA) { + radioType = GCellularPlatformProfile.RADIO_TYPE_WCDMA; + } - // Cellular platform profile - ProtoBuf cellularPlatform = + if (mCellularPlatformProfile == null) { + mCellularPlatformProfile = new ProtoBuf(GlocationMessageTypes.GCELLULAR_PLATFORM_PROFILE); - cellularPlatform.setInt(GCellularPlatformProfile.RADIO_TYPE, radioType); - if ((cellState.getHomeMcc() != -1) && (cellState.getHomeMnc() != -1)) { - cellularPlatform.setInt(GCellularPlatformProfile.HOME_MCC, cellState.getHomeMcc()); - cellularPlatform.setInt(GCellularPlatformProfile.HOME_MNC, cellState.getHomeMnc()); - } - if (cellState.getCarrier() != null) { - cellularPlatform.setString(GCellularPlatformProfile.CARRIER, - cellState.getCarrier()); - } - mCellularPlatformProfile = cellularPlatform; } + mCellularPlatformProfile.setInt(GCellularPlatformProfile.RADIO_TYPE, radioType); + if ((cellState.getHomeMcc() != -1) && (cellState.getHomeMnc() != -1)) { + mCellularPlatformProfile.setInt(GCellularPlatformProfile.HOME_MCC, + cellState.getHomeMcc()); + mCellularPlatformProfile.setInt(GCellularPlatformProfile.HOME_MNC, + cellState.getHomeMnc()); + } + if (cellState.getCarrier() != null) { + mCellularPlatformProfile.setString(GCellularPlatformProfile.CARRIER, + cellState.getCarrier()); + } + return mCellularPlatformProfile; } @@ -1100,4 +1165,20 @@ public class LocationMasfClient { } } + private void addNeighborsToCellProfile(CellState cellState, ProtoBuf cellularProfile) { + List<CellState.NeighborCell> neighbors = cellState.getNeighbors(); + if (neighbors != null) { + for (CellState.NeighborCell neighbor : neighbors) { + ProtoBuf nCell = new ProtoBuf(GcellularMessageTypes.GCELL); + nCell.setInt(GCell.CELLID, neighbor.getCid()); + nCell.setInt(GCell.LAC, neighbor.getLac()); + nCell.setInt(GCell.RSSI, neighbor.getRssi()); + if (neighbor.getPsc() != -1) { + nCell.setInt(GCell.PRIMARY_SCRAMBLING_CODE, neighbor.getPsc()); + } + cellularProfile.addProtoBuf(GCellularProfile.NEIGHBORS, nCell); + } + } + } + } diff --git a/location/java/com/android/internal/location/NetworkLocationProvider.java b/location/java/com/android/internal/location/NetworkLocationProvider.java index 7d3fda1..d0a59b9 100644 --- a/location/java/com/android/internal/location/NetworkLocationProvider.java +++ b/location/java/com/android/internal/location/NetworkLocationProvider.java @@ -107,8 +107,8 @@ public class NetworkLocationProvider extends LocationProviderImpl { public static boolean isSupported() { // This class provides a Google-specific location feature, so it's enabled only - // when the system property ro.com.google.enable_google_location_features is set. - if (!SystemProperties.get("ro.com.google.enable_google_location_features").equals("1")) { + // when the system property ro.com.google.locationfeatures is set. + if (!SystemProperties.get("ro.com.google.locationfeatures").equals("1")) { return false; } diff --git a/location/java/com/android/internal/location/protocol/GDebugProfile.java b/location/java/com/android/internal/location/protocol/GDebugProfile.java index e5c9fe6..b964387 100644 --- a/location/java/com/android/internal/location/protocol/GDebugProfile.java +++ b/location/java/com/android/internal/location/protocol/GDebugProfile.java @@ -32,5 +32,6 @@ public interface GDebugProfile { static final int TRIGGER = 1; static final int ACTUAL_REQUEST = 2; static final int CACHE_LOCATION = 3; + static final int DEVICE_RESTART = 4; } diff --git a/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java b/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java index faf5b89..9a51efe 100644 --- a/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java +++ b/location/java/com/android/internal/location/protocol/GdebugprofileMessageTypes.java @@ -29,7 +29,9 @@ public class GdebugprofileMessageTypes { .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL, GDebugProfile.ACTUAL_REQUEST, ProtoBuf.TRUE) .addElement(ProtoBufType.REPEATED | ProtoBufType.TYPE_MESSAGE, - GDebugProfile.CACHE_LOCATION, GlocationMessageTypes.GDEVICE_LOCATION); + GDebugProfile.CACHE_LOCATION, GlocationMessageTypes.GDEVICE_LOCATION) + .addElement(ProtoBufType.OPTIONAL | ProtoBufType.TYPE_BOOL, + GDebugProfile.DEVICE_RESTART, ProtoBuf.FALSE); } } |