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