LocationManager.java revision 9aa1fa2d3612d1d8ffeae6552d65669f4ca194d9
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 android.app.PendingIntent;
20import android.content.Intent;
21import android.os.Bundle;
22import android.os.Looper;
23import android.os.RemoteException;
24import android.os.Handler;
25import android.os.Message;
26import android.util.Config;
27import android.util.Log;
28
29import com.android.internal.location.DummyLocationProvider;
30
31import java.util.ArrayList;
32import java.util.Collections;
33import java.util.Comparator;
34import java.util.HashMap;
35import java.util.List;
36
37/**
38 * This class provides access to the system location services.  These
39 * services allow applications to obtain periodic updates of the
40 * device's geographical location, or to fire an application-specified
41 * {@link Intent} when the device enters the proximity of a given
42 * geographical location.
43 *
44 * <p>You do not
45 * instantiate this class directly; instead, retrieve it through
46 * {@link android.content.Context#getSystemService
47 * Context.getSystemService(Context.LOCATION_SERVICE)}.
48 */
49public class LocationManager {
50    private static final String TAG = "LocationManager";
51    private ILocationManager mService;
52    private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
53            new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
54    private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
55            new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
56    private final GpsStatus mGpsStatus = new GpsStatus();
57
58    /**
59     * Name of the network location provider.  This provider determines location based on
60     * availability of cell tower and WiFi access points. Results are retrieved
61     * by means of a network lookup.
62     *
63     * Requires either of the permissions android.permission.ACCESS_COARSE_LOCATION
64     * or android.permission.ACCESS_FINE_LOCATION.
65     */
66    public static final String NETWORK_PROVIDER = "network";
67
68    /**
69     * Name of the GPS location provider. This provider determines location using
70     * satellites. Depending on conditions, this provider may take a while to return
71     * a location fix.
72     *
73     * Requires the permission android.permission.ACCESS_FINE_LOCATION.
74     *
75     * <p> The extras Bundle for the GPS location provider can contain the
76     * following key/value pairs:
77     *
78     * <ul>
79     * <li> satellites - the number of satellites used to derive the fix
80     * </ul>
81     */
82    public static final String GPS_PROVIDER = "gps";
83
84    /**
85     * Key used for the Bundle extra holding a boolean indicating whether
86     * a proximity alert is entering (true) or exiting (false)..
87     */
88    public static final String KEY_PROXIMITY_ENTERING = "entering";
89
90    /**
91     * Key used for a Bundle extra holding an Integer status value
92     * when a status change is broadcast using a PendingIntent.
93     */
94    public static final String KEY_STATUS_CHANGED = "status";
95
96    /**
97     * Key used for a Bundle extra holding an Boolean status value
98     * when a provider enabled/disabled event is broadcast using a PendingIntent.
99     */
100    public static final String KEY_PROVIDER_ENABLED = "providerEnabled";
101
102    /**
103     * Key used for a Bundle extra holding a Location value
104     * when a location change is broadcast using a PendingIntent.
105     */
106    public static final String KEY_LOCATION_CHANGED = "location";
107
108    // Map from LocationListeners to their associated ListenerTransport objects
109    private HashMap<LocationListener,ListenerTransport> mListeners =
110        new HashMap<LocationListener,ListenerTransport>();
111
112    private class ListenerTransport extends ILocationListener.Stub {
113        private static final int TYPE_LOCATION_CHANGED = 1;
114        private static final int TYPE_STATUS_CHANGED = 2;
115        private static final int TYPE_PROVIDER_ENABLED = 3;
116        private static final int TYPE_PROVIDER_DISABLED = 4;
117
118        private LocationListener mListener;
119        private final Handler mListenerHandler;
120
121        ListenerTransport(LocationListener listener, Looper looper) {
122            mListener = listener;
123
124            if (looper == null) {
125                mListenerHandler = new Handler() {
126                    @Override
127                    public void handleMessage(Message msg) {
128                        _handleMessage(msg);
129                    }
130                };
131            } else {
132                mListenerHandler = new Handler(looper) {
133                    @Override
134                    public void handleMessage(Message msg) {
135                        _handleMessage(msg);
136                    }
137                };
138            }
139        }
140
141        public void onLocationChanged(Location location) {
142            Message msg = Message.obtain();
143            msg.what = TYPE_LOCATION_CHANGED;
144            msg.obj = location;
145            mListenerHandler.sendMessage(msg);
146        }
147
148        public void onStatusChanged(String provider, int status, Bundle extras) {
149            Message msg = Message.obtain();
150            msg.what = TYPE_STATUS_CHANGED;
151            Bundle b = new Bundle();
152            b.putString("provider", provider);
153            b.putInt("status", status);
154            if (extras != null) {
155                b.putBundle("extras", extras);
156            }
157            msg.obj = b;
158            mListenerHandler.sendMessage(msg);
159        }
160
161        public void onProviderEnabled(String provider) {
162            Message msg = Message.obtain();
163            msg.what = TYPE_PROVIDER_ENABLED;
164            msg.obj = provider;
165            mListenerHandler.sendMessage(msg);
166        }
167
168        public void onProviderDisabled(String provider) {
169            Message msg = Message.obtain();
170            msg.what = TYPE_PROVIDER_DISABLED;
171            msg.obj = provider;
172            mListenerHandler.sendMessage(msg);
173        }
174
175        private void _handleMessage(Message msg) {
176            switch (msg.what) {
177                case TYPE_LOCATION_CHANGED:
178                    Location location = new Location((Location) msg.obj);
179                    mListener.onLocationChanged(location);
180                    break;
181                case TYPE_STATUS_CHANGED:
182                    Bundle b = (Bundle) msg.obj;
183                    String provider = b.getString("provider");
184                    int status = b.getInt("status");
185                    Bundle extras = b.getBundle("extras");
186                    mListener.onStatusChanged(provider, status, extras);
187                    break;
188                case TYPE_PROVIDER_ENABLED:
189                    mListener.onProviderEnabled((String) msg.obj);
190                    break;
191                case TYPE_PROVIDER_DISABLED:
192                    mListener.onProviderDisabled((String) msg.obj);
193                    break;
194            }
195            try {
196                mService.locationCallbackFinished(this);
197            } catch (RemoteException e) {
198                Log.e(TAG, "locationCallbackFinished: RemoteException", e);
199            }
200        }
201    }
202    /**
203     * @hide - hide this constructor because it has a parameter
204     * of type ILocationManager, which is a system private class. The
205     * right way to create an instance of this class is using the
206     * factory Context.getSystemService.
207     */
208    public LocationManager(ILocationManager service) {
209        if (Config.LOGD) {
210            Log.d(TAG, "Constructor: service = " + service);
211        }
212        mService = service;
213    }
214
215    private LocationProvider createProvider(String name, Bundle info) {
216        DummyLocationProvider provider =
217            new DummyLocationProvider(name);
218        provider.setRequiresNetwork(info.getBoolean("network"));
219        provider.setRequiresSatellite(info.getBoolean("satellite"));
220        provider.setRequiresCell(info.getBoolean("cell"));
221        provider.setHasMonetaryCost(info.getBoolean("cost"));
222        provider.setSupportsAltitude(info.getBoolean("altitude"));
223        provider.setSupportsSpeed(info.getBoolean("speed"));
224        provider.setSupportsBearing(info.getBoolean("bearing"));
225        provider.setPowerRequirement(info.getInt("power"));
226        provider.setAccuracy(info.getInt("accuracy"));
227        return provider;
228    }
229
230    /**
231     * Returns a list of the names of all known location providers.  All
232     * providers are returned, including ones that are not permitted to be
233     * accessed by the calling activity or are currently disabled.
234     *
235     * @return list of Strings containing names of the providers
236     */
237    public List<String> getAllProviders() {
238        if (Config.LOGD) {
239            Log.d(TAG, "getAllProviders");
240        }
241        try {
242            return mService.getAllProviders();
243        } catch (RemoteException ex) {
244            Log.e(TAG, "getAllProviders: RemoteException", ex);
245        }
246        return null;
247    }
248
249    /**
250     * Returns a list of the names of location providers.  Only providers that
251     * are permitted to be accessed by the calling activity will be returned.
252     *
253     * @param enabledOnly if true then only the providers which are currently
254     * enabled are returned.
255     * @return list of Strings containing names of the providers
256     */
257    public List<String> getProviders(boolean enabledOnly) {
258        try {
259            return mService.getProviders(enabledOnly);
260        } catch (RemoteException ex) {
261            Log.e(TAG, "getProviders: RemoteException", ex);
262        }
263        return null;
264    }
265
266    /**
267     * Returns the information associated with the location provider of the
268     * given name, or null if no provider exists by that name.
269     *
270     * @param name the provider name
271     * @return a LocationProvider, or null
272     *
273     * @throws IllegalArgumentException if name is null
274     * @throws SecurityException if the caller is not permitted to access the
275     * given provider.
276     */
277    public LocationProvider getProvider(String name) {
278        if (name == null) {
279            throw new IllegalArgumentException("name==null");
280        }
281        try {
282            Bundle info = mService.getProviderInfo(name);
283            if (info == null) {
284                return null;
285            }
286            return createProvider(name, info);
287        } catch (RemoteException ex) {
288            Log.e(TAG, "getProvider: RemoteException", ex);
289        }
290        return null;
291    }
292
293    /**
294     * Returns a list of the names of LocationProviders that satisfy the given
295     * criteria, or null if none do.  Only providers that are permitted to be
296     * accessed by the calling activity will be returned.
297     *
298     * @param criteria the criteria that the returned providers must match
299     * @param enabledOnly if true then only the providers which are currently
300     * enabled are returned.
301     * @return list of Strings containing names of the providers
302     */
303    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
304        List<String> goodProviders = Collections.emptyList();
305        List<String> providers = getProviders(enabledOnly);
306        for (String providerName : providers) {
307            LocationProvider provider = getProvider(providerName);
308            if (provider.meetsCriteria(criteria)) {
309                if (goodProviders.isEmpty()) {
310                    goodProviders = new ArrayList<String>();
311                }
312                goodProviders.add(providerName);
313            }
314        }
315        return goodProviders;
316    }
317
318    /**
319     * Returns the next looser power requirement, in the sequence:
320     *
321     * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
322     */
323    private int nextPower(int power) {
324        switch (power) {
325        case Criteria.POWER_LOW:
326            return Criteria.POWER_MEDIUM;
327        case Criteria.POWER_MEDIUM:
328            return Criteria.POWER_HIGH;
329        case Criteria.POWER_HIGH:
330            return Criteria.NO_REQUIREMENT;
331        case Criteria.NO_REQUIREMENT:
332        default:
333            return Criteria.NO_REQUIREMENT;
334        }
335    }
336
337    /**
338     * Returns the next looser accuracy requirement, in the sequence:
339     *
340     * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
341     */
342    private int nextAccuracy(int accuracy) {
343        if (accuracy == Criteria.ACCURACY_FINE) {
344            return Criteria.ACCURACY_COARSE;
345        } else {
346            return Criteria.NO_REQUIREMENT;
347        }
348    }
349
350    private abstract class LpComparator implements Comparator<LocationProvider> {
351
352        public int compare(int a1, int a2) {
353            if (a1 < a2) {
354                return -1;
355            } else if (a1 > a2) {
356                return 1;
357            } else {
358                return 0;
359            }
360        }
361
362        public int compare(float a1, float a2) {
363            if (a1 < a2) {
364                return -1;
365            } else if (a1 > a2) {
366                return 1;
367            } else {
368                return 0;
369            }
370        }
371    }
372
373    private class LpPowerComparator extends LpComparator {
374        public int compare(LocationProvider l1, LocationProvider l2) {
375            int a1 = l1.getPowerRequirement();
376            int a2 = l2.getPowerRequirement();
377            return compare(a1, a2); // Smaller is better
378         }
379
380         public boolean equals(LocationProvider l1, LocationProvider l2) {
381             int a1 = l1.getPowerRequirement();
382             int a2 = l2.getPowerRequirement();
383             return a1 == a2;
384         }
385    }
386
387    private class LpAccuracyComparator extends LpComparator {
388        public int compare(LocationProvider l1, LocationProvider l2) {
389            int a1 = l1.getAccuracy();
390            int a2 = l2.getAccuracy();
391            return compare(a1, a2); // Smaller is better
392         }
393
394         public boolean equals(LocationProvider l1, LocationProvider l2) {
395             int a1 = l1.getAccuracy();
396             int a2 = l2.getAccuracy();
397             return a1 == a2;
398         }
399    }
400
401    private class LpCapabilityComparator extends LpComparator {
402
403        private static final int ALTITUDE_SCORE = 4;
404        private static final int BEARING_SCORE = 4;
405        private static final int SPEED_SCORE = 4;
406
407        private int score(LocationProvider p) {
408            return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
409                (p.supportsBearing() ? BEARING_SCORE : 0) +
410                (p.supportsSpeed() ? SPEED_SCORE : 0);
411        }
412
413        public int compare(LocationProvider l1, LocationProvider l2) {
414            int a1 = score(l1);
415            int a2 = score(l2);
416            return compare(-a1, -a2); // Bigger is better
417         }
418
419         public boolean equals(LocationProvider l1, LocationProvider l2) {
420             int a1 = score(l1);
421             int a2 = score(l2);
422             return a1 == a2;
423         }
424    }
425
426    private LocationProvider best(List<String> providerNames) {
427        List<LocationProvider> providers = new ArrayList<LocationProvider>(providerNames.size());
428        for (String name : providerNames) {
429            providers.add(getProvider(name));
430        }
431
432        if (providers.size() < 2) {
433            return providers.get(0);
434        }
435
436        // First, sort by power requirement
437        Collections.sort(providers, new LpPowerComparator());
438        int power = providers.get(0).getPowerRequirement();
439        if (power < providers.get(1).getPowerRequirement()) {
440            return providers.get(0);
441        }
442
443        int idx, size;
444
445        List<LocationProvider> tmp = new ArrayList<LocationProvider>();
446        idx = 0;
447        size = providers.size();
448        while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
449            tmp.add(providers.get(idx));
450            idx++;
451        }
452
453        // Next, sort by accuracy
454        Collections.sort(tmp, new LpAccuracyComparator());
455        int acc = tmp.get(0).getAccuracy();
456        if (acc < tmp.get(1).getAccuracy()) {
457            return tmp.get(0);
458        }
459
460        List<LocationProvider> tmp2 = new ArrayList<LocationProvider>();
461        idx = 0;
462        size = tmp.size();
463        while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
464            tmp2.add(tmp.get(idx));
465            idx++;
466        }
467
468        // Finally, sort by capability "score"
469        Collections.sort(tmp2, new LpCapabilityComparator());
470        return tmp2.get(0);
471    }
472
473    /**
474     * Returns the name of the provider that best meets the given criteria. Only providers
475     * that are permitted to be accessed by the calling activity will be
476     * returned.  If several providers meet the criteria, the one with the best
477     * accuracy is returned.  If no provider meets the criteria,
478     * the criteria are loosened in the following sequence:
479     *
480     * <ul>
481     * <li> power requirement
482     * <li> accuracy
483     * <li> bearing
484     * <li> speed
485     * <li> altitude
486     * </ul>
487     *
488     * <p> Note that the requirement on monetary cost is not removed
489     * in this process.
490     *
491     * @param criteria the criteria that need to be matched
492     * @param enabledOnly if true then only a provider that is currently enabled is returned
493     * @return name of the provider that best matches the requirements
494     */
495    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
496        List<String> goodProviders = getProviders(criteria, enabledOnly);
497        if (!goodProviders.isEmpty()) {
498            return best(goodProviders).getName();
499        }
500
501        // Make a copy of the criteria that we can modify
502        criteria = new Criteria(criteria);
503
504        // Loosen power requirement
505        int power = criteria.getPowerRequirement();
506        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
507            power = nextPower(power);
508            criteria.setPowerRequirement(power);
509            goodProviders = getProviders(criteria, enabledOnly);
510        }
511        if (!goodProviders.isEmpty()) {
512            return best(goodProviders).getName();
513        }
514
515//        // Loosen response time requirement
516//        int responseTime = criteria.getPreferredResponseTime();
517//        while (goodProviders.isEmpty() &&
518//            (responseTime != Criteria.NO_REQUIREMENT)) {
519//            responseTime += 1000;
520//            if (responseTime > 60000) {
521//                responseTime = Criteria.NO_REQUIREMENT;
522//            }
523//            criteria.setPreferredResponseTime(responseTime);
524//            goodProviders = getProviders(criteria);
525//        }
526//        if (!goodProviders.isEmpty()) {
527//            return best(goodProviders);
528//        }
529
530        // Loosen accuracy requirement
531        int accuracy = criteria.getAccuracy();
532        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
533            accuracy = nextAccuracy(accuracy);
534            criteria.setAccuracy(accuracy);
535            goodProviders = getProviders(criteria, enabledOnly);
536        }
537        if (!goodProviders.isEmpty()) {
538            return best(goodProviders).getName();
539        }
540
541        // Remove bearing requirement
542        criteria.setBearingRequired(false);
543        goodProviders = getProviders(criteria, enabledOnly);
544        if (!goodProviders.isEmpty()) {
545            return best(goodProviders).getName();
546        }
547
548        // Remove speed requirement
549        criteria.setSpeedRequired(false);
550        goodProviders = getProviders(criteria, enabledOnly);
551        if (!goodProviders.isEmpty()) {
552            return best(goodProviders).getName();
553        }
554
555        // Remove altitude requirement
556        criteria.setAltitudeRequired(false);
557        goodProviders = getProviders(criteria, enabledOnly);
558        if (!goodProviders.isEmpty()) {
559            return best(goodProviders).getName();
560        }
561
562        return null;
563    }
564
565    /**
566     * Registers the current activity to be notified periodically by
567     * the named provider.  Periodically, the supplied LocationListener will
568     * be called with the current Location or with status updates.
569     *
570     * <p> It may take a while to receive the most recent location. If
571     * an immediate location is required, applications may use the
572     * {@link #getLastKnownLocation(String)} method.
573     *
574     * <p> In case the provider is disabled by the user, updates will stop,
575     * and the {@link LocationListener#onProviderDisabled(String)}
576     * method will be called. As soon as the provider is enabled again,
577     * the {@link LocationListener#onProviderEnabled(String)} method will
578     * be called and location updates will start again.
579     *
580     * <p> The frequency of notification may be controlled using the
581     * minTime and minDistance parameters. If minTime is greater than 0,
582     * the LocationManager could potentially rest for minTime milliseconds
583     * between location updates to conserve power. If minDistance is greater than 0,
584     * a location will only be broadcasted if the device moves by minDistance meters.
585     * To obtain notifications as frequently as possible, set both parameters to 0.
586     *
587     * <p> Background services should be careful about setting a sufficiently high
588     * minTime so that the device doesn't consume too much power by keeping the
589     * GPS or wireless radios on all the time. In particular, values under 60000ms
590     * are not recommended.
591     *
592     * <p> The calling thread must be a {@link android.os.Looper} thread such as
593     * the main thread of the calling Activity.
594     *
595     * @param provider the name of the provider with which to register
596     * @param minTime the minimum time interval for notifications, in
597     * milliseconds. This field is only used as a hint to conserve power, and actual
598     * time between location updates may be greater or lesser than this value.
599     * @param minDistance the minimum distance interval for notifications,
600     * in meters
601     * @param listener a {#link LocationListener} whose
602     * {@link LocationListener#onLocationChanged} method will be called for
603     * each location update
604     *
605     * @throws IllegalArgumentException if provider is null or doesn't exist
606     * @throws IllegalArgumentException if listener is null
607     * @throws RuntimeException if the calling thread has no Looper
608     * @throws SecurityException if no suitable permission is present for the provider.
609     */
610    public void requestLocationUpdates(String provider,
611        long minTime, float minDistance, LocationListener listener) {
612        if (provider == null) {
613            throw new IllegalArgumentException("provider==null");
614        }
615        if (listener == null) {
616            throw new IllegalArgumentException("listener==null");
617        }
618        _requestLocationUpdates(provider, minTime, minDistance, listener, null);
619    }
620
621    /**
622     * Registers the current activity to be notified periodically by
623     * the named provider.  Periodically, the supplied LocationListener will
624     * be called with the current Location or with status updates.
625     *
626     * <p> It may take a while to receive the most recent location. If
627     * an immediate location is required, applications may use the
628     * {@link #getLastKnownLocation(String)} method.
629     *
630     * <p> In case the provider is disabled by the user, updates will stop,
631     * and the {@link LocationListener#onProviderDisabled(String)}
632     * method will be called. As soon as the provider is enabled again,
633     * the {@link LocationListener#onProviderEnabled(String)} method will
634     * be called and location updates will start again.
635     *
636     * <p> The frequency of notification may be controlled using the
637     * minTime and minDistance parameters. If minTime is greater than 0,
638     * the LocationManager could potentially rest for minTime milliseconds
639     * between location updates to conserve power. If minDistance is greater than 0,
640     * a location will only be broadcasted if the device moves by minDistance meters.
641     * To obtain notifications as frequently as possible, set both parameters to 0.
642     *
643     * <p> Background services should be careful about setting a sufficiently high
644     * minTime so that the device doesn't consume too much power by keeping the
645     * GPS or wireless radios on all the time. In particular, values under 60000ms
646     * are not recommended.
647     *
648     * <p> The supplied Looper is used to implement the callback mechanism.
649     *
650     * @param provider the name of the provider with which to register
651     * @param minTime the minimum time interval for notifications, in
652     * milliseconds. This field is only used as a hint to conserve power, and actual
653     * time between location updates may be greater or lesser than this value.
654     * @param minDistance the minimum distance interval for notifications,
655     * in meters
656     * @param listener a {#link LocationListener} whose
657     * {@link LocationListener#onLocationChanged} method will be called for
658     * each location update
659     * @param looper a Looper object whose message queue will be used to
660     * implement the callback mechanism.
661     *
662     * @throws IllegalArgumentException if provider is null or doesn't exist
663     * @throws IllegalArgumentException if listener is null
664     * @throws IllegalArgumentException if looper is null
665     * @throws SecurityException if no suitable permission is present for the provider.
666     */
667    public void requestLocationUpdates(String provider,
668        long minTime, float minDistance, LocationListener listener,
669        Looper looper) {
670        if (provider == null) {
671            throw new IllegalArgumentException("provider==null");
672        }
673        if (listener == null) {
674            throw new IllegalArgumentException("listener==null");
675        }
676        if (looper == null) {
677            throw new IllegalArgumentException("looper==null");
678        }
679        _requestLocationUpdates(provider, minTime, minDistance, listener, looper);
680    }
681
682    private void _requestLocationUpdates(String provider,
683        long minTime, float minDistance, LocationListener listener,
684        Looper looper) {
685        if (minTime < 0L) {
686            minTime = 0L;
687        }
688        if (minDistance < 0.0f) {
689            minDistance = 0.0f;
690        }
691
692        try {
693            synchronized (mListeners) {
694                ListenerTransport transport = mListeners.get(listener);
695                if (transport == null) {
696                    transport = new ListenerTransport(listener, looper);
697                }
698                mListeners.put(listener, transport);
699                mService.requestLocationUpdates(provider, minTime, minDistance, transport);
700            }
701        } catch (RemoteException ex) {
702            Log.e(TAG, "requestLocationUpdates: DeadObjectException", ex);
703        }
704    }
705
706    /**
707     * Registers the current activity to be notified periodically by
708     * the named provider.  Periodically, the supplied PendingIntent will
709     * be broadcast with the current Location or with status updates.
710     *
711     * <p> Location updates are sent with a key of KEY_LOCATION_CHANGED and a Location value.
712     *
713     * <p> It may take a while to receive the most recent location. If
714     * an immediate location is required, applications may use the
715     * {@link #getLastKnownLocation(String)} method.
716     *
717     * <p> The frequency of notification or new locations may be controlled using the
718     * minTime and minDistance parameters. If minTime is greater than 0,
719     * the LocationManager could potentially rest for minTime milliseconds
720     * between location updates to conserve power. If minDistance is greater than 0,
721     * a location will only be broadcast if the device moves by minDistance meters.
722     * To obtain notifications as frequently as possible, set both parameters to 0.
723     *
724     * <p> Background services should be careful about setting a sufficiently high
725     * minTime so that the device doesn't consume too much power by keeping the
726     * GPS or wireless radios on all the time. In particular, values under 60000ms
727     * are not recommended.
728     *
729     * <p> In case the provider is disabled by the user, updates will stop,
730     * and an intent will be sent with an extra with key KEY_PROVIDER_ENABLED and a boolean value
731     * of false.  If the provider is re-enabled, an intent will be sent with an
732     * extra with key KEY_PROVIDER_ENABLED and a boolean value of true and location updates will
733     * start again.
734     *
735     * <p> If the provider's status changes, an intent will be sent with an extra with key
736     * KEY_STATUS_CHANGED and an integer value indicating the new status.  Any extras associated
737     * with the status update will be sent as well.
738     *
739     * @param provider the name of the provider with which to register
740     * @param minTime the minimum time interval for notifications, in
741     * milliseconds. This field is only used as a hint to conserve power, and actual
742     * time between location updates may be greater or lesser than this value.
743     * @param minDistance the minimum distance interval for notifications,
744     * in meters
745     * @param intent a {#link PendingIntet} to be sent for each location update
746     *
747     * @throws IllegalArgumentException if provider is null or doesn't exist
748     * @throws IllegalArgumentException if intent is null
749     * @throws SecurityException if no suitable permission is present for the provider.
750     */
751    public void requestLocationUpdates(String provider,
752            long minTime, float minDistance, PendingIntent intent) {
753        if (provider == null) {
754            throw new IllegalArgumentException("provider==null");
755        }
756        if (intent == null) {
757            throw new IllegalArgumentException("intent==null");
758        }
759        _requestLocationUpdates(provider, minTime, minDistance, intent);
760    }
761
762    private void _requestLocationUpdates(String provider,
763            long minTime, float minDistance, PendingIntent intent) {
764        if (minTime < 0L) {
765            minTime = 0L;
766        }
767        if (minDistance < 0.0f) {
768            minDistance = 0.0f;
769        }
770
771        try {
772            mService.requestLocationUpdatesPI(provider, minTime, minDistance, intent);
773        } catch (RemoteException ex) {
774            Log.e(TAG, "requestLocationUpdates: RemoteException", ex);
775        }
776    }
777
778    /**
779     * Removes any current registration for location updates of the current activity
780     * with the given LocationListener.  Following this call, updates will no longer
781     * occur for this listener.
782     *
783     * @param listener {#link LocationListener} object that no longer needs location updates
784     * @throws IllegalArgumentException if listener is null
785     */
786    public void removeUpdates(LocationListener listener) {
787        if (listener == null) {
788            throw new IllegalArgumentException("listener==null");
789        }
790        if (Config.LOGD) {
791            Log.d(TAG, "removeUpdates: listener = " + listener);
792        }
793        try {
794            ListenerTransport transport = mListeners.remove(listener);
795            if (transport != null) {
796                mService.removeUpdates(transport);
797            }
798        } catch (RemoteException ex) {
799            Log.e(TAG, "removeUpdates: DeadObjectException", ex);
800        }
801    }
802
803    /**
804     * Removes any current registration for location updates of the current activity
805     * with the given PendingIntent.  Following this call, updates will no longer
806     * occur for this intent.
807     *
808     * @param intent {#link PendingIntent} object that no longer needs location updates
809     * @throws IllegalArgumentException if intent is null
810     */
811    public void removeUpdates(PendingIntent intent) {
812        if (intent == null) {
813            throw new IllegalArgumentException("intent==null");
814        }
815        if (Config.LOGD) {
816            Log.d(TAG, "removeUpdates: intent = " + intent);
817        }
818        try {
819            mService.removeUpdatesPI(intent);
820        } catch (RemoteException ex) {
821            Log.e(TAG, "removeUpdates: RemoteException", ex);
822        }
823    }
824
825    /**
826     * Sets a proximity alert for the location given by the position
827     * (latitude, longitude) and the given radius.  When the device
828     * detects that it has entered or exited the area surrounding the
829     * location, the given PendingIntent will be used to create an Intent
830     * to be fired.
831     *
832     * <p> The fired Intent will have a boolean extra added with key
833     * {@link #KEY_PROXIMITY_ENTERING}. If the value is true, the device is
834     * entering the proximity region; if false, it is exiting.
835     *
836     * <p> Due to the approximate nature of position estimation, if the
837     * device passes through the given area briefly, it is possible
838     * that no Intent will be fired.  Similarly, an Intent could be
839     * fired if the device passes very close to the given area but
840     * does not actually enter it.
841     *
842     * <p> After the number of milliseconds given by the expiration
843     * parameter, the location manager will delete this proximity
844     * alert and no longer monitor it.  A value of -1 indicates that
845     * there should be no expiration time.
846     *
847     * <p> In case the screen goes to sleep, checks for proximity alerts
848     * happen only once every 4 minutes. This conserves battery life by
849     * ensuring that the device isn't perpetually awake.
850     *
851     * <p> Internally, this method uses both {@link #NETWORK_PROVIDER}
852     * and {@link #GPS_PROVIDER}.
853     *
854     * @param latitude the latitude of the central point of the
855     * alert region
856     * @param longitude the longitude of the central point of the
857     * alert region
858     * @param radius the radius of the central point of the
859     * alert region, in meters
860     * @param expiration time for this proximity alert, in milliseconds,
861     * or -1 to indicate no expiration
862     * @param intent a PendingIntent that will be used to generate an Intent to
863     * fire when entry to or exit from the alert region is detected
864     *
865     * @throws SecurityException if no permission exists for the required
866     * providers.
867     */
868    public void addProximityAlert(double latitude, double longitude,
869        float radius, long expiration, PendingIntent intent) {
870        if (Config.LOGD) {
871            Log.d(TAG, "addProximityAlert: latitude = " + latitude +
872                ", longitude = " + longitude + ", radius = " + radius +
873                ", expiration = " + expiration +
874                ", intent = " + intent);
875        }
876        try {
877            mService.addProximityAlert(latitude, longitude, radius,
878                                       expiration, intent);
879        } catch (RemoteException ex) {
880            Log.e(TAG, "addProximityAlert: RemoteException", ex);
881        }
882    }
883
884    /**
885     * Removes the proximity alert with the given PendingIntent.
886     *
887     * @param intent the PendingIntent that no longer needs to be notified of
888     * proximity alerts
889     */
890    public void removeProximityAlert(PendingIntent intent) {
891        if (Config.LOGD) {
892            Log.d(TAG, "removeProximityAlert: intent = " + intent);
893        }
894        try {
895            mService.removeProximityAlert(intent);
896        } catch (RemoteException ex) {
897            Log.e(TAG, "removeProximityAlert: RemoteException", ex);
898        }
899    }
900
901    /**
902     * Returns the current enabled/disabled status of the given provider. If the
903     * user has enabled this provider in the Settings menu, true is returned
904     * otherwise false is returned
905     *
906     * @param provider the name of the provider
907     * @return true if the provider is enabled
908     *
909     * @throws SecurityException if no suitable permission is present for the provider.
910     * @throws IllegalArgumentException if provider is null or doesn't exist
911     */
912    public boolean isProviderEnabled(String provider) {
913        if (provider == null) {
914            throw new IllegalArgumentException("provider==null");
915        }
916        try {
917            return mService.isProviderEnabled(provider);
918        } catch (RemoteException ex) {
919            Log.e(TAG, "isProviderEnabled: RemoteException", ex);
920            return false;
921        }
922    }
923
924    /**
925     * Returns a Location indicating the data from the last known
926     * location fix obtained from the given provider.  This can be done
927     * without starting the provider.  Note that this location could
928     * be out-of-date, for example if the device was turned off and
929     * moved to another location.
930     *
931     * <p> If the provider is currently disabled, null is returned.
932     *
933     * @param provider the name of the provider
934     * @return the last known location for the provider, or null
935     *
936     * @throws SecurityException if no suitable permission is present for the provider.
937     * @throws IllegalArgumentException if provider is null or doesn't exist
938     */
939    public Location getLastKnownLocation(String provider) {
940        if (provider == null) {
941            throw new IllegalArgumentException("provider==null");
942        }
943        try {
944            return mService.getLastKnownLocation(provider);
945        } catch (RemoteException ex) {
946            Log.e(TAG, "getLastKnowLocation: RemoteException", ex);
947            return null;
948        }
949    }
950
951    // Mock provider support
952
953    /**
954     * Creates a mock location provider and adds it to the set of active providers.
955     *
956     * @param name the provider name
957     * @param requiresNetwork
958     * @param requiresSatellite
959     * @param requiresCell
960     * @param hasMonetaryCost
961     * @param supportsAltitude
962     * @param supportsSpeed
963     * @param supportsBearing
964     * @param powerRequirement
965     * @param accuracy
966     *
967     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
968     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
969     * Settings.Secure.ALLOW_MOCK_LOCATION} system setting is not enabled
970     * @throws IllegalArgumentException if a provider with the given name already exists
971     */
972    public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
973        boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
974        boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
975        try {
976            mService.addTestProvider(name, requiresNetwork, requiresSatellite, requiresCell,
977                hasMonetaryCost, supportsAltitude, supportsSpeed, supportsBearing, powerRequirement,
978                accuracy);
979        } catch (RemoteException ex) {
980            Log.e(TAG, "addTestProvider: RemoteException", ex);
981        }
982    }
983
984    /**
985     * Removes the mock location provider with the given name.
986     *
987     * @param provider the provider name
988     *
989     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
990     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
991     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
992     * @throws IllegalArgumentException if no provider with the given name exists
993     */
994    public void removeTestProvider(String provider) {
995        try {
996            mService.removeTestProvider(provider);
997        } catch (RemoteException ex) {
998            Log.e(TAG, "removeTestProvider: RemoteException", ex);
999        }
1000    }
1001
1002    /**
1003     * Sets a mock location for the given provider.  This location will be used in place
1004     * of any actual location from the provider.
1005     *
1006     * @param provider the provider name
1007     * @param loc the mock location
1008     *
1009     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1010     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1011     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1012     * @throws IllegalArgumentException if no provider with the given name exists
1013     */
1014    public void setTestProviderLocation(String provider, Location loc) {
1015        try {
1016            mService.setTestProviderLocation(provider, loc);
1017        } catch (RemoteException ex) {
1018            Log.e(TAG, "setTestProviderLocation: RemoteException", ex);
1019        }
1020    }
1021
1022    /**
1023     * Removes any mock location associated with the given provider.
1024     *
1025     * @param provider the provider name
1026     *
1027     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1028     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1029     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1030     * @throws IllegalArgumentException if no provider with the given name exists
1031     */
1032    public void clearTestProviderLocation(String provider) {
1033        try {
1034            mService.clearTestProviderLocation(provider);
1035        } catch (RemoteException ex) {
1036            Log.e(TAG, "clearTestProviderLocation: RemoteException", ex);
1037        }
1038    }
1039
1040    /**
1041     * Sets a mock enabled value for the given provider.  This value will be used in place
1042     * of any actual value from the provider.
1043     *
1044     * @param provider the provider name
1045     * @param enabled the mock enabled value
1046     *
1047     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1048     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1049     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1050     * @throws IllegalArgumentException if no provider with the given name exists
1051     */
1052    public void setTestProviderEnabled(String provider, boolean enabled) {
1053        try {
1054            mService.setTestProviderEnabled(provider, enabled);
1055        } catch (RemoteException ex) {
1056            Log.e(TAG, "setTestProviderEnabled: RemoteException", ex);
1057        }
1058    }
1059
1060    /**
1061     * Removes any mock enabled value associated with the given provider.
1062     *
1063     * @param provider the provider name
1064     *
1065     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1066     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1067     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1068     * @throws IllegalArgumentException if no provider with the given name exists
1069     */
1070    public void clearTestProviderEnabled(String provider) {
1071        try {
1072            mService.clearTestProviderEnabled(provider);
1073        } catch (RemoteException ex) {
1074            Log.e(TAG, "clearTestProviderEnabled: RemoteException", ex);
1075        }
1076
1077    }
1078
1079    /**
1080     * Sets mock status values for the given provider.  These values will be used in place
1081     * of any actual values from the provider.
1082     *
1083     * @param provider the provider name
1084     * @param status the mock status
1085     * @param extras a Bundle containing mock extras
1086     * @param updateTime the mock update time
1087     *
1088     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1089     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1090     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1091     * @throws IllegalArgumentException if no provider with the given name exists
1092     */
1093    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1094        try {
1095            mService.setTestProviderStatus(provider, status, extras, updateTime);
1096        } catch (RemoteException ex) {
1097            Log.e(TAG, "setTestProviderStatus: RemoteException", ex);
1098        }
1099    }
1100
1101    /**
1102     * Removes any mock status values associated with the given provider.
1103     *
1104     * @param provider the provider name
1105     *
1106     * @throws SecurityException if the ACCESS_MOCK_LOCATION permission is not present
1107     * or the {@link android.provider.Settings.Secure#ALLOW_MOCK_LOCATION
1108     * Settings.Secure.ALLOW_MOCK_LOCATION}} system setting is not enabled
1109     * @throws IllegalArgumentException if no provider with the given name exists
1110     */
1111    public void clearTestProviderStatus(String provider) {
1112        try {
1113            mService.clearTestProviderStatus(provider);
1114        } catch (RemoteException ex) {
1115            Log.e(TAG, "clearTestProviderStatus: RemoteException", ex);
1116        }
1117    }
1118
1119    // GPS-specific support
1120
1121    // This class is used to send GPS status events to the client's main thread.
1122    private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
1123
1124        private final GpsStatus.Listener mListener;
1125        private final GpsStatus.NmeaListener mNmeaListener;
1126
1127        // This must not equal any of the GpsStatus event IDs
1128        private static final int NMEA_RECEIVED = 1000;
1129
1130        private class Nmea {
1131            long mTimestamp;
1132            String mNmea;
1133
1134            Nmea(long timestamp, String nmea) {
1135                mTimestamp = timestamp;
1136                mNmea = nmea;
1137            }
1138        }
1139        private ArrayList<Nmea> mNmeaBuffer;
1140
1141        GpsStatusListenerTransport(GpsStatus.Listener listener) {
1142            mListener = listener;
1143            mNmeaListener = null;
1144        }
1145
1146        GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
1147            mNmeaListener = listener;
1148            mListener = null;
1149            mNmeaBuffer = new ArrayList<Nmea>();
1150        }
1151
1152        public void onGpsStarted() {
1153            if (mListener != null) {
1154                Message msg = Message.obtain();
1155                msg.what = GpsStatus.GPS_EVENT_STARTED;
1156                mGpsHandler.sendMessage(msg);
1157            }
1158        }
1159
1160        public void onGpsStopped() {
1161            if (mListener != null) {
1162                Message msg = Message.obtain();
1163                msg.what = GpsStatus.GPS_EVENT_STOPPED;
1164                mGpsHandler.sendMessage(msg);
1165            }
1166        }
1167
1168        public void onFirstFix(int ttff) {
1169            if (mListener != null) {
1170                mGpsStatus.setTimeToFirstFix(ttff);
1171                Message msg = Message.obtain();
1172                msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
1173                mGpsHandler.sendMessage(msg);
1174            }
1175        }
1176
1177        public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
1178                float[] elevations, float[] azimuths, int ephemerisMask,
1179                int almanacMask, int usedInFixMask) {
1180            if (mListener != null) {
1181                mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
1182                        ephemerisMask, almanacMask, usedInFixMask);
1183
1184                Message msg = Message.obtain();
1185                msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
1186                // remove any SV status messages already in the queue
1187                mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
1188                mGpsHandler.sendMessage(msg);
1189            }
1190        }
1191
1192        public void onNmeaReceived(long timestamp, String nmea) {
1193            if (mNmeaListener != null) {
1194                synchronized (mNmeaBuffer) {
1195                    mNmeaBuffer.add(new Nmea(timestamp, nmea));
1196                }
1197                Message msg = Message.obtain();
1198                msg.what = NMEA_RECEIVED;
1199                // remove any NMEA_RECEIVED messages already in the queue
1200                mGpsHandler.removeMessages(NMEA_RECEIVED);
1201                mGpsHandler.sendMessage(msg);
1202            }
1203        }
1204
1205        private final Handler mGpsHandler = new Handler() {
1206            @Override
1207            public void handleMessage(Message msg) {
1208                if (msg.what == NMEA_RECEIVED) {
1209                    synchronized (mNmeaBuffer) {
1210                        int length = mNmeaBuffer.size();
1211                        for (int i = 0; i < length; i++) {
1212                            Nmea nmea = mNmeaBuffer.get(i);
1213                            mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
1214                        }
1215                        mNmeaBuffer.clear();
1216                    }
1217                } else {
1218                    // synchronize on mGpsStatus to ensure the data is copied atomically.
1219                    synchronized(mGpsStatus) {
1220                        mListener.onGpsStatusChanged(msg.what);
1221                    }
1222                }
1223            }
1224        };
1225    }
1226
1227    /**
1228     * Adds a GPS status listener.
1229     *
1230     * @param listener GPS status listener object to register
1231     *
1232     * @return true if the listener was successfully added
1233     *
1234     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1235     */
1236    public boolean addGpsStatusListener(GpsStatus.Listener listener) {
1237        boolean result;
1238
1239        if (mGpsStatusListeners.get(listener) != null) {
1240            // listener is already registered
1241            return true;
1242        }
1243        try {
1244            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1245            result = mService.addGpsStatusListener(transport);
1246            if (result) {
1247                mGpsStatusListeners.put(listener, transport);
1248            }
1249        } catch (RemoteException e) {
1250            Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1251            result = false;
1252        }
1253
1254        return result;
1255    }
1256
1257    /**
1258     * Removes a GPS status listener.
1259     *
1260     * @param listener GPS status listener object to remove
1261     */
1262    public void removeGpsStatusListener(GpsStatus.Listener listener) {
1263        try {
1264            GpsStatusListenerTransport transport = mGpsStatusListeners.remove(listener);
1265            if (transport != null) {
1266                mService.removeGpsStatusListener(transport);
1267            }
1268        } catch (RemoteException e) {
1269            Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
1270        }
1271    }
1272
1273    /**
1274     * Adds an NMEA listener.
1275     *
1276     * @param listener a {#link GpsStatus.NmeaListener} object to register
1277     *
1278     * @return true if the listener was successfully added
1279     *
1280     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
1281     */
1282    public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
1283        boolean result;
1284
1285        if (mNmeaListeners.get(listener) != null) {
1286            // listener is already registered
1287            return true;
1288        }
1289        try {
1290            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
1291            result = mService.addGpsStatusListener(transport);
1292            if (result) {
1293                mNmeaListeners.put(listener, transport);
1294            }
1295        } catch (RemoteException e) {
1296            Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
1297            result = false;
1298        }
1299
1300        return result;
1301    }
1302
1303    /**
1304     * Removes an NMEA listener.
1305     *
1306     * @param listener a {#link GpsStatus.NmeaListener} object to remove
1307     */
1308    public void removeNmeaListener(GpsStatus.NmeaListener listener) {
1309        try {
1310            GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
1311            if (transport != null) {
1312                mService.removeGpsStatusListener(transport);
1313            }
1314        } catch (RemoteException e) {
1315            Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
1316        }
1317    }
1318
1319     /**
1320     * Retrieves information about the current status of the GPS engine.
1321     * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
1322     * callback to ensure that the data is copied atomically.
1323     *
1324     * The caller may either pass in a {@link GpsStatus} object to set with the latest
1325     * status information, or pass null to create a new {@link GpsStatus} object.
1326     *
1327     * @param status object containing GPS status details, or null.
1328     * @return status object containing updated GPS status.
1329     */
1330    public GpsStatus getGpsStatus(GpsStatus status) {
1331        if (status == null) {
1332            status = new GpsStatus();
1333       }
1334       status.setStatus(mGpsStatus);
1335       return status;
1336    }
1337
1338    /**
1339     * Sends additional commands to a location provider.
1340     * Can be used to support provider specific extensions to the Location Manager API
1341     *
1342     * @param provider name of the location provider.
1343     * @param command name of the command to send to the provider.
1344     * @param extras optional arguments for the command (or null).
1345     * The provider may optionally fill the extras Bundle with results from the command.
1346     *
1347     * @return true if the command succeeds.
1348     */
1349    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1350        try {
1351            return mService.sendExtraCommand(provider, command, extras);
1352        } catch (RemoteException e) {
1353            Log.e(TAG, "RemoteException in sendExtraCommand: ", e);
1354            return false;
1355        }
1356    }
1357
1358    /**
1359     * Installs a location provider.
1360     *
1361     * @param name of the location provider
1362     * @param provider Binder interface for the location provider
1363     *
1364     * @return true if the command succeeds.
1365     *
1366     * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
1367     *
1368     * {@hide}
1369     */
1370    public boolean installLocationProvider(String name, ILocationProvider provider) {
1371        try {
1372            mService.installLocationProvider(name, provider);
1373            return true;
1374        } catch (RemoteException e) {
1375            Log.e(TAG, "RemoteException in installLocationProvider: ", e);
1376            return false;
1377        }
1378    }
1379
1380    /**
1381     * Installs a geocoder server.
1382     *
1383     * @param provider Binder interface for the geocoder provider
1384     *
1385     * @return true if the command succeeds.
1386     *
1387     * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
1388     *
1389     * {@hide}
1390     */
1391    public boolean installGeocodeProvider(IGeocodeProvider provider) {
1392        try {
1393            mService.installGeocodeProvider(provider);
1394            return true;
1395        } catch (RemoteException e) {
1396            Log.e(TAG, "RemoteException in setGeocodeProvider: ", e);
1397            return false;
1398        }
1399    }
1400
1401    /**
1402     * Used by location providers to report new locations.
1403     *
1404     * @param location new Location to report
1405     *
1406     * Requires the android.permission.INSTALL_LOCATION_PROVIDER permission.
1407     *
1408     * {@hide}
1409     */
1410    public void reportLocation(Location location) {
1411        try {
1412            mService.reportLocation(location);
1413        } catch (RemoteException e) {
1414            Log.e(TAG, "RemoteException in reportLocation: ", e);
1415        }
1416    }
1417
1418    /**
1419     * Used by NetInitiatedActivity to report user response
1420     * for network initiated GPS fix requests.
1421     *
1422     * {@hide}
1423     */
1424    public boolean sendNiResponse(int notifId, int userResponse) {
1425    	try {
1426            return mService.sendNiResponse(notifId, userResponse);
1427        } catch (RemoteException e) {
1428            Log.e(TAG, "RemoteException in sendNiResponse: ", e);
1429            return false;
1430        }
1431    }
1432
1433}
1434