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 static android.Manifest.permission.ACCESS_COARSE_LOCATION;
     20 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
     21 import static android.Manifest.permission.LOCATION_HARDWARE;
     22 import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
     23 
     24 import android.Manifest;
     25 import android.annotation.NonNull;
     26 import android.annotation.Nullable;
     27 import android.annotation.RequiresFeature;
     28 import android.annotation.RequiresPermission;
     29 import android.annotation.SuppressLint;
     30 import android.annotation.SystemApi;
     31 import android.annotation.SystemService;
     32 import android.annotation.TestApi;
     33 import android.app.PendingIntent;
     34 import android.content.Context;
     35 import android.content.Intent;
     36 import android.content.pm.PackageManager;
     37 import android.os.Build;
     38 import android.os.Bundle;
     39 import android.os.Handler;
     40 import android.os.Looper;
     41 import android.os.Message;
     42 import android.os.Process;
     43 import android.os.RemoteException;
     44 import android.os.UserHandle;
     45 import android.provider.Settings;
     46 import android.text.TextUtils;
     47 import android.util.ArraySet;
     48 import android.util.Log;
     49 import com.android.internal.location.ProviderProperties;
     50 import java.util.ArrayList;
     51 import java.util.Arrays;
     52 import java.util.HashMap;
     53 import java.util.List;
     54 import java.util.Set;
     55 
     56 /**
     57  * This class provides access to the system location services.  These
     58  * services allow applications to obtain periodic updates of the
     59  * device's geographical location, or to fire an application-specified
     60  * {@link Intent} when the device enters the proximity of a given
     61  * geographical location.
     62  *
     63  * <p class="note">Unless noted, all Location API methods require
     64  * the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
     65  * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions.
     66  * If your application only has the coarse permission then it will not have
     67  * access to the GPS or passive location providers. Other providers will still
     68  * return location results, but the update rate will be throttled and the exact
     69  * location will be obfuscated to a coarse level of accuracy.
     70  */
     71 @SystemService(Context.LOCATION_SERVICE)
     72 @RequiresFeature(PackageManager.FEATURE_LOCATION)
     73 public class LocationManager {
     74     private static final String TAG = "LocationManager";
     75 
     76     private final Context mContext;
     77     private final ILocationManager mService;
     78     private final GnssMeasurementCallbackTransport mGnssMeasurementCallbackTransport;
     79     private final GnssNavigationMessageCallbackTransport mGnssNavigationMessageCallbackTransport;
     80     private final BatchedLocationCallbackTransport mBatchedLocationCallbackTransport;
     81     private final HashMap<GpsStatus.Listener, GnssStatusListenerTransport> mGpsStatusListeners =
     82             new HashMap<>();
     83     private final HashMap<GpsStatus.NmeaListener, GnssStatusListenerTransport> mGpsNmeaListeners =
     84             new HashMap<>();
     85     private final HashMap<GnssStatus.Callback, GnssStatusListenerTransport> mGnssStatusListeners =
     86             new HashMap<>();
     87     private final HashMap<OnNmeaMessageListener, GnssStatusListenerTransport> mGnssNmeaListeners =
     88             new HashMap<>();
     89     // volatile + GnssStatus final-fields pattern to avoid a partially published object
     90     private volatile GnssStatus mGnssStatus;
     91     private int mTimeToFirstFix;
     92 
     93     /**
     94      * Name of the network location provider.
     95      * <p>This provider determines location based on
     96      * availability of cell tower and WiFi access points. Results are retrieved
     97      * by means of a network lookup.
     98      */
     99     public static final String NETWORK_PROVIDER = "network";
    100 
    101     /**
    102      * Name of the GPS location provider.
    103      *
    104      * <p>This provider determines location using
    105      * satellites. Depending on conditions, this provider may take a while to return
    106      * a location fix. Requires the permission
    107      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
    108      *
    109      * <p> The extras Bundle for the GPS location provider can contain the
    110      * following key/value pairs:
    111      * <ul>
    112      * <li> satellites - the number of satellites used to derive the fix
    113      * </ul>
    114      */
    115     public static final String GPS_PROVIDER = "gps";
    116 
    117     /**
    118      * A special location provider for receiving locations without actually initiating
    119      * a location fix.
    120      *
    121      * <p>This provider can be used to passively receive location updates
    122      * when other applications or services request them without actually requesting
    123      * the locations yourself.  This provider will return locations generated by other
    124      * providers.  You can query the {@link Location#getProvider()} method to determine
    125      * the origin of the location update. Requires the permission
    126      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION}, although if the GPS is
    127      * not enabled this provider might only return coarse fixes.
    128      */
    129     public static final String PASSIVE_PROVIDER = "passive";
    130 
    131     /**
    132      * Name of the Fused location provider.
    133      *
    134      * <p>This provider combines inputs for all possible location sources
    135      * to provide the best possible Location fix. It is implicitly
    136      * used for all API's that involve the {@link LocationRequest}
    137      * object.
    138      *
    139      * @hide
    140      */
    141     public static final String FUSED_PROVIDER = "fused";
    142 
    143     /**
    144      * Key used for the Bundle extra holding a boolean indicating whether
    145      * a proximity alert is entering (true) or exiting (false)..
    146      */
    147     public static final String KEY_PROXIMITY_ENTERING = "entering";
    148 
    149     /**
    150      * Key used for a Bundle extra holding an Integer status value
    151      * when a status change is broadcast using a PendingIntent.
    152      */
    153     public static final String KEY_STATUS_CHANGED = "status";
    154 
    155     /**
    156      * Key used for a Bundle extra holding an Boolean status value
    157      * when a provider enabled/disabled event is broadcast using a PendingIntent.
    158      */
    159     public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
    160 
    161     /**
    162      * Key used for a Bundle extra holding a Location value
    163      * when a location change is broadcast using a PendingIntent.
    164      */
    165     public static final String KEY_LOCATION_CHANGED = "location";
    166 
    167     /**
    168      * Broadcast intent action indicating that the GPS has either been
    169      * enabled or disabled. An intent extra provides this state as a boolean,
    170      * where {@code true} means enabled.
    171      * @see #EXTRA_GPS_ENABLED
    172      *
    173      * @hide
    174      */
    175     public static final String GPS_ENABLED_CHANGE_ACTION =
    176         "android.location.GPS_ENABLED_CHANGE";
    177 
    178     /**
    179      * Broadcast intent action when the configured location providers
    180      * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the
    181      * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION}
    182      * instead.
    183      */
    184     public static final String PROVIDERS_CHANGED_ACTION =
    185         "android.location.PROVIDERS_CHANGED";
    186 
    187     /**
    188      * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes.
    189      * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
    190      * If you're interacting with {@link #isProviderEnabled(String)}, use
    191      * {@link #PROVIDERS_CHANGED_ACTION} instead.
    192      *
    193      * In the future, there may be mode changes that do not result in
    194      * {@link #PROVIDERS_CHANGED_ACTION} broadcasts.
    195      */
    196     public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED";
    197 
    198     /**
    199      * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} is
    200      * about to be changed through Settings app or Quick Settings.
    201      * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API.
    202      * If you're interacting with {@link #isProviderEnabled(String)}, use
    203      * {@link #PROVIDERS_CHANGED_ACTION} instead.
    204      *
    205      * @hide
    206      */
    207     public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING";
    208 
    209     /**
    210      * Broadcast intent action indicating that the GPS has either started or
    211      * stopped receiving GPS fixes. An intent extra provides this state as a
    212      * boolean, where {@code true} means that the GPS is actively receiving fixes.
    213      * @see #EXTRA_GPS_ENABLED
    214      *
    215      * @hide
    216      */
    217     public static final String GPS_FIX_CHANGE_ACTION =
    218         "android.location.GPS_FIX_CHANGE";
    219 
    220     /**
    221      * The lookup key for a boolean that indicates whether GPS is enabled or
    222      * disabled. {@code true} means GPS is enabled. Retrieve it with
    223      * {@link android.content.Intent#getBooleanExtra(String,boolean)}.
    224      *
    225      * @hide
    226      */
    227     public static final String EXTRA_GPS_ENABLED = "enabled";
    228 
    229     /**
    230      * Broadcast intent action indicating that a high power location requests
    231      * has either started or stopped being active.  The current state of
    232      * active location requests should be read from AppOpsManager using
    233      * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
    234      *
    235      * @hide
    236      */
    237     public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
    238         "android.location.HIGH_POWER_REQUEST_CHANGE";
    239 
    240     /**
    241      * Broadcast intent action for Settings app to inject a footer at the bottom of location
    242      * settings.
    243      *
    244      * <p>This broadcast is used for two things:
    245      * <ol>
    246      *     <li>For receivers to inject a footer with provided text. This is for use only by apps
    247      *         that are included in the system image. </li>
    248      *     <li>For receivers to know their footer is injected under location settings.</li>
    249      * </ol>
    250      *
    251      * <p>To inject a footer to location settings, you must declare a broadcast receiver of
    252      * {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} in the manifest as so:
    253      * <pre>
    254      *     &lt;receiver android:name="com.example.android.footer.MyFooterInjector"&gt;
    255      *         &lt;intent-filter&gt;
    256      *             &lt;action android:name="com.android.settings.location.INJECT_FOOTER" /&gt;
    257      *         &lt;/intent-filter&gt;
    258      *         &lt;meta-data
    259      *             android:name="com.android.settings.location.FOOTER_STRING"
    260      *             android:resource="@string/my_injected_footer_string" /&gt;
    261      *     &lt;/receiver&gt;
    262      * </pre>
    263      *
    264      * <p>On entering location settings, Settings app will send a
    265      * {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast to receivers whose footer is successfully
    266      * injected. On leaving location settings, the footer becomes not visible to users. Settings app
    267      * will send a {@link #SETTINGS_FOOTER_REMOVED_ACTION} broadcast to those receivers.
    268      *
    269      * @hide
    270      */
    271     public static final String SETTINGS_FOOTER_DISPLAYED_ACTION =
    272             "com.android.settings.location.DISPLAYED_FOOTER";
    273 
    274     /**
    275      * Broadcast intent action when location settings footer is not visible to users.
    276      *
    277      * <p>See {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} for more detail on how to use.
    278      *
    279      * @hide
    280      */
    281     public static final String SETTINGS_FOOTER_REMOVED_ACTION =
    282             "com.android.settings.location.REMOVED_FOOTER";
    283 
    284     /**
    285      * Metadata name for {@link LocationManager#SETTINGS_FOOTER_DISPLAYED_ACTION} broadcast
    286      * receivers to specify a string resource id as location settings footer text. This is for use
    287      * only by apps that are included in the system image.
    288      *
    289      * <p>See {@link #SETTINGS_FOOTER_DISPLAYED_ACTION} for more detail on how to use.
    290      *
    291      * @hide
    292      */
    293     public static final String METADATA_SETTINGS_FOOTER_STRING =
    294             "com.android.settings.location.FOOTER_STRING";
    295 
    296     // Map from LocationListeners to their associated ListenerTransport objects
    297     private HashMap<LocationListener,ListenerTransport> mListeners =
    298         new HashMap<LocationListener,ListenerTransport>();
    299 
    300     private class ListenerTransport extends ILocationListener.Stub {
    301         private static final int TYPE_LOCATION_CHANGED = 1;
    302         private static final int TYPE_STATUS_CHANGED = 2;
    303         private static final int TYPE_PROVIDER_ENABLED = 3;
    304         private static final int TYPE_PROVIDER_DISABLED = 4;
    305 
    306         private LocationListener mListener;
    307         private final Handler mListenerHandler;
    308 
    309         ListenerTransport(LocationListener listener, Looper looper) {
    310             mListener = listener;
    311 
    312             if (looper == null) {
    313                 mListenerHandler = new Handler() {
    314                     @Override
    315                     public void handleMessage(Message msg) {
    316                         _handleMessage(msg);
    317                     }
    318                 };
    319             } else {
    320                 mListenerHandler = new Handler(looper) {
    321                     @Override
    322                     public void handleMessage(Message msg) {
    323                         _handleMessage(msg);
    324                     }
    325                 };
    326             }
    327         }
    328 
    329         @Override
    330         public void onLocationChanged(Location location) {
    331             Message msg = Message.obtain();
    332             msg.what = TYPE_LOCATION_CHANGED;
    333             msg.obj = location;
    334             mListenerHandler.sendMessage(msg);
    335         }
    336 
    337         @Override
    338         public void onStatusChanged(String provider, int status, Bundle extras) {
    339             Message msg = Message.obtain();
    340             msg.what = TYPE_STATUS_CHANGED;
    341             Bundle b = new Bundle();
    342             b.putString("provider", provider);
    343             b.putInt("status", status);
    344             if (extras != null) {
    345                 b.putBundle("extras", extras);
    346             }
    347             msg.obj = b;
    348             mListenerHandler.sendMessage(msg);
    349         }
    350 
    351         @Override
    352         public void onProviderEnabled(String provider) {
    353             Message msg = Message.obtain();
    354             msg.what = TYPE_PROVIDER_ENABLED;
    355             msg.obj = provider;
    356             mListenerHandler.sendMessage(msg);
    357         }
    358 
    359         @Override
    360         public void onProviderDisabled(String provider) {
    361             Message msg = Message.obtain();
    362             msg.what = TYPE_PROVIDER_DISABLED;
    363             msg.obj = provider;
    364             mListenerHandler.sendMessage(msg);
    365         }
    366 
    367         private void _handleMessage(Message msg) {
    368             switch (msg.what) {
    369                 case TYPE_LOCATION_CHANGED:
    370                     Location location = new Location((Location) msg.obj);
    371                     mListener.onLocationChanged(location);
    372                     break;
    373                 case TYPE_STATUS_CHANGED:
    374                     Bundle b = (Bundle) msg.obj;
    375                     String provider = b.getString("provider");
    376                     int status = b.getInt("status");
    377                     Bundle extras = b.getBundle("extras");
    378                     mListener.onStatusChanged(provider, status, extras);
    379                     break;
    380                 case TYPE_PROVIDER_ENABLED:
    381                     mListener.onProviderEnabled((String) msg.obj);
    382                     break;
    383                 case TYPE_PROVIDER_DISABLED:
    384                     mListener.onProviderDisabled((String) msg.obj);
    385                     break;
    386             }
    387             try {
    388                 mService.locationCallbackFinished(this);
    389             } catch (RemoteException e) {
    390                 throw e.rethrowFromSystemServer();
    391             }
    392         }
    393     }
    394 
    395     /**
    396      * @hide
    397      */
    398     @TestApi
    399     public String[] getBackgroundThrottlingWhitelist() {
    400         try {
    401             return mService.getBackgroundThrottlingWhitelist();
    402         } catch (RemoteException e) {
    403             throw e.rethrowFromSystemServer();
    404         }
    405     }
    406 
    407     /**
    408      * @hide - hide this constructor because it has a parameter
    409      * of type ILocationManager, which is a system private class. The
    410      * right way to create an instance of this class is using the
    411      * factory Context.getSystemService.
    412      */
    413     public LocationManager(Context context, ILocationManager service) {
    414         mService = service;
    415         mContext = context;
    416         mGnssMeasurementCallbackTransport =
    417                 new GnssMeasurementCallbackTransport(mContext, mService);
    418         mGnssNavigationMessageCallbackTransport =
    419                 new GnssNavigationMessageCallbackTransport(mContext, mService);
    420         mBatchedLocationCallbackTransport =
    421                 new BatchedLocationCallbackTransport(mContext, mService);
    422 
    423     }
    424 
    425     private LocationProvider createProvider(String name, ProviderProperties properties) {
    426         return new LocationProvider(name, properties);
    427     }
    428 
    429     /**
    430      * Returns a list of the names of all known location providers.
    431      * <p>All providers are returned, including ones that are not permitted to
    432      * be accessed by the calling activity or are currently disabled.
    433      *
    434      * @return list of Strings containing names of the provider
    435      */
    436     public List<String> getAllProviders() {
    437         try {
    438             return mService.getAllProviders();
    439         } catch (RemoteException e) {
    440             throw e.rethrowFromSystemServer();
    441         }
    442     }
    443 
    444     /**
    445      * Returns a list of the names of location providers.
    446      *
    447      * @param enabledOnly if true then only the providers which are currently
    448      * enabled are returned.
    449      * @return list of Strings containing names of the providers
    450      */
    451     public List<String> getProviders(boolean enabledOnly) {
    452         try {
    453             return mService.getProviders(null, enabledOnly);
    454         } catch (RemoteException e) {
    455             throw e.rethrowFromSystemServer();
    456         }
    457     }
    458 
    459     /**
    460      * Returns the information associated with the location provider of the
    461      * given name, or null if no provider exists by that name.
    462      *
    463      * @param name the provider name
    464      * @return a LocationProvider, or null
    465      *
    466      * @throws IllegalArgumentException if name is null or does not exist
    467      * @throws SecurityException if the caller is not permitted to access the
    468      * given provider.
    469      */
    470     public LocationProvider getProvider(String name) {
    471         checkProvider(name);
    472         try {
    473             ProviderProperties properties = mService.getProviderProperties(name);
    474             if (properties == null) {
    475                 return null;
    476             }
    477             return createProvider(name, properties);
    478         } catch (RemoteException e) {
    479             throw e.rethrowFromSystemServer();
    480         }
    481     }
    482 
    483     /**
    484      * Returns a list of the names of LocationProviders that satisfy the given
    485      * criteria, or null if none do.  Only providers that are permitted to be
    486      * accessed by the calling activity will be returned.
    487      *
    488      * @param criteria the criteria that the returned providers must match
    489      * @param enabledOnly if true then only the providers which are currently
    490      * enabled are returned.
    491      * @return list of Strings containing names of the providers
    492      */
    493     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
    494         checkCriteria(criteria);
    495         try {
    496             return mService.getProviders(criteria, enabledOnly);
    497         } catch (RemoteException e) {
    498             throw e.rethrowFromSystemServer();
    499         }
    500     }
    501 
    502     /**
    503      * Returns the name of the provider that best meets the given criteria. Only providers
    504      * that are permitted to be accessed by the calling activity will be
    505      * returned.  If several providers meet the criteria, the one with the best
    506      * accuracy is returned.  If no provider meets the criteria,
    507      * the criteria are loosened in the following sequence:
    508      *
    509      * <ul>
    510      * <li> power requirement
    511      * <li> accuracy
    512      * <li> bearing
    513      * <li> speed
    514      * <li> altitude
    515      * </ul>
    516      *
    517      * <p> Note that the requirement on monetary cost is not removed
    518      * in this process.
    519      *
    520      * @param criteria the criteria that need to be matched
    521      * @param enabledOnly if true then only a provider that is currently enabled is returned
    522      * @return name of the provider that best matches the requirements
    523      */
    524     public String getBestProvider(Criteria criteria, boolean enabledOnly) {
    525         checkCriteria(criteria);
    526         try {
    527             return mService.getBestProvider(criteria, enabledOnly);
    528         } catch (RemoteException e) {
    529             throw e.rethrowFromSystemServer();
    530         }
    531     }
    532 
    533     /**
    534      * Register for location updates using the named provider, and a
    535      * pending intent.
    536      *
    537      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    538      * for more detail on how to use this method.
    539      *
    540      * @param provider the name of the provider with which to register
    541      * @param minTime minimum time interval between location updates, in milliseconds
    542      * @param minDistance minimum distance between location updates, in meters
    543      * @param listener a {@link LocationListener} whose
    544      * {@link LocationListener#onLocationChanged} method will be called for
    545      * each location update
    546      *
    547      * @throws IllegalArgumentException if provider is null or doesn't exist
    548      * on this device
    549      * @throws IllegalArgumentException if listener is null
    550      * @throws RuntimeException if the calling thread has no Looper
    551      * @throws SecurityException if no suitable permission is present
    552      */
    553     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    554     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    555             LocationListener listener) {
    556         checkProvider(provider);
    557         checkListener(listener);
    558 
    559         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    560                 provider, minTime, minDistance, false);
    561         requestLocationUpdates(request, listener, null, null);
    562     }
    563 
    564     /**
    565      * Register for location updates using the named provider, and a callback on
    566      * the specified looper thread.
    567      *
    568      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    569      * for more detail on how to use this method.
    570      *
    571      * @param provider the name of the provider with which to register
    572      * @param minTime minimum time interval between location updates, in milliseconds
    573      * @param minDistance minimum distance between location updates, in meters
    574      * @param listener a {@link LocationListener} whose
    575      * {@link LocationListener#onLocationChanged} method will be called for
    576      * each location update
    577      * @param looper a Looper object whose message queue will be used to
    578      * implement the callback mechanism, or null to make callbacks on the calling
    579      * thread
    580      *
    581      * @throws IllegalArgumentException if provider is null or doesn't exist
    582      * @throws IllegalArgumentException if listener is null
    583      * @throws SecurityException if no suitable permission is present
    584      */
    585     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    586     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    587             LocationListener listener, Looper looper) {
    588         checkProvider(provider);
    589         checkListener(listener);
    590 
    591         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    592                 provider, minTime, minDistance, false);
    593         requestLocationUpdates(request, listener, looper, null);
    594     }
    595 
    596     /**
    597      * Register for location updates using a Criteria, and a callback
    598      * on the specified looper thread.
    599      *
    600      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    601      * for more detail on how to use this method.
    602      *
    603      * @param minTime minimum time interval between location updates, in milliseconds
    604      * @param minDistance minimum distance between location updates, in meters
    605      * @param criteria contains parameters for the location manager to choose the
    606      * appropriate provider and parameters to compute the location
    607      * @param listener a {@link LocationListener} whose
    608      * {@link LocationListener#onLocationChanged} method will be called for
    609      * each location update
    610      * @param looper a Looper object whose message queue will be used to
    611      * implement the callback mechanism, or null to make callbacks on the calling
    612      * thread
    613      *
    614      * @throws IllegalArgumentException if criteria is null
    615      * @throws IllegalArgumentException if listener is null
    616      * @throws SecurityException if no suitable permission is present
    617      */
    618     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    619     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
    620             LocationListener listener, Looper looper) {
    621         checkCriteria(criteria);
    622         checkListener(listener);
    623 
    624         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    625                 criteria, minTime, minDistance, false);
    626         requestLocationUpdates(request, listener, looper, null);
    627     }
    628 
    629     /**
    630      * Register for location updates using the named provider, and a
    631      * pending intent.
    632      *
    633      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    634      * for more detail on how to use this method.
    635      *
    636      * @param provider the name of the provider with which to register
    637      * @param minTime minimum time interval between location updates, in milliseconds
    638      * @param minDistance minimum distance between location updates, in meters
    639      * @param intent a {@link PendingIntent} to be sent for each location update
    640      *
    641      * @throws IllegalArgumentException if provider is null or doesn't exist
    642      * on this device
    643      * @throws IllegalArgumentException if intent is null
    644      * @throws SecurityException if no suitable permission is present
    645      */
    646     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    647     public void requestLocationUpdates(String provider, long minTime, float minDistance,
    648             PendingIntent intent) {
    649         checkProvider(provider);
    650         checkPendingIntent(intent);
    651 
    652         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    653                 provider, minTime, minDistance, false);
    654         requestLocationUpdates(request, null, null, intent);
    655     }
    656 
    657     /**
    658      * Register for location updates using a Criteria and pending intent.
    659      *
    660      * <p>The <code>requestLocationUpdates()</code> and
    661      * <code>requestSingleUpdate()</code> register the current activity to be
    662      * updated periodically by the named provider, or by the provider matching
    663      * the specified {@link Criteria}, with location and status updates.
    664      *
    665      * <p> It may take a while to receive the first location update. If
    666      * an immediate location is required, applications may use the
    667      * {@link #getLastKnownLocation(String)} method.
    668      *
    669      * <p> Location updates are received either by {@link LocationListener}
    670      * callbacks, or by broadcast intents to a supplied {@link PendingIntent}.
    671      *
    672      * <p> If the caller supplied a pending intent, then location updates
    673      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
    674      * {@link android.location.Location} value.
    675      *
    676      * <p> The location update interval can be controlled using the minTime parameter.
    677      * The elapsed time between location updates will never be less than
    678      * minTime, although it can be more depending on the Location Provider
    679      * implementation and the update interval requested by other applications.
    680      *
    681      * <p> Choosing a sensible value for minTime is important to conserve
    682      * battery life. Each location update requires power from
    683      * GPS, WIFI, Cell and other radios. Select a minTime value as high as
    684      * possible while still providing a reasonable user experience.
    685      * If your application is not in the foreground and showing
    686      * location to the user then your application should avoid using an active
    687      * provider (such as {@link #NETWORK_PROVIDER} or {@link #GPS_PROVIDER}),
    688      * but if you insist then select a minTime of 5 * 60 * 1000 (5 minutes)
    689      * or greater. If your application is in the foreground and showing
    690      * location to the user then it is appropriate to select a faster
    691      * update interval.
    692      *
    693      * <p> The minDistance parameter can also be used to control the
    694      * frequency of location updates. If it is greater than 0 then the
    695      * location provider will only send your application an update when
    696      * the location has changed by at least minDistance meters, AND
    697      * at least minTime milliseconds have passed. However it is more
    698      * difficult for location providers to save power using the minDistance
    699      * parameter, so minTime should be the primary tool to conserving battery
    700      * life.
    701      *
    702      * <p> If your application wants to passively observe location
    703      * updates triggered by other applications, but not consume
    704      * any additional power otherwise, then use the {@link #PASSIVE_PROVIDER}
    705      * This provider does not actively turn on or modify active location
    706      * providers, so you do not need to be as careful about minTime and
    707      * minDistance. However if your application performs heavy work
    708      * on a location update (such as network activity) then you should
    709      * select non-zero values for minTime and/or minDistance to rate-limit
    710      * your update frequency in the case another application enables a
    711      * location provider with extremely fast updates.
    712      *
    713      * <p>In case the provider is disabled by the user, updates will stop,
    714      * and a provider availability update will be sent.
    715      * As soon as the provider is enabled again,
    716      * location updates will immediately resume and a provider availability
    717      * update sent. Providers can also send status updates, at any time,
    718      * with extra's specific to the provider. If a callback was supplied
    719      * then status and availability updates are via
    720      * {@link LocationListener#onProviderDisabled},
    721      * {@link LocationListener#onProviderEnabled} or
    722      * {@link LocationListener#onStatusChanged}. Alternately, if a
    723      * pending intent was supplied then status and availability updates
    724      * are broadcast intents with extra keys of
    725      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED}.
    726      *
    727      * <p> If a {@link LocationListener} is used but with no Looper specified
    728      * then the calling thread must already
    729      * be a {@link android.os.Looper} thread such as the main thread of the
    730      * calling Activity. If a Looper is specified with a {@link LocationListener}
    731      * then callbacks are made on the supplied Looper thread.
    732      *
    733      * <p class="note"> Prior to Jellybean, the minTime parameter was
    734      * only a hint, and some location provider implementations ignored it.
    735      * From Jellybean and onwards it is mandatory for Android compatible
    736      * devices to observe both the minTime and minDistance parameters.
    737      *
    738      * @param minTime minimum time interval between location updates, in milliseconds
    739      * @param minDistance minimum distance between location updates, in meters
    740      * @param criteria contains parameters for the location manager to choose the
    741      * appropriate provider and parameters to compute the location
    742      * @param intent a {@link PendingIntent} to be sent for each location update
    743      *
    744      * @throws IllegalArgumentException if criteria is null
    745      * @throws IllegalArgumentException if intent is null
    746      * @throws SecurityException if no suitable permission is present
    747      */
    748     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    749     public void requestLocationUpdates(long minTime, float minDistance, Criteria criteria,
    750             PendingIntent intent) {
    751         checkCriteria(criteria);
    752         checkPendingIntent(intent);
    753 
    754         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    755                 criteria, minTime, minDistance, false);
    756         requestLocationUpdates(request, null, null, intent);
    757     }
    758 
    759     /**
    760      * Register for a single location update using the named provider and
    761      * a callback.
    762      *
    763      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    764      * for more detail on how to use this method.
    765      *
    766      * @param provider the name of the provider with which to register
    767      * @param listener a {@link LocationListener} whose
    768      * {@link LocationListener#onLocationChanged} method will be called when
    769      * the location update is available
    770      * @param looper a Looper object whose message queue will be used to
    771      * implement the callback mechanism, or null to make callbacks on the calling
    772      * thread
    773      *
    774      * @throws IllegalArgumentException if provider is null or doesn't exist
    775      * @throws IllegalArgumentException if listener is null
    776      * @throws SecurityException if no suitable permission is present
    777      */
    778     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    779     public void requestSingleUpdate(String provider, LocationListener listener, Looper looper) {
    780         checkProvider(provider);
    781         checkListener(listener);
    782 
    783         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    784                 provider, 0, 0, true);
    785         requestLocationUpdates(request, listener, looper, null);
    786     }
    787 
    788     /**
    789      * Register for a single location update using a Criteria and
    790      * a callback.
    791      *
    792      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    793      * for more detail on how to use this method.
    794      *
    795      * @param criteria contains parameters for the location manager to choose the
    796      * appropriate provider and parameters to compute the location
    797      * @param listener a {@link LocationListener} whose
    798      * {@link LocationListener#onLocationChanged} method will be called when
    799      * the location update is available
    800      * @param looper a Looper object whose message queue will be used to
    801      * implement the callback mechanism, or null to make callbacks on the calling
    802      * thread
    803      *
    804      * @throws IllegalArgumentException if criteria is null
    805      * @throws IllegalArgumentException if listener is null
    806      * @throws SecurityException if no suitable permission is present
    807      */
    808     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    809     public void requestSingleUpdate(Criteria criteria, LocationListener listener, Looper looper) {
    810         checkCriteria(criteria);
    811         checkListener(listener);
    812 
    813         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    814                 criteria, 0, 0, true);
    815         requestLocationUpdates(request, listener, looper, null);
    816     }
    817 
    818     /**
    819      * Register for a single location update using a named provider and pending intent.
    820      *
    821      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    822      * for more detail on how to use this method.
    823      *
    824      * @param provider the name of the provider with which to register
    825      * @param intent a {@link PendingIntent} to be sent for the location update
    826      *
    827      * @throws IllegalArgumentException if provider is null or doesn't exist
    828      * @throws IllegalArgumentException if intent is null
    829      * @throws SecurityException if no suitable permission is present
    830      */
    831     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    832     public void requestSingleUpdate(String provider, PendingIntent intent) {
    833         checkProvider(provider);
    834         checkPendingIntent(intent);
    835 
    836         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
    837                 provider, 0, 0, true);
    838         requestLocationUpdates(request, null, null, intent);
    839     }
    840 
    841     /**
    842      * Register for a single location update using a Criteria and pending intent.
    843      *
    844      * <p>See {@link #requestLocationUpdates(long, float, Criteria, PendingIntent)}
    845      * for more detail on how to use this method.
    846      *
    847      * @param criteria contains parameters for the location manager to choose the
    848      * appropriate provider and parameters to compute the location
    849      * @param intent a {@link PendingIntent} to be sent for the location update
    850      *
    851      * @throws IllegalArgumentException if provider is null or doesn't exist
    852      * @throws IllegalArgumentException if intent is null
    853      * @throws SecurityException if no suitable permission is present
    854      */
    855     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    856     public void requestSingleUpdate(Criteria criteria, PendingIntent intent) {
    857         checkCriteria(criteria);
    858         checkPendingIntent(intent);
    859 
    860         LocationRequest request = LocationRequest.createFromDeprecatedCriteria(
    861                 criteria, 0, 0, true);
    862         requestLocationUpdates(request, null, null, intent);
    863     }
    864 
    865     /**
    866      * Register for fused location updates using a LocationRequest and callback.
    867      *
    868      * <p>Upon a location update, the system delivers the new {@link Location} to the
    869      * provided {@link LocationListener}, by calling its {@link
    870      * LocationListener#onLocationChanged} method.</p>
    871      *
    872      * <p>The system will automatically select and enable the best providers
    873      * to compute a location for your application. It may use only passive
    874      * locations, or just a single location source, or it may fuse together
    875      * multiple location sources in order to produce the best possible
    876      * result, depending on the quality of service requested in the
    877      * {@link LocationRequest}.
    878      *
    879      * <p>LocationRequest can be null, in which case the system will choose
    880      * default, low power parameters for location updates. You will occasionally
    881      * receive location updates as available, without a major power impact on the
    882      * system. If your application just needs an occasional location update
    883      * without any strict demands, then pass a null LocationRequest.
    884      *
    885      * <p>Only one LocationRequest can be registered for each unique callback
    886      * or pending intent. So a subsequent request with the same callback or
    887      * pending intent will over-write the previous LocationRequest.
    888      *
    889      * <p> If a pending intent is supplied then location updates
    890      * are sent with a key of {@link #KEY_LOCATION_CHANGED} and a
    891      * {@link android.location.Location} value. If a callback is supplied
    892      * then location updates are made using the
    893      * {@link LocationListener#onLocationChanged} callback, on the specified
    894      * Looper thread. If a {@link LocationListener} is used
    895      * but with a null Looper then the calling thread must already
    896      * be a {@link android.os.Looper} thread (such as the main thread) and
    897      * callbacks will occur on this thread.
    898      *
    899      * <p> Provider status updates and availability updates are deprecated
    900      * because the system is performing provider fusion on the applications
    901      * behalf. So {@link LocationListener#onProviderDisabled},
    902      * {@link LocationListener#onProviderEnabled}, {@link LocationListener#onStatusChanged}
    903      * will not be called, and intents with extra keys of
    904      * {@link #KEY_PROVIDER_ENABLED} or {@link #KEY_STATUS_CHANGED} will not
    905      * be received.
    906      *
    907      * <p> To unregister for Location updates, use: {@link #removeUpdates(LocationListener)}.
    908      *
    909      * @param request quality of service required, null for default low power
    910      * @param listener a {@link LocationListener} whose
    911      * {@link LocationListener#onLocationChanged} method will be called when
    912      * the location update is available
    913      * @param looper a Looper object whose message queue will be used to
    914      * implement the callback mechanism, or null to make callbacks on the calling
    915      * thread
    916      *
    917      * @throws IllegalArgumentException if listener is null
    918      * @throws SecurityException if no suitable permission is present
    919      *
    920      * @hide
    921      */
    922     @SystemApi
    923     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    924     public void requestLocationUpdates(LocationRequest request, LocationListener listener,
    925             Looper looper) {
    926         checkListener(listener);
    927         requestLocationUpdates(request, listener, looper, null);
    928     }
    929 
    930 
    931     /**
    932      * Register for fused location updates using a LocationRequest and a pending intent.
    933      *
    934      * <p>Upon a location update, the system delivers the new {@link Location} with your provided
    935      * {@link PendingIntent}, as the value for {@link LocationManager#KEY_LOCATION_CHANGED}
    936      * in the intent's extras.</p>
    937      *
    938      * <p> To unregister for Location updates, use: {@link #removeUpdates(PendingIntent)}.
    939      *
    940      * <p> See {@link #requestLocationUpdates(LocationRequest, LocationListener, Looper)}
    941      * for more detail.
    942      *
    943      * @param request quality of service required, null for default low power
    944      * @param intent a {@link PendingIntent} to be sent for the location update
    945      *
    946      * @throws IllegalArgumentException if intent is null
    947      * @throws SecurityException if no suitable permission is present
    948      *
    949      * @hide
    950      */
    951     @SystemApi
    952     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    953     public void requestLocationUpdates(LocationRequest request, PendingIntent intent) {
    954         checkPendingIntent(intent);
    955         requestLocationUpdates(request, null, null, intent);
    956     }
    957 
    958     /**
    959      * Set the last known location with a new location.
    960      *
    961      * <p>A privileged client can inject a {@link Location} if it has a better estimate of what
    962      * the recent location is.  This is especially useful when the device boots up and the GPS
    963      * chipset is in the process of getting the first fix.  If the client has cached the location,
    964      * it can inject the {@link Location}, so if an app requests for a {@link Location} from {@link
    965      * #getLastKnownLocation(String)}, the location information is still useful before getting
    966      * the first fix.</p>
    967      *
    968      * <p> Useful in products like Auto.
    969      *
    970      * @param newLocation newly available {@link Location} object
    971      * @return true if update was successful, false if not
    972      *
    973      * @throws SecurityException if no suitable permission is present
    974      *
    975      * @hide
    976      */
    977     @RequiresPermission(allOf = {LOCATION_HARDWARE, ACCESS_FINE_LOCATION})
    978     public boolean injectLocation(Location newLocation) {
    979         try {
    980             return mService.injectLocation(newLocation);
    981         } catch (RemoteException e) {
    982             throw e.rethrowFromSystemServer();
    983         }
    984     }
    985 
    986     private ListenerTransport wrapListener(LocationListener listener, Looper looper) {
    987         if (listener == null) return null;
    988         synchronized (mListeners) {
    989             ListenerTransport transport = mListeners.get(listener);
    990             if (transport == null) {
    991                 transport = new ListenerTransport(listener, looper);
    992             }
    993             mListeners.put(listener, transport);
    994             return transport;
    995         }
    996     }
    997 
    998     private void requestLocationUpdates(LocationRequest request, LocationListener listener,
    999             Looper looper, PendingIntent intent) {
   1000 
   1001         String packageName = mContext.getPackageName();
   1002 
   1003         // wrap the listener class
   1004         ListenerTransport transport = wrapListener(listener, looper);
   1005 
   1006         try {
   1007             mService.requestLocationUpdates(request, transport, intent, packageName);
   1008        } catch (RemoteException e) {
   1009            throw e.rethrowFromSystemServer();
   1010        }
   1011     }
   1012 
   1013     /**
   1014      * Removes all location updates for the specified LocationListener.
   1015      *
   1016      * <p>Following this call, updates will no longer
   1017      * occur for this listener.
   1018      *
   1019      * @param listener listener object that no longer needs location updates
   1020      * @throws IllegalArgumentException if listener is null
   1021      */
   1022     public void removeUpdates(LocationListener listener) {
   1023         checkListener(listener);
   1024         String packageName = mContext.getPackageName();
   1025 
   1026         ListenerTransport transport;
   1027         synchronized (mListeners) {
   1028             transport = mListeners.remove(listener);
   1029         }
   1030         if (transport == null) return;
   1031 
   1032         try {
   1033             mService.removeUpdates(transport, null, packageName);
   1034         } catch (RemoteException e) {
   1035             throw e.rethrowFromSystemServer();
   1036         }
   1037     }
   1038 
   1039     /**
   1040      * Removes all location updates for the specified pending intent.
   1041      *
   1042      * <p>Following this call, updates will no longer for this pending intent.
   1043      *
   1044      * @param intent pending intent object that no longer needs location updates
   1045      * @throws IllegalArgumentException if intent is null
   1046      */
   1047     public void removeUpdates(PendingIntent intent) {
   1048         checkPendingIntent(intent);
   1049         String packageName = mContext.getPackageName();
   1050 
   1051         try {
   1052             mService.removeUpdates(null, intent, packageName);
   1053         } catch (RemoteException e) {
   1054             throw e.rethrowFromSystemServer();
   1055         }
   1056     }
   1057 
   1058     /**
   1059      * Set a proximity alert for the location given by the position
   1060      * (latitude, longitude) and the given radius.
   1061      *
   1062      * <p> When the device
   1063      * detects that it has entered or exited the area surrounding the
   1064      * location, the given PendingIntent will be used to create an Intent
   1065      * to be fired.
   1066      *
   1067      * <p> The fired Intent will have a boolean extra added with key
   1068      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
   1069      * entering the proximity region; if false, it is exiting.
   1070      *
   1071      * <p> Due to the approximate nature of position estimation, if the
   1072      * device passes through the given area briefly, it is possible
   1073      * that no Intent will be fired.  Similarly, an Intent could be
   1074      * fired if the device passes very close to the given area but
   1075      * does not actually enter it.
   1076      *
   1077      * <p> After the number of milliseconds given by the expiration
   1078      * parameter, the location manager will delete this proximity
   1079      * alert and no longer monitor it.  A value of -1 indicates that
   1080      * there should be no expiration time.
   1081      *
   1082      * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
   1083      * and {@link #GPS_PROVIDER}.
   1084      *
   1085      * <p>Before API version 17, this method could be used with
   1086      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
   1087      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
   1088      * From API version 17 and onwards, this method requires
   1089      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
   1090      *
   1091      * @param latitude the latitude of the central point of the
   1092      * alert region
   1093      * @param longitude the longitude of the central point of the
   1094      * alert region
   1095      * @param radius the radius of the central point of the
   1096      * alert region, in meters
   1097      * @param expiration time for this proximity alert, in milliseconds,
   1098      * or -1 to indicate no expiration
   1099      * @param intent a PendingIntent that will be used to generate an Intent to
   1100      * fire when entry to or exit from the alert region is detected
   1101      *
   1102      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1103      * permission is not present
   1104      */
   1105     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
   1106     public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
   1107             PendingIntent intent) {
   1108         checkPendingIntent(intent);
   1109         if (expiration < 0) expiration = Long.MAX_VALUE;
   1110 
   1111         Geofence fence = Geofence.createCircle(latitude, longitude, radius);
   1112         LocationRequest request = new LocationRequest().setExpireIn(expiration);
   1113         try {
   1114             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
   1115         } catch (RemoteException e) {
   1116             throw e.rethrowFromSystemServer();
   1117         }
   1118     }
   1119 
   1120     /**
   1121      * Add a geofence with the specified LocationRequest quality of service.
   1122      *
   1123      * <p> When the device
   1124      * detects that it has entered or exited the area surrounding the
   1125      * location, the given PendingIntent will be used to create an Intent
   1126      * to be fired.
   1127      *
   1128      * <p> The fired Intent will have a boolean extra added with key
   1129      * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
   1130      * entering the proximity region; if false, it is exiting.
   1131      *
   1132      * <p> The geofence engine fuses results from all location providers to
   1133      * provide the best balance between accuracy and power. Applications
   1134      * can choose the quality of service required using the
   1135      * {@link LocationRequest} object. If it is null then a default,
   1136      * low power geo-fencing implementation is used. It is possible to cross
   1137      * a geo-fence without notification, but the system will do its best
   1138      * to detect, using {@link LocationRequest} as a hint to trade-off
   1139      * accuracy and power.
   1140      *
   1141      * <p> The power required by the geofence engine can depend on many factors,
   1142      * such as quality and interval requested in {@link LocationRequest},
   1143      * distance to nearest geofence and current device velocity.
   1144      *
   1145      * @param request quality of service required, null for default low power
   1146      * @param fence a geographical description of the geofence area
   1147      * @param intent pending intent to receive geofence updates
   1148      *
   1149      * @throws IllegalArgumentException if fence is null
   1150      * @throws IllegalArgumentException if intent is null
   1151      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1152      * permission is not present
   1153      *
   1154      * @hide
   1155      */
   1156     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
   1157     public void addGeofence(LocationRequest request, Geofence fence, PendingIntent intent) {
   1158         checkPendingIntent(intent);
   1159         checkGeofence(fence);
   1160 
   1161         try {
   1162             mService.requestGeofence(request, fence, intent, mContext.getPackageName());
   1163         } catch (RemoteException e) {
   1164             throw e.rethrowFromSystemServer();
   1165         }
   1166     }
   1167 
   1168     /**
   1169      * Removes the proximity alert with the given PendingIntent.
   1170      *
   1171      * <p>Before API version 17, this method could be used with
   1172      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} or
   1173      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}.
   1174      * From API version 17 and onwards, this method requires
   1175      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
   1176      *
   1177      * @param intent the PendingIntent that no longer needs to be notified of
   1178      * proximity alerts
   1179      *
   1180      * @throws IllegalArgumentException if intent is null
   1181      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1182      * permission is not present
   1183      */
   1184     public void removeProximityAlert(PendingIntent intent) {
   1185         checkPendingIntent(intent);
   1186         String packageName = mContext.getPackageName();
   1187 
   1188         try {
   1189             mService.removeGeofence(null, intent, packageName);
   1190         } catch (RemoteException e) {
   1191             throw e.rethrowFromSystemServer();
   1192         }
   1193     }
   1194 
   1195     /**
   1196      * Remove a single geofence.
   1197      *
   1198      * <p>This removes only the specified geofence associated with the
   1199      * specified pending intent. All other geofences remain unchanged.
   1200      *
   1201      * @param fence a geofence previously passed to {@link #addGeofence}
   1202      * @param intent a pending intent previously passed to {@link #addGeofence}
   1203      *
   1204      * @throws IllegalArgumentException if fence is null
   1205      * @throws IllegalArgumentException if intent is null
   1206      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1207      * permission is not present
   1208      *
   1209      * @hide
   1210      */
   1211     public void removeGeofence(Geofence fence, PendingIntent intent) {
   1212         checkPendingIntent(intent);
   1213         checkGeofence(fence);
   1214         String packageName = mContext.getPackageName();
   1215 
   1216         try {
   1217             mService.removeGeofence(fence, intent, packageName);
   1218         } catch (RemoteException e) {
   1219             throw e.rethrowFromSystemServer();
   1220         }
   1221     }
   1222 
   1223     /**
   1224      * Remove all geofences registered to the specified pending intent.
   1225      *
   1226      * @param intent a pending intent previously passed to {@link #addGeofence}
   1227      *
   1228      * @throws IllegalArgumentException if intent is null
   1229      * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
   1230      * permission is not present
   1231      *
   1232      * @hide
   1233      */
   1234     public void removeAllGeofences(PendingIntent intent) {
   1235         checkPendingIntent(intent);
   1236         String packageName = mContext.getPackageName();
   1237 
   1238         try {
   1239             mService.removeGeofence(null, intent, packageName);
   1240         } catch (RemoteException e) {
   1241             throw e.rethrowFromSystemServer();
   1242         }
   1243     }
   1244 
   1245     /**
   1246      * Returns the current enabled/disabled status of location
   1247      *
   1248      * @return true if location is enabled. false if location is disabled.
   1249      */
   1250     public boolean isLocationEnabled() {
   1251         return isLocationEnabledForUser(Process.myUserHandle());
   1252     }
   1253 
   1254     /**
   1255      * Method for enabling or disabling location.
   1256      *
   1257      * @param enabled true to enable location. false to disable location
   1258      * @param userHandle the user to set
   1259      *
   1260      * @hide
   1261      */
   1262     @SystemApi
   1263     @RequiresPermission(WRITE_SECURE_SETTINGS)
   1264     public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) {
   1265         try {
   1266             mService.setLocationEnabledForUser(enabled, userHandle.getIdentifier());
   1267         } catch (RemoteException e) {
   1268             throw e.rethrowFromSystemServer();
   1269         }
   1270     }
   1271 
   1272     /**
   1273      * Returns the current enabled/disabled status of location
   1274      *
   1275      * @param userHandle the user to query
   1276      * @return true location is enabled. false if location is disabled.
   1277      *
   1278      * @hide
   1279      */
   1280     @SystemApi
   1281     public boolean isLocationEnabledForUser(UserHandle userHandle) {
   1282         try {
   1283             return mService.isLocationEnabledForUser(userHandle.getIdentifier());
   1284         } catch (RemoteException e) {
   1285             throw e.rethrowFromSystemServer();
   1286         }
   1287     }
   1288 
   1289     /**
   1290      * Returns the current enabled/disabled status of the given provider.
   1291      *
   1292      * <p>If the user has enabled this provider in the Settings menu, true
   1293      * is returned otherwise false is returned
   1294      *
   1295      * <p>Callers should instead use {@link #isLocationEnabled()}
   1296      * unless they depend on provider-specific APIs such as
   1297      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
   1298      *
   1299      * <p>
   1300      * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
   1301      * method would throw {@link SecurityException} if the location permissions
   1302      * were not sufficient to use the specified provider.
   1303      *
   1304      * @param provider the name of the provider
   1305      * @return true if the provider exists and is enabled
   1306      *
   1307      * @throws IllegalArgumentException if provider is null
   1308      */
   1309     public boolean isProviderEnabled(String provider) {
   1310         return isProviderEnabledForUser(provider, Process.myUserHandle());
   1311     }
   1312 
   1313     /**
   1314      * Returns the current enabled/disabled status of the given provider and user.
   1315      *
   1316      * <p>If the user has enabled this provider in the Settings menu, true
   1317      * is returned otherwise false is returned
   1318      *
   1319      * <p>Callers should instead use {@link #isLocationEnabled()}
   1320      * unless they depend on provider-specific APIs such as
   1321      * {@link #requestLocationUpdates(String, long, float, LocationListener)}.
   1322      *
   1323      * <p>
   1324      * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this
   1325      * method would throw {@link SecurityException} if the location permissions
   1326      * were not sufficient to use the specified provider.
   1327      *
   1328      * @param provider the name of the provider
   1329      * @param userHandle the user to query
   1330      * @return true if the provider exists and is enabled
   1331      *
   1332      * @throws IllegalArgumentException if provider is null
   1333      * @hide
   1334      */
   1335     @SystemApi
   1336     public boolean isProviderEnabledForUser(String provider, UserHandle userHandle) {
   1337         checkProvider(provider);
   1338 
   1339         try {
   1340             return mService.isProviderEnabledForUser(provider, userHandle.getIdentifier());
   1341         } catch (RemoteException e) {
   1342             throw e.rethrowFromSystemServer();
   1343         }
   1344     }
   1345 
   1346     /**
   1347      * Method for enabling or disabling a single location provider.
   1348      *
   1349      * @param provider the name of the provider
   1350      * @param enabled true to enable the provider. false to disable the provider
   1351      * @param userHandle the user to set
   1352      * @return true if the value was set, false on database errors
   1353      *
   1354      * @throws IllegalArgumentException if provider is null
   1355      * @hide
   1356      */
   1357     @SystemApi
   1358     @RequiresPermission(WRITE_SECURE_SETTINGS)
   1359     public boolean setProviderEnabledForUser(
   1360             String provider, boolean enabled, UserHandle userHandle) {
   1361         checkProvider(provider);
   1362 
   1363         try {
   1364             return mService.setProviderEnabledForUser(
   1365                     provider, enabled, userHandle.getIdentifier());
   1366         } catch (RemoteException e) {
   1367             throw e.rethrowFromSystemServer();
   1368         }
   1369     }
   1370 
   1371     /**
   1372      * Get the last known location.
   1373      *
   1374      * <p>This location could be very old so use
   1375      * {@link Location#getElapsedRealtimeNanos} to calculate its age. It can
   1376      * also return null if no previous location is available.
   1377      *
   1378      * <p>Always returns immediately.
   1379      *
   1380      * @return The last known location, or null if not available
   1381      * @throws SecurityException if no suitable permission is present
   1382      *
   1383      * @hide
   1384      */
   1385     public Location getLastLocation() {
   1386         String packageName = mContext.getPackageName();
   1387 
   1388         try {
   1389             return mService.getLastLocation(null, packageName);
   1390         } catch (RemoteException e) {
   1391             throw e.rethrowFromSystemServer();
   1392         }
   1393     }
   1394 
   1395     /**
   1396      * Returns a Location indicating the data from the last known
   1397      * location fix obtained from the given provider.
   1398      *
   1399      * <p> This can be done
   1400      * without starting the provider.  Note that this location could
   1401      * be out-of-date, for example if the device was turned off and
   1402      * moved to another location.
   1403      *
   1404      * <p> If the provider is currently disabled, null is returned.
   1405      *
   1406      * @param provider the name of the provider
   1407      * @return the last known location for the provider, or null
   1408      *
   1409      * @throws SecurityException if no suitable permission is present
   1410      * @throws IllegalArgumentException if provider is null or doesn't exist
   1411      */
   1412     @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
   1413     public Location getLastKnownLocation(String provider) {
   1414         checkProvider(provider);
   1415         String packageName = mContext.getPackageName();
   1416         LocationRequest request = LocationRequest.createFromDeprecatedProvider(
   1417                 provider, 0, 0, true);
   1418 
   1419         try {
   1420             return mService.getLastLocation(request, packageName);
   1421         } catch (RemoteException e) {
   1422             throw e.rethrowFromSystemServer();
   1423         }
   1424     }
   1425 
   1426     // --- Mock provider support ---
   1427     // TODO: It would be fantastic to deprecate mock providers entirely, and replace
   1428     // with something closer to LocationProviderBase.java
   1429 
   1430     /**
   1431      * Creates a mock location provider and adds it to the set of active providers.
   1432      *
   1433      * @param name the provider name
   1434      *
   1435      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1436      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1437      * allowed} for your app.
   1438      * @throws IllegalArgumentException if a provider with the given name already exists
   1439      */
   1440     public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
   1441             boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
   1442             boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
   1443         ProviderProperties properties = new ProviderProperties(requiresNetwork,
   1444                 requiresSatellite, requiresCell, hasMonetaryCost, supportsAltitude, supportsSpeed,
   1445                 supportsBearing, powerRequirement, accuracy);
   1446         if (name.matches(LocationProvider.BAD_CHARS_REGEX)) {
   1447             throw new IllegalArgumentException("provider name contains illegal character: " + name);
   1448         }
   1449 
   1450         try {
   1451             mService.addTestProvider(name, properties, mContext.getOpPackageName());
   1452         } catch (RemoteException e) {
   1453             throw e.rethrowFromSystemServer();
   1454         }
   1455     }
   1456 
   1457     /**
   1458      * Removes the mock location provider with the given name.
   1459      *
   1460      * @param provider the provider name
   1461      *
   1462      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1463      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1464      * allowed} for your app.
   1465      * @throws IllegalArgumentException if no provider with the given name exists
   1466      */
   1467     public void removeTestProvider(String provider) {
   1468         try {
   1469             mService.removeTestProvider(provider, mContext.getOpPackageName());
   1470         } catch (RemoteException e) {
   1471             throw e.rethrowFromSystemServer();
   1472         }
   1473     }
   1474 
   1475     /**
   1476      * Sets a mock location for the given provider.
   1477      * <p>This location will be used in place of any actual location from the provider.
   1478      * The location object must have a minimum number of fields set to be
   1479      * considered a valid LocationProvider Location, as per documentation
   1480      * on {@link Location} class.
   1481      *
   1482      * @param provider the provider name
   1483      * @param loc the mock location
   1484      *
   1485      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1486      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1487      * allowed} for your app.
   1488      * @throws IllegalArgumentException if no provider with the given name exists
   1489      * @throws IllegalArgumentException if the location is incomplete
   1490      */
   1491     public void setTestProviderLocation(String provider, Location loc) {
   1492         if (!loc.isComplete()) {
   1493             IllegalArgumentException e = new IllegalArgumentException(
   1494                     "Incomplete location object, missing timestamp or accuracy? " + loc);
   1495             if (mContext.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN) {
   1496                 // just log on old platform (for backwards compatibility)
   1497                 Log.w(TAG, e);
   1498                 loc.makeComplete();
   1499             } else {
   1500                 // really throw it!
   1501                 throw e;
   1502             }
   1503         }
   1504 
   1505         try {
   1506             mService.setTestProviderLocation(provider, loc, mContext.getOpPackageName());
   1507         } catch (RemoteException e) {
   1508             throw e.rethrowFromSystemServer();
   1509         }
   1510     }
   1511 
   1512     /**
   1513      * Removes any mock location associated with the given provider.
   1514      *
   1515      * @param provider the provider name
   1516      *
   1517      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1518      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1519      * allowed} for your app.
   1520      * @throws IllegalArgumentException if no provider with the given name exists
   1521      */
   1522     public void clearTestProviderLocation(String provider) {
   1523         try {
   1524             mService.clearTestProviderLocation(provider, mContext.getOpPackageName());
   1525         } catch (RemoteException e) {
   1526             throw e.rethrowFromSystemServer();
   1527         }
   1528     }
   1529 
   1530     /**
   1531      * Sets a mock enabled value for the given provider.  This value will be used in place
   1532      * of any actual value from the provider.
   1533      *
   1534      * @param provider the provider name
   1535      * @param enabled the mock enabled value
   1536      *
   1537      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1538      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1539      * allowed} for your app.
   1540      * @throws IllegalArgumentException if no provider with the given name exists
   1541      */
   1542     public void setTestProviderEnabled(String provider, boolean enabled) {
   1543         try {
   1544             mService.setTestProviderEnabled(provider, enabled, mContext.getOpPackageName());
   1545         } catch (RemoteException e) {
   1546             throw e.rethrowFromSystemServer();
   1547         }
   1548     }
   1549 
   1550     /**
   1551      * Removes any mock enabled value associated with the given provider.
   1552      *
   1553      * @param provider the provider name
   1554      *
   1555      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1556      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1557      * allowed} for your app.
   1558      * @throws IllegalArgumentException if no provider with the given name exists
   1559      */
   1560     public void clearTestProviderEnabled(String provider) {
   1561         try {
   1562             mService.clearTestProviderEnabled(provider, mContext.getOpPackageName());
   1563         } catch (RemoteException e) {
   1564             throw e.rethrowFromSystemServer();
   1565         }
   1566     }
   1567 
   1568     /**
   1569      * Sets mock status values for the given provider.  These values will be used in place
   1570      * of any actual values from the provider.
   1571      *
   1572      * @param provider the provider name
   1573      * @param status the mock status
   1574      * @param extras a Bundle containing mock extras
   1575      * @param updateTime the mock update time
   1576      *
   1577      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1578      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1579      * allowed} for your app.
   1580      * @throws IllegalArgumentException if no provider with the given name exists
   1581      */
   1582     public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
   1583         try {
   1584             mService.setTestProviderStatus(provider, status, extras, updateTime,
   1585                     mContext.getOpPackageName());
   1586         } catch (RemoteException e) {
   1587             throw e.rethrowFromSystemServer();
   1588         }
   1589     }
   1590 
   1591     /**
   1592      * Removes any mock status values associated with the given provider.
   1593      *
   1594      * @param provider the provider name
   1595      *
   1596      * @throws SecurityException if {@link android.app.AppOpsManager#OPSTR_MOCK_LOCATION
   1597      * mock location app op} is not set to {@link android.app.AppOpsManager#MODE_ALLOWED
   1598      * allowed} for your app.
   1599      * @throws IllegalArgumentException if no provider with the given name exists
   1600      */
   1601     public void clearTestProviderStatus(String provider) {
   1602         try {
   1603             mService.clearTestProviderStatus(provider, mContext.getOpPackageName());
   1604         } catch (RemoteException e) {
   1605             throw e.rethrowFromSystemServer();
   1606         }
   1607     }
   1608 
   1609     // --- GPS-specific support ---
   1610 
   1611     // This class is used to send Gnss status events to the client's specific thread.
   1612     private class GnssStatusListenerTransport extends IGnssStatusListener.Stub {
   1613 
   1614         private final GpsStatus.Listener mGpsListener;
   1615         private final GpsStatus.NmeaListener mGpsNmeaListener;
   1616         private final GnssStatus.Callback mGnssCallback;
   1617         private final OnNmeaMessageListener mGnssNmeaListener;
   1618 
   1619         private class GnssHandler extends Handler {
   1620             public GnssHandler(Handler handler) {
   1621                 super(handler != null ? handler.getLooper() : Looper.myLooper());
   1622             }
   1623 
   1624             @Override
   1625             public void handleMessage(Message msg) {
   1626                 switch (msg.what) {
   1627                     case NMEA_RECEIVED:
   1628                         synchronized (mNmeaBuffer) {
   1629                             int length = mNmeaBuffer.size();
   1630                             for (int i = 0; i < length; i++) {
   1631                                 Nmea nmea = mNmeaBuffer.get(i);
   1632                                 mGnssNmeaListener.onNmeaMessage(nmea.mNmea, nmea.mTimestamp);
   1633                             }
   1634                             mNmeaBuffer.clear();
   1635                         }
   1636                         break;
   1637                     case GpsStatus.GPS_EVENT_STARTED:
   1638                         mGnssCallback.onStarted();
   1639                         break;
   1640                     case GpsStatus.GPS_EVENT_STOPPED:
   1641                         mGnssCallback.onStopped();
   1642                         break;
   1643                     case GpsStatus.GPS_EVENT_FIRST_FIX:
   1644                         mGnssCallback.onFirstFix(mTimeToFirstFix);
   1645                         break;
   1646                     case GpsStatus.GPS_EVENT_SATELLITE_STATUS:
   1647                         mGnssCallback.onSatelliteStatusChanged(mGnssStatus);
   1648                         break;
   1649                     default:
   1650                         break;
   1651                 }
   1652             }
   1653         }
   1654 
   1655         private final Handler mGnssHandler;
   1656 
   1657         // This must not equal any of the GpsStatus event IDs
   1658         private static final int NMEA_RECEIVED = 1000;
   1659 
   1660         private class Nmea {
   1661             long mTimestamp;
   1662             String mNmea;
   1663 
   1664             Nmea(long timestamp, String nmea) {
   1665                 mTimestamp = timestamp;
   1666                 mNmea = nmea;
   1667             }
   1668         }
   1669         private final ArrayList<Nmea> mNmeaBuffer;
   1670 
   1671         GnssStatusListenerTransport(GpsStatus.Listener listener) {
   1672             this(listener, null);
   1673         }
   1674 
   1675         GnssStatusListenerTransport(GpsStatus.Listener listener, Handler handler) {
   1676             mGpsListener = listener;
   1677             mGnssHandler = new GnssHandler(handler);
   1678             mGpsNmeaListener = null;
   1679             mNmeaBuffer = null;
   1680             mGnssCallback = mGpsListener != null ? new GnssStatus.Callback() {
   1681                 @Override
   1682                 public void onStarted() {
   1683                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STARTED);
   1684                 }
   1685 
   1686                 @Override
   1687                 public void onStopped() {
   1688                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_STOPPED);
   1689                 }
   1690 
   1691                 @Override
   1692                 public void onFirstFix(int ttff) {
   1693                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_FIRST_FIX);
   1694                 }
   1695 
   1696                 @Override
   1697                 public void onSatelliteStatusChanged(GnssStatus status) {
   1698                     mGpsListener.onGpsStatusChanged(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
   1699                 }
   1700             } : null;
   1701             mGnssNmeaListener = null;
   1702         }
   1703 
   1704         GnssStatusListenerTransport(GpsStatus.NmeaListener listener) {
   1705             this(listener, null);
   1706         }
   1707 
   1708         GnssStatusListenerTransport(GpsStatus.NmeaListener listener, Handler handler) {
   1709             mGpsListener = null;
   1710             mGnssHandler = new GnssHandler(handler);
   1711             mGpsNmeaListener = listener;
   1712             mNmeaBuffer = new ArrayList<Nmea>();
   1713             mGnssCallback = null;
   1714             mGnssNmeaListener = mGpsNmeaListener != null ? new OnNmeaMessageListener() {
   1715                 @Override
   1716                 public void onNmeaMessage(String nmea, long timestamp) {
   1717                     mGpsNmeaListener.onNmeaReceived(timestamp, nmea);
   1718                 }
   1719             } : null;
   1720         }
   1721 
   1722         GnssStatusListenerTransport(GnssStatus.Callback callback) {
   1723             this(callback, null);
   1724         }
   1725 
   1726         GnssStatusListenerTransport(GnssStatus.Callback callback, Handler handler) {
   1727             mGnssCallback = callback;
   1728             mGnssHandler = new GnssHandler(handler);
   1729             mGnssNmeaListener = null;
   1730             mNmeaBuffer = null;
   1731             mGpsListener = null;
   1732             mGpsNmeaListener = null;
   1733         }
   1734 
   1735         GnssStatusListenerTransport(OnNmeaMessageListener listener) {
   1736             this(listener, null);
   1737         }
   1738 
   1739         GnssStatusListenerTransport(OnNmeaMessageListener listener, Handler handler) {
   1740             mGnssCallback = null;
   1741             mGnssHandler = new GnssHandler(handler);
   1742             mGnssNmeaListener = listener;
   1743             mGpsListener = null;
   1744             mGpsNmeaListener = null;
   1745             mNmeaBuffer = new ArrayList<Nmea>();
   1746         }
   1747 
   1748         @Override
   1749         public void onGnssStarted() {
   1750             if (mGnssCallback != null) {
   1751                 Message msg = Message.obtain();
   1752                 msg.what = GpsStatus.GPS_EVENT_STARTED;
   1753                 mGnssHandler.sendMessage(msg);
   1754             }
   1755         }
   1756 
   1757         @Override
   1758         public void onGnssStopped() {
   1759             if (mGnssCallback != null) {
   1760                 Message msg = Message.obtain();
   1761                 msg.what = GpsStatus.GPS_EVENT_STOPPED;
   1762                 mGnssHandler.sendMessage(msg);
   1763             }
   1764         }
   1765 
   1766         @Override
   1767         public void onFirstFix(int ttff) {
   1768             if (mGnssCallback != null) {
   1769                 mTimeToFirstFix = ttff;
   1770                 Message msg = Message.obtain();
   1771                 msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
   1772                 mGnssHandler.sendMessage(msg);
   1773             }
   1774         }
   1775 
   1776         @Override
   1777         public void onSvStatusChanged(int svCount, int[] prnWithFlags,
   1778                 float[] cn0s, float[] elevations, float[] azimuths, float[] carrierFreqs) {
   1779             if (mGnssCallback != null) {
   1780                 mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths,
   1781                         carrierFreqs);
   1782 
   1783                 Message msg = Message.obtain();
   1784                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
   1785                 // remove any SV status messages already in the queue
   1786                 mGnssHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
   1787                 mGnssHandler.sendMessage(msg);
   1788             }
   1789         }
   1790 
   1791         @Override
   1792         public void onNmeaReceived(long timestamp, String nmea) {
   1793             if (mGnssNmeaListener != null) {
   1794                 synchronized (mNmeaBuffer) {
   1795                     mNmeaBuffer.add(new Nmea(timestamp, nmea));
   1796                 }
   1797                 Message msg = Message.obtain();
   1798                 msg.what = NMEA_RECEIVED;
   1799                 // remove any NMEA_RECEIVED messages already in the queue
   1800                 mGnssHandler.removeMessages(NMEA_RECEIVED);
   1801                 mGnssHandler.sendMessage(msg);
   1802             }
   1803         }
   1804     }
   1805 
   1806     /**
   1807      * Adds a GPS status listener.
   1808      *
   1809      * @param listener GPS status listener object to register
   1810      *
   1811      * @return true if the listener was successfully added
   1812      *
   1813      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1814      * @deprecated use {@link #registerGnssStatusCallback(GnssStatus.Callback)} instead.
   1815      */
   1816     @Deprecated
   1817     @RequiresPermission(ACCESS_FINE_LOCATION)
   1818     public boolean addGpsStatusListener(GpsStatus.Listener listener) {
   1819         boolean result;
   1820 
   1821         if (mGpsStatusListeners.get(listener) != null) {
   1822             // listener is already registered
   1823             return true;
   1824         }
   1825         try {
   1826             GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
   1827             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
   1828             if (result) {
   1829                 mGpsStatusListeners.put(listener, transport);
   1830             }
   1831         } catch (RemoteException e) {
   1832             throw e.rethrowFromSystemServer();
   1833         }
   1834 
   1835         return result;
   1836     }
   1837 
   1838     /**
   1839      * Removes a GPS status listener.
   1840      *
   1841      * @param listener GPS status listener object to remove
   1842      * @deprecated use {@link #unregisterGnssStatusCallback(GnssStatus.Callback)} instead.
   1843      */
   1844     @Deprecated
   1845     public void removeGpsStatusListener(GpsStatus.Listener listener) {
   1846         try {
   1847             GnssStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
   1848             if (transport != null) {
   1849                 mService.unregisterGnssStatusCallback(transport);
   1850             }
   1851         } catch (RemoteException e) {
   1852             throw e.rethrowFromSystemServer();
   1853         }
   1854     }
   1855 
   1856     /**
   1857      * Registers a GNSS status callback.
   1858      *
   1859      * @param callback GNSS status callback object to register
   1860      *
   1861      * @return true if the listener was successfully added
   1862      *
   1863      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1864      */
   1865     @RequiresPermission(ACCESS_FINE_LOCATION)
   1866     public boolean registerGnssStatusCallback(GnssStatus.Callback callback) {
   1867         return registerGnssStatusCallback(callback, null);
   1868     }
   1869 
   1870     /**
   1871      * Registers a GNSS status callback.
   1872      *
   1873      * @param callback GNSS status callback object to register
   1874      * @param handler the handler that the callback runs on.
   1875      *
   1876      * @return true if the listener was successfully added
   1877      *
   1878      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1879      */
   1880     @RequiresPermission(ACCESS_FINE_LOCATION)
   1881     public boolean registerGnssStatusCallback(GnssStatus.Callback callback, Handler handler) {
   1882         boolean result;
   1883         if (mGnssStatusListeners.get(callback) != null) {
   1884             // listener is already registered
   1885             return true;
   1886         }
   1887         try {
   1888             GnssStatusListenerTransport transport =
   1889                     new GnssStatusListenerTransport(callback, handler);
   1890             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
   1891             if (result) {
   1892                 mGnssStatusListeners.put(callback, transport);
   1893             }
   1894         } catch (RemoteException e) {
   1895             throw e.rethrowFromSystemServer();
   1896         }
   1897 
   1898         return result;
   1899     }
   1900 
   1901     /**
   1902      * Removes a GNSS status callback.
   1903      *
   1904      * @param callback GNSS status callback object to remove
   1905      */
   1906     public void unregisterGnssStatusCallback(GnssStatus.Callback callback) {
   1907         try {
   1908             GnssStatusListenerTransport transport = mGnssStatusListeners.remove(callback);
   1909             if (transport != null) {
   1910                 mService.unregisterGnssStatusCallback(transport);
   1911             }
   1912         } catch (RemoteException e) {
   1913             throw e.rethrowFromSystemServer();
   1914         }
   1915     }
   1916 
   1917     /**
   1918      * Adds an NMEA listener.
   1919      *
   1920      * @param listener a {@link GpsStatus.NmeaListener} object to register
   1921      *
   1922      * @return true if the listener was successfully added
   1923      *
   1924      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1925      * @deprecated use {@link #addNmeaListener(OnNmeaMessageListener)} instead.
   1926      */
   1927     @Deprecated
   1928     @RequiresPermission(ACCESS_FINE_LOCATION)
   1929     public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
   1930         boolean result;
   1931 
   1932         if (mGpsNmeaListeners.get(listener) != null) {
   1933             // listener is already registered
   1934             return true;
   1935         }
   1936         try {
   1937             GnssStatusListenerTransport transport = new GnssStatusListenerTransport(listener);
   1938             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
   1939             if (result) {
   1940                 mGpsNmeaListeners.put(listener, transport);
   1941             }
   1942         } catch (RemoteException e) {
   1943             throw e.rethrowFromSystemServer();
   1944         }
   1945 
   1946         return result;
   1947     }
   1948 
   1949     /**
   1950      * Removes an NMEA listener.
   1951      *
   1952      * @param listener a {@link GpsStatus.NmeaListener} object to remove
   1953      * @deprecated use {@link #removeNmeaListener(OnNmeaMessageListener)} instead.
   1954      */
   1955     @Deprecated
   1956     public void removeNmeaListener(GpsStatus.NmeaListener listener) {
   1957         try {
   1958             GnssStatusListenerTransport transport = mGpsNmeaListeners.remove(listener);
   1959             if (transport != null) {
   1960                 mService.unregisterGnssStatusCallback(transport);
   1961             }
   1962         } catch (RemoteException e) {
   1963             throw e.rethrowFromSystemServer();
   1964         }
   1965     }
   1966 
   1967     /**
   1968      * Adds an NMEA listener.
   1969      *
   1970      * @param listener a {@link OnNmeaMessageListener} object to register
   1971      *
   1972      * @return true if the listener was successfully added
   1973      *
   1974      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1975      */
   1976     @RequiresPermission(ACCESS_FINE_LOCATION)
   1977     public boolean addNmeaListener(OnNmeaMessageListener listener) {
   1978         return addNmeaListener(listener, null);
   1979     }
   1980 
   1981     /**
   1982      * Adds an NMEA listener.
   1983      *
   1984      * @param listener a {@link OnNmeaMessageListener} object to register
   1985      * @param handler the handler that the listener runs on.
   1986      *
   1987      * @return true if the listener was successfully added
   1988      *
   1989      * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
   1990      */
   1991     @RequiresPermission(ACCESS_FINE_LOCATION)
   1992     public boolean addNmeaListener(OnNmeaMessageListener listener, Handler handler) {
   1993         boolean result;
   1994 
   1995         if (mGpsNmeaListeners.get(listener) != null) {
   1996             // listener is already registered
   1997             return true;
   1998         }
   1999         try {
   2000             GnssStatusListenerTransport transport =
   2001                     new GnssStatusListenerTransport(listener, handler);
   2002             result = mService.registerGnssStatusCallback(transport, mContext.getPackageName());
   2003             if (result) {
   2004                 mGnssNmeaListeners.put(listener, transport);
   2005             }
   2006         } catch (RemoteException e) {
   2007             throw e.rethrowFromSystemServer();
   2008         }
   2009 
   2010         return result;
   2011     }
   2012 
   2013     /**
   2014      * Removes an NMEA listener.
   2015      *
   2016      * @param listener a {@link OnNmeaMessageListener} object to remove
   2017      */
   2018     public void removeNmeaListener(OnNmeaMessageListener listener) {
   2019         try {
   2020             GnssStatusListenerTransport transport = mGnssNmeaListeners.remove(listener);
   2021             if (transport != null) {
   2022                 mService.unregisterGnssStatusCallback(transport);
   2023             }
   2024         } catch (RemoteException e) {
   2025             throw e.rethrowFromSystemServer();
   2026         }
   2027     }
   2028 
   2029     /**
   2030      * No-op method to keep backward-compatibility.
   2031      * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
   2032      * @hide
   2033      * @deprecated Not supported anymore.
   2034      */
   2035     @Deprecated
   2036     @SystemApi
   2037     @SuppressLint("Doclava125")
   2038     public boolean addGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
   2039         return false;
   2040     }
   2041 
   2042     /**
   2043      * Registers a GPS Measurement callback.
   2044      *
   2045      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
   2046      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
   2047      */
   2048     @RequiresPermission(ACCESS_FINE_LOCATION)
   2049     public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
   2050         return registerGnssMeasurementsCallback(callback, null);
   2051     }
   2052 
   2053     /**
   2054      * Registers a GPS Measurement callback.
   2055      *
   2056      * @param callback a {@link GnssMeasurementsEvent.Callback} object to register.
   2057      * @param handler the handler that the callback runs on.
   2058      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
   2059      */
   2060     @RequiresPermission(ACCESS_FINE_LOCATION)
   2061     public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback,
   2062             Handler handler) {
   2063         return mGnssMeasurementCallbackTransport.add(callback, handler);
   2064     }
   2065 
   2066     /**
   2067      * No-op method to keep backward-compatibility.
   2068      * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead.
   2069      * @hide
   2070      * @deprecated use {@link #unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback)}
   2071      * instead.
   2072      */
   2073     @Deprecated
   2074     @SystemApi
   2075     @SuppressLint("Doclava125")
   2076     public void removeGpsMeasurementListener(GpsMeasurementsEvent.Listener listener) {
   2077     }
   2078 
   2079     /**
   2080      * Unregisters a GPS Measurement callback.
   2081      *
   2082      * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
   2083      */
   2084     public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
   2085         mGnssMeasurementCallbackTransport.remove(callback);
   2086     }
   2087 
   2088     /**
   2089      * No-op method to keep backward-compatibility.
   2090      * Don't use it. Use {@link #registerGnssNavigationMessageCallback} instead.
   2091      * @hide
   2092      * @deprecated Not supported anymore.
   2093      */
   2094     @Deprecated
   2095     @SystemApi
   2096     @SuppressLint("Doclava125")
   2097     public boolean addGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
   2098         return false;
   2099     }
   2100 
   2101     /**
   2102      * No-op method to keep backward-compatibility.
   2103      * Don't use it. Use {@link #unregisterGnssNavigationMessageCallback} instead.
   2104      * @hide
   2105      * @deprecated use
   2106      * {@link #unregisterGnssNavigationMessageCallback(GnssNavigationMessage.Callback)}
   2107      * instead
   2108      */
   2109     @Deprecated
   2110     @SystemApi
   2111     @SuppressLint("Doclava125")
   2112     public void removeGpsNavigationMessageListener(GpsNavigationMessageEvent.Listener listener) {
   2113     }
   2114 
   2115     /**
   2116      * Registers a GNSS Navigation Message callback.
   2117      *
   2118      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
   2119      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
   2120      */
   2121     public boolean registerGnssNavigationMessageCallback(
   2122             GnssNavigationMessage.Callback callback) {
   2123         return registerGnssNavigationMessageCallback(callback, null);
   2124     }
   2125 
   2126     /**
   2127      * Registers a GNSS Navigation Message callback.
   2128      *
   2129      * @param callback a {@link GnssNavigationMessage.Callback} object to register.
   2130      * @param handler the handler that the callback runs on.
   2131      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
   2132      */
   2133     @RequiresPermission(ACCESS_FINE_LOCATION)
   2134     public boolean registerGnssNavigationMessageCallback(
   2135             GnssNavigationMessage.Callback callback, Handler handler) {
   2136         return mGnssNavigationMessageCallbackTransport.add(callback, handler);
   2137     }
   2138 
   2139     /**
   2140      * Unregisters a GNSS Navigation Message callback.
   2141      *
   2142      * @param callback a {@link GnssNavigationMessage.Callback} object to remove.
   2143      */
   2144     public void unregisterGnssNavigationMessageCallback(
   2145             GnssNavigationMessage.Callback callback) {
   2146         mGnssNavigationMessageCallbackTransport.remove(callback);
   2147     }
   2148 
   2149     /**
   2150      * Retrieves information about the current status of the GPS engine.
   2151      * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
   2152      * callback to ensure that the data is copied atomically.
   2153      *
   2154      * The caller may either pass in a {@link GpsStatus} object to set with the latest
   2155      * status information, or pass null to create a new {@link GpsStatus} object.
   2156      *
   2157      * @param status object containing GPS status details, or null.
   2158      * @return status object containing updated GPS status.
   2159      */
   2160     @Deprecated
   2161     @RequiresPermission(ACCESS_FINE_LOCATION)
   2162     public GpsStatus getGpsStatus(GpsStatus status) {
   2163         if (status == null) {
   2164             status = new GpsStatus();
   2165         }
   2166         // When mGnssStatus is null, that means that this method is called outside
   2167         // onGpsStatusChanged().  Return an empty status to maintain backwards compatibility.
   2168         if (mGnssStatus != null) {
   2169             status.setStatus(mGnssStatus, mTimeToFirstFix);
   2170         }
   2171         return status;
   2172     }
   2173 
   2174     /**
   2175      * Returns the model year of the GNSS hardware and software build.
   2176      *
   2177      * <p> More details, such as build date, may be available in {@link #getGnssHardwareModelName()}.
   2178      *
   2179      * <p> May return 0 if the model year is less than 2016.
   2180      */
   2181     public int getGnssYearOfHardware() {
   2182         try {
   2183             return mService.getGnssYearOfHardware();
   2184         } catch (RemoteException e) {
   2185             throw e.rethrowFromSystemServer();
   2186         }
   2187     }
   2188 
   2189     /**
   2190      * Returns the Model Name (including Vendor and Hardware/Software Version) of the GNSS hardware
   2191      * driver.
   2192      *
   2193      * <p> No device-specific serial number or ID is returned from this API.
   2194      *
   2195      * <p> Will return null when the GNSS hardware abstraction layer does not support providing
   2196      * this value.
   2197      */
   2198     @Nullable
   2199     public String getGnssHardwareModelName() {
   2200         try {
   2201             return mService.getGnssHardwareModelName();
   2202         } catch (RemoteException e) {
   2203             throw e.rethrowFromSystemServer();
   2204         }
   2205     }
   2206 
   2207     /**
   2208      * Returns the batch size (in number of Location objects) that are supported by the batching
   2209      * interface.
   2210      *
   2211      * @return Maximum number of location objects that can be returned
   2212      * @hide
   2213      */
   2214     @SystemApi
   2215     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
   2216     public int getGnssBatchSize() {
   2217         try {
   2218             return mService.getGnssBatchSize(mContext.getPackageName());
   2219         } catch (RemoteException e) {
   2220             throw e.rethrowFromSystemServer();
   2221         }
   2222     }
   2223 
   2224     /**
   2225      * Start hardware-batching of GNSS locations. This API is primarily used when the AP is
   2226      * asleep and the device can batch GNSS locations in the hardware.
   2227      *
   2228      * Note this is designed (as was the fused location interface before it) for a single user
   2229      * SystemApi - requests are not consolidated.  Care should be taken when the System switches
   2230      * users that may have different batching requests, to stop hardware batching for one user, and
   2231      * restart it for the next.
   2232      *
   2233      * @param periodNanos Time interval, in nanoseconds, that the GNSS locations are requested
   2234      *                    within the batch
   2235      * @param wakeOnFifoFull True if the hardware batching should flush the locations in a
   2236      *                       a callback to the listener, when it's internal buffer is full.  If
   2237      *                       set to false, the oldest location information is, instead,
   2238      *                       dropped when the buffer is full.
   2239      * @param callback The listener on which to return the batched locations
   2240      * @param handler The handler on which to process the callback
   2241      *
   2242      * @return True if batching was successfully started
   2243      * @hide
   2244      */
   2245     @SystemApi
   2246     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
   2247     public boolean registerGnssBatchedLocationCallback(long periodNanos, boolean wakeOnFifoFull,
   2248                                   BatchedLocationCallback callback, Handler handler) {
   2249         mBatchedLocationCallbackTransport.add(callback, handler);
   2250 
   2251         try {
   2252             return mService.startGnssBatch(periodNanos, wakeOnFifoFull, mContext.getPackageName());
   2253         } catch (RemoteException e) {
   2254             throw e.rethrowFromSystemServer();
   2255         }
   2256     }
   2257 
   2258     /**
   2259      * Flush the batched GNSS locations.
   2260      * All GNSS locations currently ready in the batch are returned via the callback sent in
   2261      * startGnssBatch(), and the buffer containing the batched locations is cleared.
   2262      *
   2263      * @hide
   2264      */
   2265     @SystemApi
   2266     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
   2267     public void flushGnssBatch() {
   2268         try {
   2269             mService.flushGnssBatch(mContext.getPackageName());
   2270         } catch (RemoteException e) {
   2271             throw e.rethrowFromSystemServer();
   2272         }
   2273     }
   2274 
   2275     /**
   2276      * Stop batching locations. This API is primarily used when the AP is
   2277      * asleep and the device can batch locations in the hardware.
   2278      *
   2279      * @param callback the specific callback class to remove from the transport layer
   2280      *
   2281      * @return True if batching was successfully started
   2282      * @hide
   2283      */
   2284     @SystemApi
   2285     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
   2286     public boolean unregisterGnssBatchedLocationCallback(BatchedLocationCallback callback) {
   2287 
   2288         mBatchedLocationCallbackTransport.remove(callback);
   2289 
   2290         try {
   2291             return mService.stopGnssBatch();
   2292         } catch (RemoteException e) {
   2293             throw e.rethrowFromSystemServer();
   2294         }
   2295     }
   2296 
   2297     /**
   2298      * Sends additional commands to a location provider.
   2299      * Can be used to support provider specific extensions to the Location Manager API
   2300      *
   2301      * @param provider name of the location provider.
   2302      * @param command name of the command to send to the provider.
   2303      * @param extras optional arguments for the command (or null).
   2304      * The provider may optionally fill the extras Bundle with results from the command.
   2305      *
   2306      * @return true if the command succeeds.
   2307      */
   2308     public boolean sendExtraCommand(String provider, String command, Bundle extras) {
   2309         try {
   2310             return mService.sendExtraCommand(provider, command, extras);
   2311         } catch (RemoteException e) {
   2312             throw e.rethrowFromSystemServer();
   2313         }
   2314     }
   2315 
   2316     /**
   2317      * Used by NetInitiatedActivity to report user response
   2318      * for network initiated GPS fix requests.
   2319      *
   2320      * @hide
   2321      */
   2322     public boolean sendNiResponse(int notifId, int userResponse) {
   2323         try {
   2324             return mService.sendNiResponse(notifId, userResponse);
   2325         } catch (RemoteException e) {
   2326             throw e.rethrowFromSystemServer();
   2327         }
   2328     }
   2329 
   2330     private static void checkProvider(String provider) {
   2331         if (provider == null) {
   2332             throw new IllegalArgumentException("invalid provider: " + provider);
   2333         }
   2334     }
   2335 
   2336     private static void checkCriteria(Criteria criteria) {
   2337         if (criteria == null) {
   2338             throw new IllegalArgumentException("invalid criteria: " + criteria);
   2339         }
   2340     }
   2341 
   2342     private static void checkListener(LocationListener listener) {
   2343         if (listener == null) {
   2344             throw new IllegalArgumentException("invalid listener: " + listener);
   2345         }
   2346     }
   2347 
   2348     private void checkPendingIntent(PendingIntent intent) {
   2349         if (intent == null) {
   2350             throw new IllegalArgumentException("invalid pending intent: " + intent);
   2351         }
   2352         if (!intent.isTargetedToPackage()) {
   2353             IllegalArgumentException e = new IllegalArgumentException(
   2354                     "pending intent must be targeted to package");
   2355             if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
   2356                 throw e;
   2357             } else {
   2358                 Log.w(TAG, e);
   2359             }
   2360         }
   2361     }
   2362 
   2363     private static void checkGeofence(Geofence fence) {
   2364         if (fence == null) {
   2365             throw new IllegalArgumentException("invalid geofence: " + fence);
   2366         }
   2367     }
   2368 }
   2369