diff options
Diffstat (limited to 'location/java/android/location/LocationManager.java')
-rw-r--r-- | location/java/android/location/LocationManager.java | 265 |
1 files changed, 177 insertions, 88 deletions
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 { |