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