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