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