Home | History | Annotate | Download | only in location
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.location;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.os.Build;
     23 import android.os.Bundle;
     24 import android.os.Looper;
     25 import android.os.RemoteException;
     26 import android.os.Handler;
     27 import android.os.Message;
     28 import android.util.Log;
     29 
     30 
     31 import java.util.ArrayList;
     32 import java.util.HashMap;
     33 import java.util.List;
     34 
     35 import com.android.internal.location.ProviderProperties;
     36 
     37 /**
     38  * This class provides access to the system location services.  These
     39  * services allow applications to obtain periodic updates of the
     40  * device's geographical location, or to fire an application-specified
     41  * {@link Intent} when the device enters the proximity of a given
     42  * geographical location.
     43  *
     44  * <p>You do not
     45  * instantiate this class directly; instead, retrieve it through
     46  * {@link android.content.Context#getSystemService
     47  * Context.getSystemService(Context.LOCATION_SERVICE)}.
     48  *
     49  * <p class="note">Unless noted, all Location API methods require
     50  * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
     51  * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.
     52  * If your application only has the coarse permission then it will not have
     53  * access to the GPS or passive location providers. Other providers will still
     54  * return location results, but the update rate will be throttled and the exact
     55  * location will be obfuscated to a coarse level of accuracy.
     56  */
     57 public class LocationManager {
     58     private static final String TAG = "LocationManager";
     59 
     60     private final Context mContext;
     61     private final ILocationManager mService;
     62     private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
     63             new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
     64     private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
     65             new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
     66     private final GpsStatus mGpsStatus = new GpsStatus();
     67 
     68     /**
     69      * Name of the network location provider.
     70      * <p>This provider determines location based on
     71      * availability of cell tower and WiFi access points. Results are retrieved
     72      * by means of a network lookup.
     73      */
     74     public static final String NETWORK_PROVIDER = "network";
     75 
     76     /**
     77      * Name of the GPS location provider.
     78      *
     79      * <p>This provider determines location using
     80      * satellites. Depending on conditions, this provider may take a while to return
     81      * a location fix. Requires the permission
     82      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
     83      *
     84      * <p> The extras Bundle for the GPS location provider can contain the
     85      * following key/value pairs:
     86      * <ul>
     87      * <li> satellites - the number of satellites used to derive the fix
     88      * </ul>
     89      */
     90     public static final String GPS_PROVIDER = "gps";
     91 
     92     /**
     93      * A special location provider for receiving locations without actually initiating
     94      * a location fix.
     95      *
     96      * <p>This provider can be used to passively receive location updates
     97      * when other applications or services request them without actually requesting
     98      * the locations yourself.  This provider will return locations generated by other
     99      * providers.  You can query the {@link Location#getProvider()} method to determine
    100      * the origin of the location update. Requires the permission
    101      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is
    102      * not enabled this provider might only return coarse fixes.
    103      */
    104     public static final String PASSIVE_PROVIDER = "passive";
    105 
    106     /**
    107      * Name of the Fused location provider.
    108      *
    109      * <p>This provider combines inputs for all possible location sources
    110      * to provide the best possible Location fix. It is implicitly
    111      * used for all API's that involve the {@link LocationRequest}
    112      * object.
    113      *
    114      * @hide
    115      */
    116     public static final String FUSED_PROVIDER = "fused";
    117 
    118     /**
    119      * Key used for the Bundle extra holding a boolean indicating whether
    120      * a proximity alert is entering (true) or exiting (false)..
    121      */
    122     public static final String KEY_PROXIMITY_ENTERING = "entering";
    123 
    124     /**
    125      * Key used for a Bundle extra holding an Integer status value
    126      * when a status change is broadcast using a PendingIntent.
    127      */
    128     public static final String KEY_STATUS_CHANGED = "status";
    129 
    130     /**
    131      * Key used for a Bundle extra holding an Boolean status value
    132      * when a provider enabled/disabled event is broadcast using a PendingIntent.
    133      */
    134     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
    135 
    136     /**
    137      * Key used for a Bundle extra holding a Location value
    138      * when a location change is broadcast using a PendingIntent.
    139      */
    140     public static final String KEY_LOCATION_CHANGED = "location";
    141 
    142     /**
    143      * Broadcast intent action indicating that the GPS has either been
    144      * enabled or disabled. An intent extra provides this state as a boolean,
    145      * where {@code true} means enabled.
    146      * @see #EXTRA_GPS_ENABLED
    147      *
    148      * @hide
    149      */
    150     public static final String GPS_ENABLED_CHANGE_ACTION =
    151         "android.location.GPS_ENABLED_CHANGE";
    152 
    153     /**
    154      * Broadcast intent action when the configured location providers
    155      * change.
    156      */
    157     public static final String PROVIDERS_CHANGED_ACTION =
    158         "android.location.PROVIDERS_CHANGED";
    159 
    160     /**
    161      * Broadcast intent action indicating that the GPS has either started or
    162      * stopped receiving GPS fixes. An intent extra provides this state as a
    163      * boolean, where {@code true} means that the GPS is actively receiving fixes.
    164      * @see #EXTRA_GPS_ENABLED
    165      *
    166      * @hide
    167      */
    168     public static final String GPS_FIX_CHANGE_ACTION =
    169         "android.location.GPS_FIX_CHANGE";
    170 
    171     /**
    172      * The lookup key for a boolean that indicates whether GPS is enabled or
    173      * disabled. {@code true} means GPS is enabled. Retrieve it with
    174      * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
    175      *
    176      * @hide
    177      */
    178     public static final String EXTRA_GPS_ENABLED = "enabled";
    179 
    180     // Map from LocationListeners to their associated ListenerTransport objects
    181     private HashMap<LocationListener,ListenerTransport> mListeners =
    182         new HashMap<LocationListener,ListenerTransport>();
    183 
    184     private class ListenerTransport extends ILocationListener.Stub {
    185         private static final int TYPE_LOCATION_CHANGED = 1;
    186         private static final int TYPE_STATUS_CHANGED = 2;
    187         private static final int TYPE_PROVIDER_ENABLED = 3;
    188         private static final int TYPE_PROVIDER_DISABLED = 4;
    189 
    190         private LocationListener mListener;
    191         private final Handler mListenerHandler;
    192 
    193         ListenerTransport(LocationListener listener, Looper looper) {
    194             mListener = listener;
    195 
    196             if (looper == null) {
    197                 mListenerHandler = new Handler() {
    198                     @Override
    199                     public void handleMessage(Message msg) {
    200                         _handleMessage(msg);
    201                     }
    202                 };
    203             } else {
    204                 mListenerHandler = new Handler(looper) {
    205                     @Override
    206                     public void handleMessage(Message msg) {
    207                         _handleMessage(msg);
    208                     }
    209                 };
    210             }
    211         }
    212 
    213         @Override
    214         public void onLocationChanged(Location location) {
    215             Message msg = Message.obtain();
    216             msg.what = TYPE_LOCATION_CHANGED;
    217             msg.obj = location;
    218             mListenerHandler.sendMessage(msg);
    219         }
    220 
    221         @Override
    222         public void onStatusChanged(String provider, int status, Bundle extras) {
    223             Message msg = Message.obtain();
    224             msg.what = TYPE_STATUS_CHANGED;
    225             Bundle b = new Bundle();
    226             b.putString("provider", provider);
    227             b.putInt("status", status);
    228             if (extras != null) {
    229                 b.putBundle("extras", extras);
    230             }
    231             msg.obj = b;
    232             mListenerHandler.sendMessage(msg);
    233         }
    234 
    235         @Override
    236         public void onProviderEnabled(String provider) {
    237             Message msg = Message.obtain();
    238             msg.what = TYPE_PROVIDER_ENABLED;
    239             msg.obj = provider;
    240             mListenerHandler.sendMessage(msg);
    241         }
    242 
    243         @Override
    244         public void onProviderDisabled(String provider) {
    245             Message msg = Message.obtain();
    246             msg.what = TYPE_PROVIDER_DISABLED;
    247             msg.obj = provider;
    248             mListenerHandler.sendMessage(msg);
    249         }
    250 
    251         private void _handleMessage(Message msg) {
    252             switch (msg.what) {
    253                 case TYPE_LOCATION_CHANGED:
    254                     Location location = new Location((Location) msg.obj);
    255                     mListener.onLocationChanged(location);
    256                     break;
    257                 case TYPE_STATUS_CHANGED:
    258                     Bundle b = (Bundle) msg.obj;
    259                     String provider = b.getString("provider");
    260                     int status = b.getInt("status");
    261                     Bundle extras = b.getBundle("extras");
    262                     mListener.onStatusChanged(provider, status, extras);
    263                     break;
    264                 case TYPE_PROVIDER_ENABLED:
    265                     mListener.onProviderEnabled((String) msg.obj);
    266                     break;
    267                 case TYPE_PROVIDER_DISABLED:
    268                     mListener.onProviderDisabled((String) msg.obj);
    269                     break;
    270             }
    271             try {
    272                 mService.locationCallbackFinished(this);
    273             } catch (RemoteException e) {
    274                 Log.e(TAG, "locationCallbackFinished: RemoteException", e);
    275             }
    276         }
    277     }
    278 
    279     /**
    280      * @hide - hide this constructor because it has a parameter
    281      * of type ILocationManager, which is a system private class. The
    282      * right way to create an instance of this class is using the
    283      * factory Context.getSystemService.
    284      */
    285     public LocationManager(Context context, ILocationManager service) {
    286         mService = service;
    287         mContext = context;
    288     }
    289 
    290     private LocationProvider createProvider(String name, ProviderProperties properties) {
    291         return new LocationProvider(name, properties);
    292     }
    293 
    294     /**
    295      * Returns a list of the names of all known location providers.
    296      * <p>All providers are returned, including ones that are not permitted to
    297      * be accessed by the calling activity or are currently disabled.
    298      *
    299      * @return list of Strings containing names of the provider
    300      */
    301     public List<String> getAllProviders() {
    302         try {
    303             return mService.getAllProviders();
    304         } catch (RemoteException e) {
    305             Log.e(TAG, "RemoteException", e);
    306         }
    307         return null;
    308     }
    309 
    310     /**
    311      * Returns a list of the names of location providers.
    312      *
    313      * @param enabledOnly if true then only the providers which are currently
    314      * enabled are returned.
    315      * @return list of Strings containing names of the providers
    316      */
    317     public List<String> getProviders(boolean enabledOnly) {
    318         try {
    319             return mService.getProviders(null, enabledOnly);
    320         } catch (RemoteException e) {
    321             Log.e(TAG, "RemoteException", e);
    322         }
    323         return null;
    324     }
    325 
    326     /**
    327      * Returns the information associated with the location provider of the
    328      * given name, or null if no provider exists by that name.
    329      *
    330      * @param name the provider name
    331      * @return a LocationProvider, or null
    332      *
    333      * @throws IllegalArgumentException if name is null or does not exist
    334      * @throws SecurityException if the caller is not permitted to access the
    335      * given provider.
    336      */
    337     public LocationProvider getProvider(String name) {
    338         checkProvider(name);
    339         try {
    340             ProviderProperties properties = mService.getProviderProperties(name);
    341             if (properties == null) {
    342                 return null;
    343             }
    344             return createProvider(name, properties);
    345         } catch (RemoteException e) {
    346             Log.e(TAG, "RemoteException", e);
    347         }
    348         return null;
    349     }
    350 
    351     /**
    352      * Returns a list of the names of LocationProviders that satisfy the given
    353      * criteria, or null if none do.  Only providers that are permitted to be
    354      * accessed by the calling activity will be returned.
    355      *
    356      * @param criteria the criteria that the returned providers must match
    357      * @param enabledOnly if true then only the providers which are currently
    358      * enabled are returned.
    359      * @return list of Strings containing names of the providers
    360      */
    361     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
    362         checkCriteria(criteria);
    363         try {
    364             return mService.getProviders(criteria, enabledOnly);
    365         } catch (RemoteException e) {
    366             Log.e(TAG, "RemoteException", e);
    367         }
    368         return null;
    369     }
    370 
    371     /**
    372      * Returns the name of the provider that best meets the given criteria. Only providers
    373      * that are permitted to be accessed by the calling activity will be
    374      * returned.  If several providers meet the criteria, the one with the best
    375      * accuracy is returned.  If no provider meets the criteria,
    376      * the criteria are loosened in the following sequence:
    377      *
    378      * <ul>
    379      * <li> power requirement
    380      * <li> accuracy
    381      * <li> bearing
    382      * <li> speed
    383      * <li> altitude
    384      * </ul>
    385      *
    386      * <p> Note that the requirement on monetary cost is not removed
    387      * in this process.
    388      *
    389      * @param criteria the criteria that need to be matched
    390      * @param enabledOnly if true then only a provider that is currently enabled is returned
    391      * @return name of the provider that best matches the requirements
    392      */
    393     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
    394         checkCriteria(criteria);
    395         try {
    396             return mService.getBestProvider(criteria, enabledOnly);
    397         } catch (RemoteException e) {
    398             Log.e(TAG, "RemoteException", e);
    399         }
    400         return null;
    401     }
    402 
    403     /**
    404      * Register for location updates using the named provider, and a
    405      * pending intent.
    406      *
    407      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    408      * for more detail on how to use this method.
    409      *
    410      * @param provider the name of the provider with which to register
    411      * @param minTime minimum time interval between location updates, in milliseconds
    412      * @param minDistance minimum distance between location updates, in meters
    413      * @param listener a {@link LocationListener} whose
    414      * {@link LocationListener#onLocationChanged} method will be called for
    415      * each location update
    416      *
    417      * @throws IllegalArgumentException if provider is null or doesn't exist
    418      * on this device
    419      * @throws IllegalArgumentException if listener is null
    420      * @throws RuntimeException if the calling thread has no Looper
    421      * @throws SecurityException if no suitable permission is present
    422      */
    423     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    424             LocationListener listener) {
    425         checkProvider(provider);
    426         checkListener(listener);
    427 
    428         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    429                 provider, minTime, minDistance, false);
    430         requestLocationUpdates(request, listener, null, null);
    431     }
    432 
    433     /**
    434      * Register for location updates using the named provider, and a callback on
    435      * the specified looper thread.
    436      *
    437      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    438      * for more detail on how to use this method.
    439      *
    440      * @param provider the name of the provider with which to register
    441      * @param minTime minimum time interval between location updates, in milliseconds
    442      * @param minDistance minimum distance between location updates, in meters
    443      * @param listener a {@link LocationListener} whose
    444      * {@link LocationListener#onLocationChanged} method will be called for
    445      * each location update
    446      * @param looper a Looper object whose message queue will be used to
    447      * implement the callback mechanism, or null to make callbacks on the calling
    448      * thread
    449      *
    450      * @throws IllegalArgumentException if provider is null or doesn't exist
    451      * @throws IllegalArgumentException if listener is null
    452      * @throws SecurityException if no suitable permission is present
    453      */
    454     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    455             LocationListener listener, Looper looper) {
    456         checkProvider(provider);
    457         checkListener(listener);
    458 
    459         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    460                 provider, minTime, minDistance, false);
    461         requestLocationUpdates(request, listener, looper, null);
    462     }
    463 
    464     /**
    465      * Register for location updates using a Criteria, and a callback
    466      * on the specified looper thread.
    467      *
    468      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    469      * for more detail on how to use this method.
    470      *
    471      * @param minTime minimum time interval between location updates, in milliseconds
    472      * @param minDistance minimum distance between location updates, in meters
    473      * @param criteria contains parameters for the location manager to choose the
    474      * appropriate provider and parameters to compute the location
    475      * @param listener a {@link LocationListener} whose
    476      * {@link LocationListener#onLocationChanged} method will be called for
    477      * each location update
    478      * @param looper a Looper object whose message queue will be used to
    479      * implement the callback mechanism, or null to make callbacks on the calling
    480      * thread
    481      *
    482      * @throws IllegalArgumentException if criteria is null
    483      * @throws IllegalArgumentException if listener is null
    484      * @throws SecurityException if no suitable permission is present
    485      */
    486     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
    487             LocationListener listener, Looper looper) {
    488         checkCriteria(criteria);
    489         checkListener(listener);
    490 
    491         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    492                 criteria, minTime, minDistance, false);
    493         requestLocationUpdates(request, listener, looper, null);
    494     }
    495 
    496     /**
    497      * Register for location updates using the named provider, and a
    498      * pending intent.
    499      *
    500      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    501      * for more detail on how to use this method.
    502      *
    503      * @param provider the name of the provider with which to register
    504      * @param minTime minimum time interval between location updates, in milliseconds
    505      * @param minDistance minimum distance between location updates, in meters
    506      * @param intent a {@link PendingIntent} to be sent for each location update
    507      *
    508      * @throws IllegalArgumentException if provider is null or doesn't exist
    509      * on this device
    510      * @throws IllegalArgumentException if intent is null
    511      * @throws SecurityException if no suitable permission is present
    512      */
    513     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    514             PendingIntent intent) {
    515         checkProvider(provider);
    516         checkPendingIntent(intent);
    517 
    518         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    519                 provider, minTime, minDistance, false);
    520         requestLocationUpdates(request, null, null, intent);
    521     }
    522 
    523     /**
    524      * Register for location updates using a Criteria and pending intent.
    525      *
    526      * <p>The <code>requestLocationUpdates()</code> and
    527      * <code>requestSingleUpdate()</code> register the current activity to be
    528      * updated periodically by the named provider, or by the provider matching
    529      * the specified {@link Criteria}, with location and status updates.
    530      *
    531      * <p> It may take a while to receive the first location update. If
    532      * an immediate location is required, applications may use the
    533      * {@link #getLastKnownLocation(String)} method.
    534      *
    535      * <p> Location updates are received either by {@link LocationListener}
    536      * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.
    537      *
    538      * <p> If the caller supplied a pending intent, then location updates
    539      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
    540      * {@link android.location.Location} value.
    541      *
    542      * <p> The location update interval can be controlled using the minTime parameter.
    543      * The elapsed time between location updates will never be less than
    544      * minTime, although it can be more depending on the Location Provider
    545      * implementation and the update interval requested by other applications.
    546      *
    547      * <p> Choosing a sensible value for minTime is important to conserve
    548      * battery life. Each location update requires power from
    549      * GPS, WIFI, Cell and other radios. Select a minTime value as high as
    550      * possible while still providing a reasonable user experience.
    551      * If your application is not in the foreground and showing
    552      * location to the user then your application should avoid using an active
    553      * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
    554      * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
    555      * or greater. If your application is in the foreground and showing
    556      * location to the user then it is appropriate to select a faster
    557      * update interval.
    558      *
    559      * <p> The minDistance parameter can also be used to control the
    560      * frequency of location updates. If it is greater than 0 then the
    561      * location provider will only send your application an update when
    562      * the location has changed by at least minDistance meters, AND
    563      * at least minTime milliseconds have passed. However it is more
    564      * difficult for location providers to save power using the minDistance
    565      * parameter, so minTime should be the primary tool to conserving battery
    566      * life.
    567      *
    568      * <p> If your application wants to passively observe location
    569      * updates triggered by other applications, but not consume
    570      * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
    571      * This provider does not actively turn on or modify active location
    572      * providers, so you do not need to be as careful about minTime and
    573      * minDistance. However if your application performs heavy work
    574      * on a location update (such as network activity) then you should
    575      * select non-zero values for minTime and/or minDistance to rate-limit
    576      * your update frequency in the case another application enables a
    577      * location provider with extremely fast updates.
    578      *
    579      * <p>In case the provider is disabled by the user, updates will stop,
    580      * and a provider availability update will be sent.
    581      * As soon as the provider is enabled again,
    582      * location updates will immediately resume and a provider availability
    583      * update sent. Providers can also send status updates, at any time,
    584      * with extra's specific to the provider. If a callback was supplied
    585      * then status and availability updates are via
    586      * {@link LocationListener#onProviderDisabled},
    587      * {@link LocationListener#onProviderEnabled} or
    588      * {@link LocationListener#onStatusChanged}. Alternately, if a
    589      * pending intent was supplied then status and availability updates
    590      * are broadcast intents with extra keys of
    591      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.
    592      *
    593      * <p> If a {@link LocationListener} is used but with no Looper specified
    594      * then the calling thread must already
    595      * be a {@link android.os.Looper} thread such as the main thread of the
    596      * calling Activity. If a Looper is specified with a {@link LocationListener}
    597      * then callbacks are made on the supplied Looper thread.
    598      *
    599      * <p class="note"> Prior to Jellybean, the minTime parameter was
    600      * only a hint, and some location provider implementations ignored it.
    601      * From Jellybean and onwards it is mandatory for Android compatible
    602      * devices to observe both the minTime and minDistance parameters.
    603      *
    604      * @param minTime minimum time interval between location updates, in milliseconds
    605      * @param minDistance minimum distance between location updates, in meters
    606      * @param criteria contains parameters for the location manager to choose the
    607      * appropriate provider and parameters to compute the location
    608      * @param intent a {@link PendingIntent} to be sent for each location update
    609      *
    610      * @throws IllegalArgumentException if criteria is null
    611      * @throws IllegalArgumentException if intent is null
    612      * @throws SecurityException if no suitable permission is present
    613      */
    614     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
    615             PendingIntent intent) {
    616         checkCriteria(criteria);
    617         checkPendingIntent(intent);
    618 
    619         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    620                 criteria, minTime, minDistance, false);
    621         requestLocationUpdates(request, null, null, intent);
    622     }
    623 
    624     /**
    625      * Register for a single location update using the named provider and
    626      * a callback.
    627      *
    628      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    629      * for more detail on how to use this method.
    630      *
    631      * @param provider the name of the provider with which to register
    632      * @param listener a {@link LocationListener} whose
    633      * {@link LocationListener#onLocationChanged} method will be called when
    634      * the location update is available
    635      * @param looper a Looper object whose message queue will be used to
    636      * implement the callback mechanism, or null to make callbacks on the calling
    637      * thread
    638      *
    639      * @throws IllegalArgumentException if provider is null or doesn't exist
    640      * @throws IllegalArgumentException if listener is null
    641      * @throws SecurityException if no suitable permission is present
    642      */
    643     public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
    644         checkProvider(provider);
    645         checkListener(listener);
    646 
    647         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    648                 provider, 0, 0, true);
    649         requestLocationUpdates(request, listener, looper, null);
    650     }
    651 
    652     /**
    653      * Register for a single location update using a Criteria and
    654      * a callback.
    655      *
    656      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    657      * for more detail on how to use this method.
    658      *
    659      * @param criteria contains parameters for the location manager to choose the
    660      * appropriate provider and parameters to compute the location
    661      * @param listener a {@link LocationListener} whose
    662      * {@link LocationListener#onLocationChanged} method will be called when
    663      * the location update is available
    664      * @param looper a Looper object whose message queue will be used to
    665      * implement the callback mechanism, or null to make callbacks on the calling
    666      * thread
    667      *
    668      * @throws IllegalArgumentException if criteria is null
    669      * @throws IllegalArgumentException if listener is null
    670      * @throws SecurityException if no suitable permission is present
    671      */
    672     public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
    673         checkCriteria(criteria);
    674         checkListener(listener);
    675 
    676         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    677                 criteria, 0, 0, true);
    678         requestLocationUpdates(request, listener, looper, null);
    679     }
    680 
    681     /**
    682      * Register for a single location update using a named provider and pending intent.
    683      *
    684      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    685      * for more detail on how to use this method.
    686      *
    687      * @param provider the name of the provider with which to register
    688      * @param intent a {@link PendingIntent} to be sent for the location update
    689      *
    690      * @throws IllegalArgumentException if provider is null or doesn't exist
    691      * @throws IllegalArgumentException if intent is null
    692      * @throws SecurityException if no suitable permission is present
    693      */
    694     public void requestSingleUpdate(String provider, PendingIntent intent) {
    695         checkProvider(provider);
    696         checkPendingIntent(intent);
    697 
    698         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    699                 provider, 0, 0, true);
    700         requestLocationUpdates(request, null, null, intent);
    701     }
    702 
    703     /**
    704      * Register for a single location update using a Criteria and pending intent.
    705      *
    706      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    707      * for more detail on how to use this method.
    708      *
    709      * @param criteria contains parameters for the location manager to choose the
    710      * appropriate provider and parameters to compute the location
    711      * @param intent a {@link PendingIntent} to be sent for the location update
    712      *
    713      * @throws IllegalArgumentException if provider is null or doesn't exist
    714      * @throws IllegalArgumentException if intent is null
    715      * @throws SecurityException if no suitable permission is present
    716      */
    717     public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
    718         checkCriteria(criteria);
    719         checkPendingIntent(intent);
    720 
    721         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    722                 criteria, 0, 0, true);
    723         requestLocationUpdates(request, null, null, intent);
    724     }
    725 
    726     /**
    727      * Register for fused location updates using a LocationRequest and callback.
    728      *
    729      * <p>Upon a location update, the system delivers the new {@link Location} to the
    730      * provided {@link LocationListener}, by calling its {@link
    731      * LocationListener#onLocationChanged} method.</p>
    732      *
    733      * <p>The system will automatically select and enable the best providers
    734      * to compute a location for your application. It may use only passive
    735      * locations, or just a single location source, or it may fuse together
    736      * multiple location sources in order to produce the best possible
    737      * result, depending on the quality of service requested in the
    738      * {@link LocationRequest}.
    739      *
    740      * <p>LocationRequest can be null, in which case the system will choose
    741      * default, low power parameters for location updates. You will occasionally
    742      * receive location updates as available, without a major power impact on the
    743      * system. If your application just needs an occasional location update
    744      * without any strict demands, then pass a null LocationRequest.
    745      *
    746      * <p>Only one LocationRequest can be registered for each unique callback
    747      * or pending intent. So a subsequent request with the same callback or
    748      * pending intent will over-write the previous LocationRequest.
    749      *
    750      * <p> If a pending intent is supplied then location updates
    751      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
    752      * {@link android.location.Location} value. If a callback is supplied
    753      * then location updates are made using the
    754      * {@link LocationListener#onLocationChanged} callback, on the specified
    755      * Looper thread. If a {@link LocationListener} is used
    756      * but with a null Looper then the calling thread must already
    757      * be a {@link android.os.Looper} thread (such as the main thread) and
    758      * callbacks will occur on this thread.
    759      *
    760      * <p> Provider status updates and availability updates are deprecated
    761      * because the system is performing provider fusion on the applications
    762      * behalf. So {@link LocationListener#onProviderDisabled},
    763      * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}
    764      * will not be called, and intents with extra keys of
    765      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not
    766      * be received.
    767      *
    768      * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}.
    769      *
    770      * @param request quality of service required, null for default low power
    771      * @param listener a {@link LocationListener} whose
    772      * {@link LocationListener#onLocationChanged} method will be called when
    773      * the location update is available
    774      * @param looper a Looper object whose message queue will be used to
    775      * implement the callback mechanism, or null to make callbacks on the calling
    776      * thread
    777      *
    778      * @throws IllegalArgumentException if listener is null
    779      * @throws SecurityException if no suitable permission is present
    780      *
    781      * @hide
    782      */
    783     public void requestLocationUpdates(LocationRequest request, LocationListener listener,
    784             Looper looper) {
    785         checkListener(listener);
    786         requestLocationUpdates(request, listener, looper, null);
    787     }
    788 
    789 
    790     /**
    791      * Register for fused location updates using a LocationRequest and a pending intent.
    792      *
    793      * <p>Upon a location update, the system delivers the new {@link Location} with your provided
    794      * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
    795      * in the intent's extras.</p>
    796      *
    797      * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
    798      *
    799      * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
    800      * for more detail.
    801      *
    802      * @param request quality of service required, null for default low power
    803      * @param intent a {@link PendingIntent} to be sent for the location update
    804      *
    805      * @throws IllegalArgumentException if intent is null
    806      * @throws SecurityException if no suitable permission is present
    807      *
    808      * @hide
    809      */
    810     public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
    811         checkPendingIntent(intent);
    812         requestLocationUpdates(request, null, null, intent);
    813     }
    814 
    815     private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
    816         if (listener == null) return null;
    817         synchronized (mListeners) {
    818             ListenerTransport transport = mListeners.get(listener);
    819             if (transport == null) {
    820                 transport = new ListenerTransport(listener, looper);
    821             }
    822             mListeners.put(listener, transport);
    823             return transport;
    824         }
    825     }
    826 
    827     private void requestLocationUpdates(LocationRequest request, LocationListener listener,
    828             Looper looper, PendingIntent intent) {
    829 
    830         String packageName = mContext.getPackageName();
    831 
    832         // wrap the listener class
    833         ListenerTransport transport = wrapListener(listener, looper);
    834 
    835         try {
    836             mService.requestLocationUpdates(request, transport, intent, packageName);
    837        } catch (RemoteException e) {
    838            Log.e(TAG, "RemoteException", e);
    839        }
    840     }
    841 
    842     /**
    843      * Removes all location updates for the specified LocationListener.
    844      *
    845      * <p>Following this call, updates will no longer
    846      * occur for this listener.
    847      *
    848      * @param listener listener object that no longer needs location updates
    849      * @throws IllegalArgumentException if listener is null
    850      */
    851     public void removeUpdates(LocationListener listener) {
    852         checkListener(listener);
    853         String packageName = mContext.getPackageName();
    854 
    855         ListenerTransport transport;
    856         synchronized (mListeners) {
    857             transport = mListeners.remove(listener);
    858         }
    859         if (transport == null) return;
    860 
    861         try {
    862             mService.removeUpdates(transport, null, packageName);
    863         } catch (RemoteException e) {
    864             Log.e(TAG, "RemoteException", e);
    865         }
    866     }
    867 
    868     /**
    869      * Removes all location updates for the specified pending intent.
    870      *
    871      * <p>Following this call, updates will no longer for this pending intent.
    872      *
    873      * @param intent pending intent object that no longer needs location updates
    874      * @throws IllegalArgumentException if intent is null
    875      */
    876     public void removeUpdates(PendingIntent intent) {
    877         checkPendingIntent(intent);
    878         String packageName = mContext.getPackageName();
    879 
    880         try {
    881             mService.removeUpdates(null, intent, packageName);
    882         } catch (RemoteException e) {
    883             Log.e(TAG, "RemoteException", e);
    884         }
    885     }
    886 
    887     /**
    888      * Set a proximity alert for the location given by the position
    889      * (latitude, longitude) and the given radius.
    890      *
    891      * <p> When the device
    892      * detects that it has entered or exited the area surrounding the
    893      * location, the given PendingIntent will be used to create an Intent
    894      * to be fired.
    895      *
    896      * <p> The fired Intent will have a boolean extra added with key
    897      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
    898      * entering the proximity region; if false, it is exiting.
    899      *
    900      * <p> Due to the approximate nature of position estimation, if the
    901      * device passes through the given area briefly, it is possible
    902      * that no Intent will be fired.  Similarly, an Intent could be
    903      * fired if the device passes very close to the given area but
    904      * does not actually enter it.
    905      *
    906      * <p> After the number of milliseconds given by the expiration
    907      * parameter, the location manager will delete this proximity
    908      * alert and no longer monitor it.  A value of -1 indicates that
    909      * there should be no expiration time.
    910      *
    911      * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
    912      * and {@link #GPS_PROVIDER}.
    913      *
    914      * <p>Before API version 17, this method could be used with
    915      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
    916      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
    917      * From API version 17 and onwards, this method requires
    918      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
    919      *
    920      * @param latitude the latitude of the central point of the
    921      * alert region
    922      * @param longitude the longitude of the central point of the
    923      * alert region
    924      * @param radius the radius of the central point of the
    925      * alert region, in meters
    926      * @param expiration time for this proximity alert, in milliseconds,
    927      * or -1 to indicate no expiration
    928      * @param intent a PendingIntent that will be used to generate an Intent to
    929      * fire when entry to or exit from the alert region is detected
    930      *
    931      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
    932      * permission is not present
    933      */
    934     public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
    935             PendingIntent intent) {
    936         checkPendingIntent(intent);
    937         if (expiration < 0) expiration = Long.MAX_VALUE;
    938 
    939         Geofence fence = Geofence.createCircle(latitude, longitude, radius);
    940         LocationRequest request = new LocationRequest().setExpireIn(expiration);
    941         try {
    942             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
    943         } catch (RemoteException e) {
    944             Log.e(TAG, "RemoteException", e);
    945         }
    946     }
    947 
    948     /**
    949      * Add a geofence with the specified LocationRequest quality of service.
    950      *
    951      * <p> When the device
    952      * detects that it has entered or exited the area surrounding the
    953      * location, the given PendingIntent will be used to create an Intent
    954      * to be fired.
    955      *
    956      * <p> The fired Intent will have a boolean extra added with key
    957      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
    958      * entering the proximity region; if false, it is exiting.
    959      *
    960      * <p> The geofence engine fuses results from all location providers to
    961      * provide the best balance between accuracy and power. Applications
    962      * can choose the quality of service required using the
    963      * {@link LocationRequest} object. If it is null then a default,
    964      * low power geo-fencing implementation is used. It is possible to cross
    965      * a geo-fence without notification, but the system will do its best
    966      * to detect, using {@link LocationRequest} as a hint to trade-off
    967      * accuracy and power.
    968      *
    969      * <p> The power required by the geofence engine can depend on many factors,
    970      * such as quality and interval requested in {@link LocationRequest},
    971      * distance to nearest geofence and current device velocity.
    972      *
    973      * @param request quality of service required, null for default low power
    974      * @param fence a geographical description of the geofence area
    975      * @param intent pending intent to receive geofence updates
    976      *
    977      * @throws IllegalArgumentException if fence is null
    978      * @throws IllegalArgumentException if intent is null
    979      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
    980      * permission is not present
    981      *
    982      * @hide
    983      */
    984     public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
    985         checkPendingIntent(intent);
    986         checkGeofence(fence);
    987 
    988         try {
    989             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
    990         } catch (RemoteException e) {
    991             Log.e(TAG, "RemoteException", e);
    992         }
    993     }
    994 
    995     /**
    996      * Removes the proximity alert with the given PendingIntent.
    997      *
    998      * <p>Before API version 17, this method could be used with
    999      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
   1000      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
   1001      * From API version 17 and onwards, this method requires
   1002      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
   1003      *
   1004      * @param intent the PendingIntent that no longer needs to be notified of
   1005      * proximity alerts
   1006      *
   1007      * @throws IllegalArgumentException if intent is null
   1008      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1009      * permission is not present
   1010      */
   1011     public void removeProximityAlert(PendingIntent intent) {
   1012         checkPendingIntent(intent);
   1013         String packageName = mContext.getPackageName();
   1014 
   1015         try {
   1016             mService.removeGeofence(null, intent, packageName);
   1017         } catch (RemoteException e) {
   1018             Log.e(TAG, "RemoteException", e);
   1019         }
   1020     }
   1021 
   1022     /**
   1023      * Remove a single geofence.
   1024      *
   1025      * <p>This removes only the specified geofence associated with the
   1026      * specified pending intent. All other geofences remain unchanged.
   1027      *
   1028      * @param fence a geofence previously passed to {@link #addGeofence}
   1029      * @param intent a pending intent previously passed to {@link #addGeofence}
   1030      *
   1031      * @throws IllegalArgumentException if fence is null
   1032      * @throws IllegalArgumentException if intent is null
   1033      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1034      * permission is not present
   1035      *
   1036      * @hide
   1037      */
   1038     public void removeGeofence(Geofence fence, PendingIntent intent) {
   1039         checkPendingIntent(intent);
   1040         checkGeofence(fence);
   1041         String packageName = mContext.getPackageName();
   1042 
   1043         try {
   1044             mService.removeGeofence(fence, intent, packageName);
   1045         } catch (RemoteException e) {
   1046             Log.e(TAG, "RemoteException", e);
   1047         }
   1048     }
   1049 
   1050     /**
   1051      * Remove all geofences registered to the specified pending intent.
   1052      *
   1053      * @param intent a pending intent previously passed to {@link #addGeofence}
   1054      *
   1055      * @throws IllegalArgumentException if intent is null
   1056      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1057      * permission is not present
   1058      *
   1059      * @hide
   1060      */
   1061     public void removeAllGeofences(PendingIntent intent) {
   1062         checkPendingIntent(intent);
   1063         String packageName = mContext.getPackageName();
   1064 
   1065         try {
   1066             mService.removeGeofence(null, intent, packageName);
   1067         } catch (RemoteException e) {
   1068             Log.e(TAG, "RemoteException", e);
   1069         }
   1070     }
   1071 
   1072     /**
   1073      * Returns the current enabled/disabled status of the given provider.
   1074      *
   1075      * <p>If the user has enabled this provider in the Settings menu, true
   1076      * is returned otherwise false is returned
   1077      *
   1078      * @param provider the name of the provider
   1079      * @return true if the provider is enabled
   1080      *
   1081      * @throws IllegalArgumentException if provider is null
   1082      * @throws SecurityException if no suitable permission is present
   1083      */
   1084     public boolean isProviderEnabled(String provider) {
   1085         checkProvider(provider);
   1086 
   1087         try {
   1088             return mService.isProviderEnabled(provider);
   1089         } catch (RemoteException e) {
   1090             Log.e(TAG, "RemoteException", e);
   1091             return false;
   1092         }
   1093     }
   1094 
   1095     /**
   1096      * Get the last known location.
   1097      *
   1098      * <p>This location could be very old so use
   1099      * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can
   1100      * also return null if no previous location is available.
   1101      *
   1102      * <p>Always returns immediately.
   1103      *
   1104      * @return The last known location, or null if not available
   1105      * @throws SecurityException if no suitable permission is present
   1106      *
   1107      * @hide
   1108      */
   1109     public Location getLastLocation() {
   1110         String packageName = mContext.getPackageName();
   1111 
   1112         try {
   1113             return mService.getLastLocation(null, packageName);
   1114         } catch (RemoteException e) {
   1115             Log.e(TAG, "RemoteException", e);
   1116             return null;
   1117         }
   1118     }
   1119 
   1120     /**
   1121      * Returns a Location indicating the data from the last known
   1122      * location fix obtained from the given provider.
   1123      *
   1124      * <p> This can be done
   1125      * without starting the provider.  Note that this location could
   1126      * be out-of-date, for example if the device was turned off and
   1127      * moved to another location.
   1128      *
   1129      * <p> If the provider is currently disabled, null is returned.
   1130      *
   1131      * @param provider the name of the provider
   1132      * @return the last known location for the provider, or null
   1133      *
   1134      * @throws SecurityException if no suitable permission is present
   1135      * @throws IllegalArgumentException if provider is null or doesn't exist
   1136      */
   1137     public Location getLastKnownLocation(String provider) {
   1138         checkProvider(provider);
   1139         String packageName = mContext.getPackageName();
   1140         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
   1141                 provider, 0, 0, true);
   1142 
   1143         try {
   1144             return mService.getLastLocation(request, packageName);
   1145         } catch (RemoteException e) {
   1146             Log.e(TAG, "RemoteException", e);
   1147             return null;
   1148         }
   1149     }
   1150 
   1151     // --- Mock provider support ---
   1152     // TODO: It would be fantastic to deprecate mock providers entirely, and replace
   1153     // with something closer to LocationProviderBase.java
   1154 
   1155     /**
   1156      * Creates a mock location provider and adds it to the set of active providers.
   1157      *
   1158      * @param name the provider name
   1159      *
   1160      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1161      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1162      * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled
   1163      * @throws IllegalArgumentException if a provider with the given name already exists
   1164      */
   1165     public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
   1166             boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
   1167             boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
   1168         ProviderProperties properties = new ProviderProperties(requiresNetwork,
   1169                 requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
   1170                 supportsBearing, powerRequirement, accuracy);
   1171         if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
   1172             throw new IllegalArgumentException("provider name contains illegal character: " + name);
   1173         }
   1174 
   1175         try {
   1176             mService.addTestProvider(name, properties);
   1177         } catch (RemoteException e) {
   1178             Log.e(TAG, "RemoteException", e);
   1179         }
   1180     }
   1181 
   1182     /**
   1183      * Removes the mock location provider with the given name.
   1184      *
   1185      * @param provider the provider name
   1186      *
   1187      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1188      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1189      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1190      * @throws IllegalArgumentException if no provider with the given name exists
   1191      */
   1192     public void removeTestProvider(String provider) {
   1193         try {
   1194             mService.removeTestProvider(provider);
   1195         } catch (RemoteException e) {
   1196             Log.e(TAG, "RemoteException", e);
   1197         }
   1198     }
   1199 
   1200     /**
   1201      * Sets a mock location for the given provider.
   1202      * <p>This location will be used in place of any actual location from the provider.
   1203      * The location object must have a minimum number of fields set to be
   1204      * considered a valid LocationProvider Location, as per documentation
   1205      * on {@link Location} class.
   1206      *
   1207      * @param provider the provider name
   1208      * @param loc the mock location
   1209      *
   1210      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1211      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1212      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1213      * @throws IllegalArgumentException if no provider with the given name exists
   1214      * @throws IllegalArgumentException if the location is incomplete
   1215      */
   1216     public void setTestProviderLocation(String provider, Location loc) {
   1217         if (!loc.isComplete()) {
   1218             IllegalArgumentException e = new IllegalArgumentException(
   1219                     "Incomplete location object, missing timestamp or accuracy? " + loc);
   1220             if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
   1221                 // just log on old platform (for backwards compatibility)
   1222                 Log.w(TAG, e);
   1223                 loc.makeComplete();
   1224             } else {
   1225                 // really throw it!
   1226                 throw e;
   1227             }
   1228         }
   1229 
   1230         try {
   1231             mService.setTestProviderLocation(provider, loc);
   1232         } catch (RemoteException e) {
   1233             Log.e(TAG, "RemoteException", e);
   1234         }
   1235     }
   1236 
   1237     /**
   1238      * Removes any mock location associated with the given provider.
   1239      *
   1240      * @param provider the provider name
   1241      *
   1242      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1243      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1244      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1245      * @throws IllegalArgumentException if no provider with the given name exists
   1246      */
   1247     public void clearTestProviderLocation(String provider) {
   1248         try {
   1249             mService.clearTestProviderLocation(provider);
   1250         } catch (RemoteException e) {
   1251             Log.e(TAG, "RemoteException", e);
   1252         }
   1253     }
   1254 
   1255     /**
   1256      * Sets a mock enabled value for the given provider.  This value will be used in place
   1257      * of any actual value from the provider.
   1258      *
   1259      * @param provider the provider name
   1260      * @param enabled the mock enabled value
   1261      *
   1262      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1263      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1264      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1265      * @throws IllegalArgumentException if no provider with the given name exists
   1266      */
   1267     public void setTestProviderEnabled(String provider, boolean enabled) {
   1268         try {
   1269             mService.setTestProviderEnabled(provider, enabled);
   1270         } catch (RemoteException e) {
   1271             Log.e(TAG, "RemoteException", e);
   1272         }
   1273     }
   1274 
   1275     /**
   1276      * Removes any mock enabled value associated with the given provider.
   1277      *
   1278      * @param provider the provider name
   1279      *
   1280      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1281      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1282      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1283      * @throws IllegalArgumentException if no provider with the given name exists
   1284      */
   1285     public void clearTestProviderEnabled(String provider) {
   1286         try {
   1287             mService.clearTestProviderEnabled(provider);
   1288         } catch (RemoteException e) {
   1289             Log.e(TAG, "RemoteException", e);
   1290         }
   1291     }
   1292 
   1293     /**
   1294      * Sets mock status values for the given provider.  These values will be used in place
   1295      * of any actual values from the provider.
   1296      *
   1297      * @param provider the provider name
   1298      * @param status the mock status
   1299      * @param extras a Bundle containing mock extras
   1300      * @param updateTime the mock update time
   1301      *
   1302      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1303      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1304      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1305      * @throws IllegalArgumentException if no provider with the given name exists
   1306      */
   1307     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
   1308         try {
   1309             mService.setTestProviderStatus(provider, status, extras, updateTime);
   1310         } catch (RemoteException e) {
   1311             Log.e(TAG, "RemoteException", e);
   1312         }
   1313     }
   1314 
   1315     /**
   1316      * Removes any mock status values associated with the given provider.
   1317      *
   1318      * @param provider the provider name
   1319      *
   1320      * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
   1321      * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
   1322      * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
   1323      * @throws IllegalArgumentException if no provider with the given name exists
   1324      */
   1325     public void clearTestProviderStatus(String provider) {
   1326         try {
   1327             mService.clearTestProviderStatus(provider);
   1328         } catch (RemoteException e) {
   1329             Log.e(TAG, "RemoteException", e);
   1330         }
   1331     }
   1332 
   1333     // --- GPS-specific support ---
   1334 
   1335     // This class is used to send GPS status events to the client's main thread.
   1336     private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
   1337 
   1338         private final GpsStatus.Listener mListener;
   1339         private final GpsStatus.NmeaListener mNmeaListener;
   1340 
   1341         // This must not equal any of the GpsStatus event IDs
   1342         private static final int NMEA_RECEIVED = 1000;
   1343 
   1344         private class Nmea {
   1345             long mTimestamp;
   1346             String mNmea;
   1347 
   1348             Nmea(long timestamp, String nmea) {
   1349                 mTimestamp = timestamp;
   1350                 mNmea = nmea;
   1351             }
   1352         }
   1353         private ArrayList<Nmea> mNmeaBuffer;
   1354 
   1355         GpsStatusListenerTransport(GpsStatus.Listener listener) {
   1356             mListener = listener;
   1357             mNmeaListener = null;
   1358         }
   1359 
   1360         GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
   1361             mNmeaListener = listener;
   1362             mListener = null;
   1363             mNmeaBuffer = new ArrayList<Nmea>();
   1364         }
   1365 
   1366         @Override
   1367         public void onGpsStarted() {
   1368             if (mListener != null) {
   1369                 Message msg = Message.obtain();
   1370                 msg.what = GpsStatus.GPS_EVENT_STARTED;
   1371                 mGpsHandler.sendMessage(msg);
   1372             }
   1373         }
   1374 
   1375         @Override
   1376         public void onGpsStopped() {
   1377             if (mListener != null) {
   1378                 Message msg = Message.obtain();
   1379                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
   1380                 mGpsHandler.sendMessage(msg);
   1381             }
   1382         }
   1383 
   1384         @Override
   1385         public void onFirstFix(int ttff) {
   1386             if (mListener != null) {
   1387                 mGpsStatus.setTimeToFirstFix(ttff);
   1388                 Message msg = Message.obtain();
   1389                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
   1390                 mGpsHandler.sendMessage(msg);
   1391             }
   1392         }
   1393 
   1394         @Override
   1395         public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
   1396                 float[] elevations, float[] azimuths, int ephemerisMask,
   1397                 int almanacMask, int usedInFixMask) {
   1398             if (mListener != null) {
   1399                 mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
   1400                         ephemerisMask, almanacMask, usedInFixMask);
   1401 
   1402                 Message msg = Message.obtain();
   1403                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
   1404                 // remove any SV status messages already in the queue
   1405                 mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
   1406                 mGpsHandler.sendMessage(msg);
   1407             }
   1408         }
   1409 
   1410         @Override
   1411         public void onNmeaReceived(long timestamp, String nmea) {
   1412             if (mNmeaListener != null) {
   1413                 synchronized (mNmeaBuffer) {
   1414                     mNmeaBuffer.add(new Nmea(timestamp, nmea));
   1415                 }
   1416                 Message msg = Message.obtain();
   1417                 msg.what = NMEA_RECEIVED;
   1418                 // remove any NMEA_RECEIVED messages already in the queue
   1419                 mGpsHandler.removeMessages(NMEA_RECEIVED);
   1420                 mGpsHandler.sendMessage(msg);
   1421             }
   1422         }
   1423 
   1424         private final Handler mGpsHandler = new Handler() {
   1425             @Override
   1426             public void handleMessage(Message msg) {
   1427                 if (msg.what == NMEA_RECEIVED) {
   1428                     synchronized (mNmeaBuffer) {
   1429                         int length = mNmeaBuffer.size();
   1430                         for (int i = 0; i < length; i++) {
   1431                             Nmea nmea = mNmeaBuffer.get(i);
   1432                             mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
   1433                         }
   1434                         mNmeaBuffer.clear();
   1435                     }
   1436                 } else {
   1437                     // synchronize on mGpsStatus to ensure the data is copied atomically.
   1438                     synchronized(mGpsStatus) {
   1439                         mListener.onGpsStatusChanged(msg.what);
   1440                     }
   1441                 }
   1442             }
   1443         };
   1444     }
   1445 
   1446     /**
   1447      * Adds a GPS status listener.
   1448      *
   1449      * @param listener GPS status listener object to register
   1450      *
   1451      * @return true if the listener was successfully added
   1452      *
   1453      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1454      */
   1455     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
   1456         boolean result;
   1457 
   1458         if (mGpsStatusListeners.get(listener) != null) {
   1459             // listener is already registered
   1460             return true;
   1461         }
   1462         try {
   1463             GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
   1464             result = mService.addGpsStatusListener(transport, mContext.getPackageName());
   1465             if (result) {
   1466                 mGpsStatusListeners.put(listener, transport);
   1467             }
   1468         } catch (RemoteException e) {
   1469             Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
   1470             result = false;
   1471         }
   1472 
   1473         return result;
   1474     }
   1475 
   1476     /**
   1477      * Removes a GPS status listener.
   1478      *
   1479      * @param listener GPS status listener object to remove
   1480      */
   1481     public void removeGpsStatusListener(GpsStatus.Listener listener) {
   1482         try {
   1483             GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
   1484             if (transport != null) {
   1485                 mService.removeGpsStatusListener(transport);
   1486             }
   1487         } catch (RemoteException e) {
   1488             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
   1489         }
   1490     }
   1491 
   1492     /**
   1493      * Adds an NMEA listener.
   1494      *
   1495      * @param listener a {@link GpsStatus.NmeaListener} object to register
   1496      *
   1497      * @return true if the listener was successfully added
   1498      *
   1499      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1500      */
   1501     public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
   1502         boolean result;
   1503 
   1504         if (mNmeaListeners.get(listener) != null) {
   1505             // listener is already registered
   1506             return true;
   1507         }
   1508         try {
   1509             GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
   1510             result = mService.addGpsStatusListener(transport, mContext.getPackageName());
   1511             if (result) {
   1512                 mNmeaListeners.put(listener, transport);
   1513             }
   1514         } catch (RemoteException e) {
   1515             Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
   1516             result = false;
   1517         }
   1518 
   1519         return result;
   1520     }
   1521 
   1522     /**
   1523      * Removes an NMEA listener.
   1524      *
   1525      * @param listener a {@link GpsStatus.NmeaListener} object to remove
   1526      */
   1527     public void removeNmeaListener(GpsStatus.NmeaListener listener) {
   1528         try {
   1529             GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
   1530             if (transport != null) {
   1531                 mService.removeGpsStatusListener(transport);
   1532             }
   1533         } catch (RemoteException e) {
   1534             Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
   1535         }
   1536     }
   1537 
   1538      /**
   1539      * Retrieves information about the current status of the GPS engine.
   1540      * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
   1541      * callback to ensure that the data is copied atomically.
   1542      *
   1543      * The caller may either pass in a {@link GpsStatus} object to set with the latest
   1544      * status information, or pass null to create a new {@link GpsStatus} object.
   1545      *
   1546      * @param status object containing GPS status details, or null.
   1547      * @return status object containing updated GPS status.
   1548      */
   1549     public GpsStatus getGpsStatus(GpsStatus status) {
   1550         if (status == null) {
   1551             status = new GpsStatus();
   1552         }
   1553         status.setStatus(mGpsStatus);
   1554         return status;
   1555     }
   1556 
   1557     /**
   1558      * Sends additional commands to a location provider.
   1559      * Can be used to support provider specific extensions to the Location Manager API
   1560      *
   1561      * @param provider name of the location provider.
   1562      * @param command name of the command to send to the provider.
   1563      * @param extras optional arguments for the command (or null).
   1564      * The provider may optionally fill the extras Bundle with results from the command.
   1565      *
   1566      * @return true if the command succeeds.
   1567      */
   1568     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
   1569         try {
   1570             return mService.sendExtraCommand(provider, command, extras);
   1571         } catch (RemoteException e) {
   1572             Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
   1573             return false;
   1574         }
   1575     }
   1576 
   1577     /**
   1578      * Used by NetInitiatedActivity to report user response
   1579      * for network initiated GPS fix requests.
   1580      *
   1581      * @hide
   1582      */
   1583     public boolean sendNiResponse(int notifId, int userResponse) {
   1584     	try {
   1585             return mService.sendNiResponse(notifId, userResponse);
   1586         } catch (RemoteException e) {
   1587             Log.e(TAG, "RemoteException in sendNiResponse: ", e);
   1588             return false;
   1589         }
   1590     }
   1591 
   1592     private static void checkProvider(String provider) {
   1593         if (provider == null) {
   1594             throw new IllegalArgumentException("invalid provider: " + provider);
   1595         }
   1596     }
   1597 
   1598     private static void checkCriteria(Criteria criteria) {
   1599         if (criteria == null) {
   1600             throw new IllegalArgumentException("invalid criteria: " + criteria);
   1601         }
   1602     }
   1603 
   1604     private static void checkListener(LocationListener listener) {
   1605         if (listener == null) {
   1606             throw new IllegalArgumentException("invalid listener: " + listener);
   1607         }
   1608     }
   1609 
   1610     private void checkPendingIntent(PendingIntent intent) {
   1611         if (intent == null) {
   1612             throw new IllegalArgumentException("invalid pending intent: " + intent);
   1613         }
   1614         if (!intent.isTargetedToPackage()) {
   1615             IllegalArgumentException e = new IllegalArgumentException(
   1616                     "pending intent msut be targeted to package");
   1617             if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
   1618                 throw e;
   1619             } else {
   1620                 Log.w(TAG, e);
   1621             }
   1622         }
   1623     }
   1624 
   1625     private static void checkGeofence(Geofence fence) {
   1626         if (fence == null) {
   1627             throw new IllegalArgumentException("invalid geofence: " + fence);
   1628         }
   1629     }
   1630 }
   1631