LocationManagerService.java revision 01ac80b715881db22bde8b31633dd8a4dc375389
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 com.android.server;
18
19import android.app.Activity;
20import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
22import android.content.ComponentName;
23import android.content.ContentQueryMap;
24import android.content.ContentResolver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.ServiceConnection;
29import android.content.pm.PackageManager;
30import android.content.res.Resources;
31import android.database.Cursor;
32import android.location.Address;
33import android.location.Criteria;
34import android.location.GeocoderParams;
35import android.location.IGpsStatusListener;
36import android.location.IGpsStatusProvider;
37import android.location.ILocationListener;
38import android.location.ILocationManager;
39import android.location.INetInitiatedListener;
40import android.location.Location;
41import android.location.LocationManager;
42import android.location.LocationProvider;
43import android.net.ConnectivityManager;
44import android.net.NetworkInfo;
45import android.net.Uri;
46import android.os.Binder;
47import android.os.Bundle;
48import android.os.Handler;
49import android.os.IBinder;
50import android.os.Looper;
51import android.os.Message;
52import android.os.PowerManager;
53import android.os.Process;
54import android.os.RemoteException;
55import android.provider.Settings;
56import android.util.Log;
57import android.util.Slog;
58import android.util.PrintWriterPrinter;
59
60import com.android.internal.location.GpsNetInitiatedHandler;
61
62import com.android.server.location.GeocoderProxy;
63import com.android.server.location.GpsLocationProvider;
64import com.android.server.location.LocationProviderInterface;
65import com.android.server.location.LocationProviderProxy;
66import com.android.server.location.MockProvider;
67import com.android.server.location.PassiveProvider;
68
69import java.io.FileDescriptor;
70import java.io.PrintWriter;
71import java.util.ArrayList;
72import java.util.Collections;
73import java.util.Comparator;
74import java.util.HashMap;
75import java.util.HashSet;
76import java.util.List;
77import java.util.Map;
78import java.util.Observable;
79import java.util.Observer;
80import java.util.Set;
81
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
85 *
86 * {@hide}
87 */
88public class LocationManagerService extends ILocationManager.Stub implements Runnable {
89    private static final String TAG = "LocationManagerService";
90    private static final boolean LOCAL_LOGV = false;
91
92    // The last time a location was written, by provider name.
93    private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
94
95    private static final String ACCESS_FINE_LOCATION =
96        android.Manifest.permission.ACCESS_FINE_LOCATION;
97    private static final String ACCESS_COARSE_LOCATION =
98        android.Manifest.permission.ACCESS_COARSE_LOCATION;
99    private static final String ACCESS_MOCK_LOCATION =
100        android.Manifest.permission.ACCESS_MOCK_LOCATION;
101    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
102        android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
103    private static final String INSTALL_LOCATION_PROVIDER =
104        android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
105
106    // Set of providers that are explicitly enabled
107    private final Set<String> mEnabledProviders = new HashSet<String>();
108
109    // Set of providers that are explicitly disabled
110    private final Set<String> mDisabledProviders = new HashSet<String>();
111
112    // Locations, status values, and extras for mock providers
113    private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
114
115    private static boolean sProvidersLoaded = false;
116
117    private final Context mContext;
118    private GeocoderProxy mGeocodeProvider;
119    private IGpsStatusProvider mGpsStatusProvider;
120    private INetInitiatedListener mNetInitiatedListener;
121    private LocationWorkerHandler mLocationHandler;
122
123    // Cache the real providers for use in addTestProvider() and removeTestProvider()
124     LocationProviderInterface mNetworkLocationProvider;
125     LocationProviderInterface mGpsLocationProvider;
126
127    // Handler messages
128    private static final int MESSAGE_LOCATION_CHANGED = 1;
129
130    // wakelock variables
131    private final static String WAKELOCK_KEY = "LocationManagerService";
132    private PowerManager.WakeLock mWakeLock = null;
133    private int mPendingBroadcasts;
134
135    /**
136     * List of all receivers.
137     */
138    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
139
140
141    /**
142     * List of location providers.
143     */
144    private final ArrayList<LocationProviderInterface> mProviders =
145        new ArrayList<LocationProviderInterface>();
146    private final HashMap<String, LocationProviderInterface> mProvidersByName
147        = new HashMap<String, LocationProviderInterface>();
148
149    /**
150     * Object used internally for synchronization
151     */
152    private final Object mLock = new Object();
153
154    /**
155     * Mapping from provider name to all its UpdateRecords
156     */
157    private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
158        new HashMap<String,ArrayList<UpdateRecord>>();
159
160    // Proximity listeners
161    private Receiver mProximityReceiver = null;
162    private ILocationListener mProximityListener = null;
163    private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
164        new HashMap<PendingIntent,ProximityAlert>();
165    private HashSet<ProximityAlert> mProximitiesEntered =
166        new HashSet<ProximityAlert>();
167
168    // Last known location for each provider
169    private HashMap<String,Location> mLastKnownLocation =
170        new HashMap<String,Location>();
171
172    private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
173
174    // for Settings change notification
175    private ContentQueryMap mSettings;
176
177    /**
178     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
179     * location updates.
180     */
181    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
182        final ILocationListener mListener;
183        final PendingIntent mPendingIntent;
184        final Object mKey;
185        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
186        int mPendingBroadcasts;
187
188        Receiver(ILocationListener listener) {
189            mListener = listener;
190            mPendingIntent = null;
191            mKey = listener.asBinder();
192        }
193
194        Receiver(PendingIntent intent) {
195            mPendingIntent = intent;
196            mListener = null;
197            mKey = intent;
198        }
199
200        @Override
201        public boolean equals(Object otherObj) {
202            if (otherObj instanceof Receiver) {
203                return mKey.equals(
204                        ((Receiver)otherObj).mKey);
205            }
206            return false;
207        }
208
209        @Override
210        public int hashCode() {
211            return mKey.hashCode();
212        }
213
214        @Override
215        public String toString() {
216            if (mListener != null) {
217                return "Receiver{"
218                        + Integer.toHexString(System.identityHashCode(this))
219                        + " Listener " + mKey + "}";
220            } else {
221                return "Receiver{"
222                        + Integer.toHexString(System.identityHashCode(this))
223                        + " Intent " + mKey + "}";
224            }
225        }
226
227        public boolean isListener() {
228            return mListener != null;
229        }
230
231        public boolean isPendingIntent() {
232            return mPendingIntent != null;
233        }
234
235        public ILocationListener getListener() {
236            if (mListener != null) {
237                return mListener;
238            }
239            throw new IllegalStateException("Request for non-existent listener");
240        }
241
242        public PendingIntent getPendingIntent() {
243            if (mPendingIntent != null) {
244                return mPendingIntent;
245            }
246            throw new IllegalStateException("Request for non-existent intent");
247        }
248
249        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
250            if (mListener != null) {
251                try {
252                    synchronized (this) {
253                        // synchronize to ensure incrementPendingBroadcastsLocked()
254                        // is called before decrementPendingBroadcasts()
255                        mListener.onStatusChanged(provider, status, extras);
256                        if (mListener != mProximityListener) {
257                            // call this after broadcasting so we do not increment
258                            // if we throw an exeption.
259                            incrementPendingBroadcastsLocked();
260                        }
261                    }
262                } catch (RemoteException e) {
263                    return false;
264                }
265            } else {
266                Intent statusChanged = new Intent();
267                statusChanged.putExtras(extras);
268                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
269                try {
270                    synchronized (this) {
271                        // synchronize to ensure incrementPendingBroadcastsLocked()
272                        // is called before decrementPendingBroadcasts()
273                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
274                        // call this after broadcasting so we do not increment
275                        // if we throw an exeption.
276                        incrementPendingBroadcastsLocked();
277                    }
278                } catch (PendingIntent.CanceledException e) {
279                    return false;
280                }
281            }
282            return true;
283        }
284
285        public boolean callLocationChangedLocked(Location location) {
286            if (mListener != null) {
287                try {
288                    synchronized (this) {
289                        // synchronize to ensure incrementPendingBroadcastsLocked()
290                        // is called before decrementPendingBroadcasts()
291                        mListener.onLocationChanged(location);
292                        if (mListener != mProximityListener) {
293                            // call this after broadcasting so we do not increment
294                            // if we throw an exeption.
295                            incrementPendingBroadcastsLocked();
296                        }
297                    }
298                } catch (RemoteException e) {
299                    return false;
300                }
301            } else {
302                Intent locationChanged = new Intent();
303                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
304                try {
305                    synchronized (this) {
306                        // synchronize to ensure incrementPendingBroadcastsLocked()
307                        // is called before decrementPendingBroadcasts()
308                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
309                        // call this after broadcasting so we do not increment
310                        // if we throw an exeption.
311                        incrementPendingBroadcastsLocked();
312                    }
313                } catch (PendingIntent.CanceledException e) {
314                    return false;
315                }
316            }
317            return true;
318        }
319
320        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
321            if (mListener != null) {
322                try {
323                    synchronized (this) {
324                        // synchronize to ensure incrementPendingBroadcastsLocked()
325                        // is called before decrementPendingBroadcasts()
326                        if (enabled) {
327                            mListener.onProviderEnabled(provider);
328                        } else {
329                            mListener.onProviderDisabled(provider);
330                        }
331                        if (mListener != mProximityListener) {
332                            // call this after broadcasting so we do not increment
333                            // if we throw an exeption.
334                            incrementPendingBroadcastsLocked();
335                        }
336                    }
337                } catch (RemoteException e) {
338                    return false;
339                }
340            } else {
341                Intent providerIntent = new Intent();
342                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
343                try {
344                    synchronized (this) {
345                        // synchronize to ensure incrementPendingBroadcastsLocked()
346                        // is called before decrementPendingBroadcasts()
347                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
348                        // call this after broadcasting so we do not increment
349                        // if we throw an exeption.
350                        incrementPendingBroadcastsLocked();
351                    }
352                } catch (PendingIntent.CanceledException e) {
353                    return false;
354                }
355            }
356            return true;
357        }
358
359        public void binderDied() {
360            if (LOCAL_LOGV) {
361                Slog.v(TAG, "Location listener died");
362            }
363            synchronized (mLock) {
364                removeUpdatesLocked(this);
365            }
366            synchronized (this) {
367                if (mPendingBroadcasts > 0) {
368                    LocationManagerService.this.decrementPendingBroadcasts();
369                    mPendingBroadcasts = 0;
370                }
371            }
372        }
373
374        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
375                int resultCode, String resultData, Bundle resultExtras) {
376            synchronized (this) {
377                decrementPendingBroadcastsLocked();
378            }
379        }
380
381        // this must be called while synchronized by caller in a synchronized block
382        // containing the sending of the broadcaset
383        private void incrementPendingBroadcastsLocked() {
384            if (mPendingBroadcasts++ == 0) {
385                LocationManagerService.this.incrementPendingBroadcasts();
386            }
387        }
388
389        private void decrementPendingBroadcastsLocked() {
390            if (--mPendingBroadcasts == 0) {
391                LocationManagerService.this.decrementPendingBroadcasts();
392            }
393        }
394    }
395
396    public void locationCallbackFinished(ILocationListener listener) {
397        //Do not use getReceiver here as that will add the ILocationListener to
398        //the receiver list if it is not found.  If it is not found then the
399        //LocationListener was removed when it had a pending broadcast and should
400        //not be added back.
401        IBinder binder = listener.asBinder();
402        Receiver receiver = mReceivers.get(binder);
403        if (receiver != null) {
404            synchronized (receiver) {
405                // so wakelock calls will succeed
406                long identity = Binder.clearCallingIdentity();
407                receiver.decrementPendingBroadcastsLocked();
408                Binder.restoreCallingIdentity(identity);
409           }
410        }
411    }
412
413    private final class SettingsObserver implements Observer {
414        public void update(Observable o, Object arg) {
415            synchronized (mLock) {
416                updateProvidersLocked();
417            }
418        }
419    }
420
421    private void addProvider(LocationProviderInterface provider) {
422        mProviders.add(provider);
423        mProvidersByName.put(provider.getName(), provider);
424    }
425
426    private void removeProvider(LocationProviderInterface provider) {
427        mProviders.remove(provider);
428        mProvidersByName.remove(provider.getName());
429    }
430
431    private void loadProviders() {
432        synchronized (mLock) {
433            if (sProvidersLoaded) {
434                return;
435            }
436
437            // Load providers
438            loadProvidersLocked();
439            sProvidersLoaded = true;
440        }
441    }
442
443    private void loadProvidersLocked() {
444        try {
445            _loadProvidersLocked();
446        } catch (Exception e) {
447            Slog.e(TAG, "Exception loading providers:", e);
448        }
449    }
450
451    private void _loadProvidersLocked() {
452        // Attempt to load "real" providers first
453        if (GpsLocationProvider.isSupported()) {
454            // Create a gps location provider
455            GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
456            mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
457            mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
458            addProvider(gpsProvider);
459            mGpsLocationProvider = gpsProvider;
460        }
461
462        // create a passive location provider, which is always enabled
463        PassiveProvider passiveProvider = new PassiveProvider(this);
464        addProvider(passiveProvider);
465        mEnabledProviders.add(passiveProvider.getName());
466
467        // initialize external network location and geocoder services
468        Resources resources = mContext.getResources();
469        String serviceName = resources.getString(
470                com.android.internal.R.string.config_networkLocationProvider);
471        if (serviceName != null) {
472            mNetworkLocationProvider =
473                new LocationProviderProxy(mContext, LocationManager.NETWORK_PROVIDER,
474                        serviceName, mLocationHandler);
475            addProvider(mNetworkLocationProvider);
476        }
477
478        serviceName = resources.getString(com.android.internal.R.string.config_geocodeProvider);
479        if (serviceName != null) {
480            mGeocodeProvider = new GeocoderProxy(mContext, serviceName);
481        }
482
483        updateProvidersLocked();
484    }
485
486    /**
487     * @param context the context that the LocationManagerService runs in
488     */
489    public LocationManagerService(Context context) {
490        super();
491        mContext = context;
492
493        if (LOCAL_LOGV) {
494            Slog.v(TAG, "Constructed LocationManager Service");
495        }
496    }
497
498    void systemReady() {
499        // we defer starting up the service until the system is ready
500        Thread thread = new Thread(null, this, "LocationManagerService");
501        thread.start();
502    }
503
504    private void initialize() {
505        // Create a wake lock, needs to be done before calling loadProviders() below
506        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
507        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
508
509        // Load providers
510        loadProviders();
511
512        // Register for Network (Wifi or Mobile) updates
513        IntentFilter intentFilter = new IntentFilter();
514        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
515        // Register for Package Manager updates
516        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
517        intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
518        intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
519        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
520        IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
521        mContext.registerReceiver(mBroadcastReceiver, sdFilter);
522
523        // listen for settings changes
524        ContentResolver resolver = mContext.getContentResolver();
525        Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
526                "(" + Settings.System.NAME + "=?)",
527                new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
528                null);
529        mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
530        SettingsObserver settingsObserver = new SettingsObserver();
531        mSettings.addObserver(settingsObserver);
532    }
533
534    public void run()
535    {
536        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
537        Looper.prepare();
538        mLocationHandler = new LocationWorkerHandler();
539        initialize();
540        Looper.loop();
541    }
542
543    private boolean isAllowedBySettingsLocked(String provider) {
544        if (mEnabledProviders.contains(provider)) {
545            return true;
546        }
547        if (mDisabledProviders.contains(provider)) {
548            return false;
549        }
550        // Use system settings
551        ContentResolver resolver = mContext.getContentResolver();
552
553        return Settings.Secure.isLocationProviderEnabled(resolver, provider);
554    }
555
556    private void checkPermissionsSafe(String provider) {
557        if ((LocationManager.GPS_PROVIDER.equals(provider)
558                 || LocationManager.PASSIVE_PROVIDER.equals(provider))
559            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
560                != PackageManager.PERMISSION_GRANTED)) {
561            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
562        }
563        if (LocationManager.NETWORK_PROVIDER.equals(provider)
564            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
565                != PackageManager.PERMISSION_GRANTED)
566            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
567                != PackageManager.PERMISSION_GRANTED)) {
568            throw new SecurityException(
569                "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
570        }
571    }
572
573    private boolean isAllowedProviderSafe(String provider) {
574        if ((LocationManager.GPS_PROVIDER.equals(provider)
575                || LocationManager.PASSIVE_PROVIDER.equals(provider))
576            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
577                != PackageManager.PERMISSION_GRANTED)) {
578            return false;
579        }
580        if (LocationManager.NETWORK_PROVIDER.equals(provider)
581            && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
582                != PackageManager.PERMISSION_GRANTED)
583            && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
584                != PackageManager.PERMISSION_GRANTED)) {
585            return false;
586        }
587
588        return true;
589    }
590
591    public List<String> getAllProviders() {
592        try {
593            synchronized (mLock) {
594                return _getAllProvidersLocked();
595            }
596        } catch (SecurityException se) {
597            throw se;
598        } catch (Exception e) {
599            Slog.e(TAG, "getAllProviders got exception:", e);
600            return null;
601        }
602    }
603
604    private List<String> _getAllProvidersLocked() {
605        if (LOCAL_LOGV) {
606            Slog.v(TAG, "getAllProviders");
607        }
608        ArrayList<String> out = new ArrayList<String>(mProviders.size());
609        for (int i = mProviders.size() - 1; i >= 0; i--) {
610            LocationProviderInterface p = mProviders.get(i);
611            out.add(p.getName());
612        }
613        return out;
614    }
615
616    public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
617        try {
618            synchronized (mLock) {
619                return _getProvidersLocked(criteria, enabledOnly);
620            }
621        } catch (SecurityException se) {
622            throw se;
623        } catch (Exception e) {
624            Slog.e(TAG, "getProviders got exception:", e);
625            return null;
626        }
627    }
628
629    private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
630        if (LOCAL_LOGV) {
631            Slog.v(TAG, "getProviders");
632        }
633        ArrayList<String> out = new ArrayList<String>(mProviders.size());
634        for (int i = mProviders.size() - 1; i >= 0; i--) {
635            LocationProviderInterface p = mProviders.get(i);
636            String name = p.getName();
637            if (isAllowedProviderSafe(name)) {
638                if (enabledOnly && !isAllowedBySettingsLocked(name)) {
639                    continue;
640                }
641                if (criteria != null && !p.meetsCriteria(criteria)) {
642                    continue;
643                }
644                out.add(name);
645            }
646        }
647        return out;
648    }
649
650    /**
651     * Returns the next looser power requirement, in the sequence:
652     *
653     * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
654     */
655    private int nextPower(int power) {
656        switch (power) {
657        case Criteria.POWER_LOW:
658            return Criteria.POWER_MEDIUM;
659        case Criteria.POWER_MEDIUM:
660            return Criteria.POWER_HIGH;
661        case Criteria.POWER_HIGH:
662            return Criteria.NO_REQUIREMENT;
663        case Criteria.NO_REQUIREMENT:
664        default:
665            return Criteria.NO_REQUIREMENT;
666        }
667    }
668
669    /**
670     * Returns the next looser accuracy requirement, in the sequence:
671     *
672     * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
673     */
674    private int nextAccuracy(int accuracy) {
675        if (accuracy == Criteria.ACCURACY_FINE) {
676            return Criteria.ACCURACY_COARSE;
677        } else {
678            return Criteria.NO_REQUIREMENT;
679        }
680    }
681
682    private class LpPowerComparator implements Comparator<LocationProviderInterface> {
683        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
684            // Smaller is better
685            return (l1.getPowerRequirement() - l2.getPowerRequirement());
686         }
687
688         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
689             return (l1.getPowerRequirement() == l2.getPowerRequirement());
690         }
691    }
692
693    private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
694        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
695            // Smaller is better
696            return (l1.getAccuracy() - l2.getAccuracy());
697         }
698
699         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
700             return (l1.getAccuracy() == l2.getAccuracy());
701         }
702    }
703
704    private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
705
706        private static final int ALTITUDE_SCORE = 4;
707        private static final int BEARING_SCORE = 4;
708        private static final int SPEED_SCORE = 4;
709
710        private int score(LocationProviderInterface p) {
711            return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
712                (p.supportsBearing() ? BEARING_SCORE : 0) +
713                (p.supportsSpeed() ? SPEED_SCORE : 0);
714        }
715
716        public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
717            return (score(l2) - score(l1)); // Bigger is better
718         }
719
720         public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
721             return (score(l1) == score(l2));
722         }
723    }
724
725    private LocationProviderInterface best(List<String> providerNames) {
726        ArrayList<LocationProviderInterface> providers;
727        synchronized (mLock) {
728            providers = new ArrayList<LocationProviderInterface>(mProviders.size());
729            for (int i = mProviders.size() - 1; i >= 0; i--) {
730                providers.add(mProviders.get(i));
731            }
732        }
733
734        if (providers.size() < 2) {
735            return providers.get(0);
736        }
737
738        // First, sort by power requirement
739        Collections.sort(providers, new LpPowerComparator());
740        int power = providers.get(0).getPowerRequirement();
741        if (power < providers.get(1).getPowerRequirement()) {
742            return providers.get(0);
743        }
744
745        int idx, size;
746
747        ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
748        idx = 0;
749        size = providers.size();
750        while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
751            tmp.add(providers.get(idx));
752            idx++;
753        }
754
755        // Next, sort by accuracy
756        Collections.sort(tmp, new LpAccuracyComparator());
757        int acc = tmp.get(0).getAccuracy();
758        if (acc < tmp.get(1).getAccuracy()) {
759            return tmp.get(0);
760        }
761
762        ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
763        idx = 0;
764        size = tmp.size();
765        while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
766            tmp2.add(tmp.get(idx));
767            idx++;
768        }
769
770        // Finally, sort by capability "score"
771        Collections.sort(tmp2, new LpCapabilityComparator());
772        return tmp2.get(0);
773    }
774
775    /**
776     * Returns the name of the provider that best meets the given criteria. Only providers
777     * that are permitted to be accessed by the calling activity will be
778     * returned.  If several providers meet the criteria, the one with the best
779     * accuracy is returned.  If no provider meets the criteria,
780     * the criteria are loosened in the following sequence:
781     *
782     * <ul>
783     * <li> power requirement
784     * <li> accuracy
785     * <li> bearing
786     * <li> speed
787     * <li> altitude
788     * </ul>
789     *
790     * <p> Note that the requirement on monetary cost is not removed
791     * in this process.
792     *
793     * @param criteria the criteria that need to be matched
794     * @param enabledOnly if true then only a provider that is currently enabled is returned
795     * @return name of the provider that best matches the requirements
796     */
797    public String getBestProvider(Criteria criteria, boolean enabledOnly) {
798        List<String> goodProviders = getProviders(criteria, enabledOnly);
799        if (!goodProviders.isEmpty()) {
800            return best(goodProviders).getName();
801        }
802
803        // Make a copy of the criteria that we can modify
804        criteria = new Criteria(criteria);
805
806        // Loosen power requirement
807        int power = criteria.getPowerRequirement();
808        while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
809            power = nextPower(power);
810            criteria.setPowerRequirement(power);
811            goodProviders = getProviders(criteria, enabledOnly);
812        }
813        if (!goodProviders.isEmpty()) {
814            return best(goodProviders).getName();
815        }
816
817        // Loosen accuracy requirement
818        int accuracy = criteria.getAccuracy();
819        while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
820            accuracy = nextAccuracy(accuracy);
821            criteria.setAccuracy(accuracy);
822            goodProviders = getProviders(criteria, enabledOnly);
823        }
824        if (!goodProviders.isEmpty()) {
825            return best(goodProviders).getName();
826        }
827
828        // Remove bearing requirement
829        criteria.setBearingRequired(false);
830        goodProviders = getProviders(criteria, enabledOnly);
831        if (!goodProviders.isEmpty()) {
832            return best(goodProviders).getName();
833        }
834
835        // Remove speed requirement
836        criteria.setSpeedRequired(false);
837        goodProviders = getProviders(criteria, enabledOnly);
838        if (!goodProviders.isEmpty()) {
839            return best(goodProviders).getName();
840        }
841
842        // Remove altitude requirement
843        criteria.setAltitudeRequired(false);
844        goodProviders = getProviders(criteria, enabledOnly);
845        if (!goodProviders.isEmpty()) {
846            return best(goodProviders).getName();
847        }
848
849        return null;
850    }
851
852    public boolean providerMeetsCriteria(String provider, Criteria criteria) {
853        LocationProviderInterface p = mProvidersByName.get(provider);
854        if (p == null) {
855            throw new IllegalArgumentException("provider=" + provider);
856        }
857        return p.meetsCriteria(criteria);
858    }
859
860    private void updateProvidersLocked() {
861        for (int i = mProviders.size() - 1; i >= 0; i--) {
862            LocationProviderInterface p = mProviders.get(i);
863            boolean isEnabled = p.isEnabled();
864            String name = p.getName();
865            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
866
867            if (isEnabled && !shouldBeEnabled) {
868                updateProviderListenersLocked(name, false);
869            } else if (!isEnabled && shouldBeEnabled) {
870                updateProviderListenersLocked(name, true);
871            }
872
873        }
874    }
875
876    private void updateProviderListenersLocked(String provider, boolean enabled) {
877        int listeners = 0;
878
879        LocationProviderInterface p = mProvidersByName.get(provider);
880        if (p == null) {
881            return;
882        }
883
884        ArrayList<Receiver> deadReceivers = null;
885
886        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
887        if (records != null) {
888            final int N = records.size();
889            for (int i=0; i<N; i++) {
890                UpdateRecord record = records.get(i);
891                // Sends a notification message to the receiver
892                if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
893                    if (deadReceivers == null) {
894                        deadReceivers = new ArrayList<Receiver>();
895                    }
896                    deadReceivers.add(record.mReceiver);
897                }
898                listeners++;
899            }
900        }
901
902        if (deadReceivers != null) {
903            for (int i=deadReceivers.size()-1; i>=0; i--) {
904                removeUpdatesLocked(deadReceivers.get(i));
905            }
906        }
907
908        if (enabled) {
909            p.enable();
910            if (listeners > 0) {
911                p.setMinTime(getMinTimeLocked(provider));
912                p.enableLocationTracking(true);
913            }
914        } else {
915            p.enableLocationTracking(false);
916            p.disable();
917        }
918    }
919
920    private long getMinTimeLocked(String provider) {
921        long minTime = Long.MAX_VALUE;
922        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
923        if (records != null) {
924            for (int i=records.size()-1; i>=0; i--) {
925                minTime = Math.min(minTime, records.get(i).mMinTime);
926            }
927        }
928        return minTime;
929    }
930
931    private class UpdateRecord {
932        final String mProvider;
933        final Receiver mReceiver;
934        final long mMinTime;
935        final float mMinDistance;
936        final boolean mSingleShot;
937        final int mUid;
938        Location mLastFixBroadcast;
939        long mLastStatusBroadcast;
940
941        /**
942         * Note: must be constructed with lock held.
943         */
944        UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
945            Receiver receiver, int uid) {
946            mProvider = provider;
947            mReceiver = receiver;
948            mMinTime = minTime;
949            mMinDistance = minDistance;
950            mSingleShot = singleShot;
951            mUid = uid;
952
953            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
954            if (records == null) {
955                records = new ArrayList<UpdateRecord>();
956                mRecordsByProvider.put(provider, records);
957            }
958            if (!records.contains(this)) {
959                records.add(this);
960            }
961        }
962
963        /**
964         * Method to be called when a record will no longer be used.  Calling this multiple times
965         * must have the same effect as calling it once.
966         */
967        void disposeLocked() {
968            ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
969            if (records != null) {
970                records.remove(this);
971            }
972        }
973
974        @Override
975        public String toString() {
976            return "UpdateRecord{"
977                    + Integer.toHexString(System.identityHashCode(this))
978                    + " " + mProvider + " " + mReceiver + "}";
979        }
980
981        void dump(PrintWriter pw, String prefix) {
982            pw.println(prefix + this);
983            pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
984            pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
985            pw.println(prefix + "mSingleShot=" + mSingleShot);
986            pw.println(prefix + "mUid=" + mUid);
987            pw.println(prefix + "mLastFixBroadcast:");
988            if (mLastFixBroadcast != null) {
989                mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
990            }
991            pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
992        }
993    }
994
995    private Receiver getReceiver(ILocationListener listener) {
996        IBinder binder = listener.asBinder();
997        Receiver receiver = mReceivers.get(binder);
998        if (receiver == null) {
999            receiver = new Receiver(listener);
1000            mReceivers.put(binder, receiver);
1001
1002            try {
1003                if (receiver.isListener()) {
1004                    receiver.getListener().asBinder().linkToDeath(receiver, 0);
1005                }
1006            } catch (RemoteException e) {
1007                Slog.e(TAG, "linkToDeath failed:", e);
1008                return null;
1009            }
1010        }
1011        return receiver;
1012    }
1013
1014    private Receiver getReceiver(PendingIntent intent) {
1015        Receiver receiver = mReceivers.get(intent);
1016        if (receiver == null) {
1017            receiver = new Receiver(intent);
1018            mReceivers.put(intent, receiver);
1019        }
1020        return receiver;
1021    }
1022
1023    private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
1024        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1025        if (records != null) {
1026            for (int i = records.size() - 1; i >= 0; i--) {
1027                UpdateRecord record = records.get(i);
1028                if (record.mUid == uid && record.mReceiver != excludedReceiver) {
1029                    return true;
1030                }
1031           }
1032        }
1033        for (ProximityAlert alert : mProximityAlerts.values()) {
1034            if (alert.mUid == uid) {
1035                return true;
1036            }
1037        }
1038        return false;
1039    }
1040
1041    public void requestLocationUpdates(String provider, Criteria criteria,
1042        long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
1043        if (criteria != null) {
1044            // FIXME - should we consider using multiple providers simultaneously
1045            // rather than only the best one?
1046            // Should we do anything different for single shot fixes?
1047            provider = getBestProvider(criteria, true);
1048            if (provider == null) {
1049                throw new IllegalArgumentException("no providers found for criteria");
1050            }
1051        }
1052        try {
1053            synchronized (mLock) {
1054                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1055                        getReceiver(listener));
1056            }
1057        } catch (SecurityException se) {
1058            throw se;
1059        } catch (IllegalArgumentException iae) {
1060            throw iae;
1061        } catch (Exception e) {
1062            Slog.e(TAG, "requestUpdates got exception:", e);
1063        }
1064    }
1065
1066    public void requestLocationUpdatesPI(String provider, Criteria criteria,
1067            long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
1068        if (criteria != null) {
1069            // FIXME - should we consider using multiple providers simultaneously
1070            // rather than only the best one?
1071            // Should we do anything different for single shot fixes?
1072            provider = getBestProvider(criteria, true);
1073            if (provider == null) {
1074                throw new IllegalArgumentException("no providers found for criteria");
1075            }
1076        }
1077        try {
1078            synchronized (mLock) {
1079                requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1080                        getReceiver(intent));
1081            }
1082        } catch (SecurityException se) {
1083            throw se;
1084        } catch (IllegalArgumentException iae) {
1085            throw iae;
1086        } catch (Exception e) {
1087            Slog.e(TAG, "requestUpdates got exception:", e);
1088        }
1089    }
1090
1091    private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
1092            boolean singleShot, Receiver receiver) {
1093        if (LOCAL_LOGV) {
1094            Slog.v(TAG, "_requestLocationUpdates: listener = " + receiver);
1095        }
1096
1097        LocationProviderInterface p = mProvidersByName.get(provider);
1098        if (p == null) {
1099            throw new IllegalArgumentException("provider=" + provider);
1100        }
1101
1102        checkPermissionsSafe(provider);
1103
1104        // so wakelock calls will succeed
1105        final int callingUid = Binder.getCallingUid();
1106        boolean newUid = !providerHasListener(provider, callingUid, null);
1107        long identity = Binder.clearCallingIdentity();
1108        try {
1109            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
1110                    receiver, callingUid);
1111            UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
1112            if (oldRecord != null) {
1113                oldRecord.disposeLocked();
1114            }
1115
1116            if (newUid) {
1117                p.addListener(callingUid);
1118            }
1119
1120            boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1121            if (isProviderEnabled) {
1122                long minTimeForProvider = getMinTimeLocked(provider);
1123                p.setMinTime(minTimeForProvider);
1124                // try requesting single shot if singleShot is true, and fall back to
1125                // regular location tracking if requestSingleShotFix() is not supported
1126                if (!singleShot || !p.requestSingleShotFix()) {
1127                    p.enableLocationTracking(true);
1128                }
1129            } else {
1130                // Notify the listener that updates are currently disabled
1131                receiver.callProviderEnabledLocked(provider, false);
1132            }
1133        } finally {
1134            Binder.restoreCallingIdentity(identity);
1135        }
1136    }
1137
1138    public void removeUpdates(ILocationListener listener) {
1139        try {
1140            synchronized (mLock) {
1141                removeUpdatesLocked(getReceiver(listener));
1142            }
1143        } catch (SecurityException se) {
1144            throw se;
1145        } catch (IllegalArgumentException iae) {
1146            throw iae;
1147        } catch (Exception e) {
1148            Slog.e(TAG, "removeUpdates got exception:", e);
1149        }
1150    }
1151
1152    public void removeUpdatesPI(PendingIntent intent) {
1153        try {
1154            synchronized (mLock) {
1155                removeUpdatesLocked(getReceiver(intent));
1156            }
1157        } catch (SecurityException se) {
1158            throw se;
1159        } catch (IllegalArgumentException iae) {
1160            throw iae;
1161        } catch (Exception e) {
1162            Slog.e(TAG, "removeUpdates got exception:", e);
1163        }
1164    }
1165
1166    private void removeUpdatesLocked(Receiver receiver) {
1167        if (LOCAL_LOGV) {
1168            Slog.v(TAG, "_removeUpdates: listener = " + receiver);
1169        }
1170
1171        // so wakelock calls will succeed
1172        final int callingUid = Binder.getCallingUid();
1173        long identity = Binder.clearCallingIdentity();
1174        try {
1175            if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1176                receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1177                synchronized(receiver) {
1178                    if(receiver.mPendingBroadcasts > 0) {
1179                        decrementPendingBroadcasts();
1180                        receiver.mPendingBroadcasts = 0;
1181                    }
1182                }
1183            }
1184
1185            // Record which providers were associated with this listener
1186            HashSet<String> providers = new HashSet<String>();
1187            HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
1188            if (oldRecords != null) {
1189                // Call dispose() on the obsolete update records.
1190                for (UpdateRecord record : oldRecords.values()) {
1191                    if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1192                        LocationProviderInterface p = mProvidersByName.get(record.mProvider);
1193                        if (p != null) {
1194                            p.removeListener(callingUid);
1195                        }
1196                    }
1197                    record.disposeLocked();
1198                }
1199                // Accumulate providers
1200                providers.addAll(oldRecords.keySet());
1201            }
1202
1203            // See if the providers associated with this listener have any
1204            // other listeners; if one does, inform it of the new smallest minTime
1205            // value; if one does not, disable location tracking for it
1206            for (String provider : providers) {
1207                // If provider is already disabled, don't need to do anything
1208                if (!isAllowedBySettingsLocked(provider)) {
1209                    continue;
1210                }
1211
1212                boolean hasOtherListener = false;
1213                ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1214                if (recordsForProvider != null && recordsForProvider.size() > 0) {
1215                    hasOtherListener = true;
1216                }
1217
1218                LocationProviderInterface p = mProvidersByName.get(provider);
1219                if (p != null) {
1220                    if (hasOtherListener) {
1221                        p.setMinTime(getMinTimeLocked(provider));
1222                    } else {
1223                        p.enableLocationTracking(false);
1224                    }
1225                }
1226            }
1227        } finally {
1228            Binder.restoreCallingIdentity(identity);
1229        }
1230    }
1231
1232    public boolean addGpsStatusListener(IGpsStatusListener listener) {
1233        if (mGpsStatusProvider == null) {
1234            return false;
1235        }
1236        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
1237                PackageManager.PERMISSION_GRANTED) {
1238            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1239        }
1240
1241        try {
1242            mGpsStatusProvider.addGpsStatusListener(listener);
1243        } catch (RemoteException e) {
1244            Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
1245            return false;
1246        }
1247        return true;
1248    }
1249
1250    public void removeGpsStatusListener(IGpsStatusListener listener) {
1251        synchronized (mLock) {
1252            try {
1253                mGpsStatusProvider.removeGpsStatusListener(listener);
1254            } catch (Exception e) {
1255                Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1256            }
1257        }
1258    }
1259
1260    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1261        if (provider == null) {
1262            // throw NullPointerException to remain compatible with previous implementation
1263            throw new NullPointerException();
1264        }
1265
1266        // first check for permission to the provider
1267        checkPermissionsSafe(provider);
1268        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1269        if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1270                != PackageManager.PERMISSION_GRANTED)) {
1271            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1272        }
1273
1274        synchronized (mLock) {
1275            LocationProviderInterface p = mProvidersByName.get(provider);
1276            if (p == null) {
1277                return false;
1278            }
1279
1280            return p.sendExtraCommand(command, extras);
1281        }
1282    }
1283
1284    public boolean sendNiResponse(int notifId, int userResponse)
1285    {
1286        if (Binder.getCallingUid() != Process.myUid()) {
1287            throw new SecurityException(
1288                    "calling sendNiResponse from outside of the system is not allowed");
1289        }
1290        try {
1291            return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1292        }
1293        catch (RemoteException e)
1294        {
1295            Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1296            return false;
1297        }
1298    }
1299
1300    class ProximityAlert {
1301        final int  mUid;
1302        final double mLatitude;
1303        final double mLongitude;
1304        final float mRadius;
1305        final long mExpiration;
1306        final PendingIntent mIntent;
1307        final Location mLocation;
1308
1309        public ProximityAlert(int uid, double latitude, double longitude,
1310            float radius, long expiration, PendingIntent intent) {
1311            mUid = uid;
1312            mLatitude = latitude;
1313            mLongitude = longitude;
1314            mRadius = radius;
1315            mExpiration = expiration;
1316            mIntent = intent;
1317
1318            mLocation = new Location("");
1319            mLocation.setLatitude(latitude);
1320            mLocation.setLongitude(longitude);
1321        }
1322
1323        long getExpiration() {
1324            return mExpiration;
1325        }
1326
1327        PendingIntent getIntent() {
1328            return mIntent;
1329        }
1330
1331        boolean isInProximity(double latitude, double longitude, float accuracy) {
1332            Location loc = new Location("");
1333            loc.setLatitude(latitude);
1334            loc.setLongitude(longitude);
1335
1336            double radius = loc.distanceTo(mLocation);
1337            return radius <= Math.max(mRadius,accuracy);
1338        }
1339
1340        @Override
1341        public String toString() {
1342            return "ProximityAlert{"
1343                    + Integer.toHexString(System.identityHashCode(this))
1344                    + " uid " + mUid + mIntent + "}";
1345        }
1346
1347        void dump(PrintWriter pw, String prefix) {
1348            pw.println(prefix + this);
1349            pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1350            pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1351            pw.println(prefix + "mIntent=" + mIntent);
1352            pw.println(prefix + "mLocation:");
1353            mLocation.dump(new PrintWriterPrinter(pw), prefix + "  ");
1354        }
1355    }
1356
1357    // Listener for receiving locations to trigger proximity alerts
1358    class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
1359
1360        boolean isGpsAvailable = false;
1361
1362        // Note: this is called with the lock held.
1363        public void onLocationChanged(Location loc) {
1364
1365            // If Gps is available, then ignore updates from NetworkLocationProvider
1366            if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1367                isGpsAvailable = true;
1368            }
1369            if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1370                return;
1371            }
1372
1373            // Process proximity alerts
1374            long now = System.currentTimeMillis();
1375            double latitude = loc.getLatitude();
1376            double longitude = loc.getLongitude();
1377            float accuracy = loc.getAccuracy();
1378            ArrayList<PendingIntent> intentsToRemove = null;
1379
1380            for (ProximityAlert alert : mProximityAlerts.values()) {
1381                PendingIntent intent = alert.getIntent();
1382                long expiration = alert.getExpiration();
1383
1384                if ((expiration == -1) || (now <= expiration)) {
1385                    boolean entered = mProximitiesEntered.contains(alert);
1386                    boolean inProximity =
1387                        alert.isInProximity(latitude, longitude, accuracy);
1388                    if (!entered && inProximity) {
1389                        if (LOCAL_LOGV) {
1390                            Slog.v(TAG, "Entered alert");
1391                        }
1392                        mProximitiesEntered.add(alert);
1393                        Intent enteredIntent = new Intent();
1394                        enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1395                        try {
1396                            synchronized (this) {
1397                                // synchronize to ensure incrementPendingBroadcasts()
1398                                // is called before decrementPendingBroadcasts()
1399                                intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
1400                                // call this after broadcasting so we do not increment
1401                                // if we throw an exeption.
1402                                incrementPendingBroadcasts();
1403                            }
1404                        } catch (PendingIntent.CanceledException e) {
1405                            if (LOCAL_LOGV) {
1406                                Slog.v(TAG, "Canceled proximity alert: " + alert, e);
1407                            }
1408                            if (intentsToRemove == null) {
1409                                intentsToRemove = new ArrayList<PendingIntent>();
1410                            }
1411                            intentsToRemove.add(intent);
1412                        }
1413                    } else if (entered && !inProximity) {
1414                        if (LOCAL_LOGV) {
1415                            Slog.v(TAG, "Exited alert");
1416                        }
1417                        mProximitiesEntered.remove(alert);
1418                        Intent exitedIntent = new Intent();
1419                        exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1420                        try {
1421                            synchronized (this) {
1422                                // synchronize to ensure incrementPendingBroadcasts()
1423                                // is called before decrementPendingBroadcasts()
1424                                intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
1425                                // call this after broadcasting so we do not increment
1426                                // if we throw an exeption.
1427                                incrementPendingBroadcasts();
1428                            }
1429                        } catch (PendingIntent.CanceledException e) {
1430                            if (LOCAL_LOGV) {
1431                                Slog.v(TAG, "Canceled proximity alert: " + alert, e);
1432                            }
1433                            if (intentsToRemove == null) {
1434                                intentsToRemove = new ArrayList<PendingIntent>();
1435                            }
1436                            intentsToRemove.add(intent);
1437                        }
1438                    }
1439                } else {
1440                    // Mark alert for expiration
1441                    if (LOCAL_LOGV) {
1442                        Slog.v(TAG, "Expiring proximity alert: " + alert);
1443                    }
1444                    if (intentsToRemove == null) {
1445                        intentsToRemove = new ArrayList<PendingIntent>();
1446                    }
1447                    intentsToRemove.add(alert.getIntent());
1448                }
1449            }
1450
1451            // Remove expired alerts
1452            if (intentsToRemove != null) {
1453                for (PendingIntent i : intentsToRemove) {
1454                    ProximityAlert alert = mProximityAlerts.get(i);
1455                    mProximitiesEntered.remove(alert);
1456                    removeProximityAlertLocked(i);
1457                }
1458            }
1459        }
1460
1461        // Note: this is called with the lock held.
1462        public void onProviderDisabled(String provider) {
1463            if (provider.equals(LocationManager.GPS_PROVIDER)) {
1464                isGpsAvailable = false;
1465            }
1466        }
1467
1468        // Note: this is called with the lock held.
1469        public void onProviderEnabled(String provider) {
1470            // ignore
1471        }
1472
1473        // Note: this is called with the lock held.
1474        public void onStatusChanged(String provider, int status, Bundle extras) {
1475            if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1476                (status != LocationProvider.AVAILABLE)) {
1477                isGpsAvailable = false;
1478            }
1479        }
1480
1481        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1482                int resultCode, String resultData, Bundle resultExtras) {
1483            // synchronize to ensure incrementPendingBroadcasts()
1484            // is called before decrementPendingBroadcasts()
1485            synchronized (this) {
1486                decrementPendingBroadcasts();
1487            }
1488        }
1489    }
1490
1491    public void addProximityAlert(double latitude, double longitude,
1492        float radius, long expiration, PendingIntent intent) {
1493        try {
1494            synchronized (mLock) {
1495                addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1496            }
1497        } catch (SecurityException se) {
1498            throw se;
1499        } catch (IllegalArgumentException iae) {
1500            throw iae;
1501        } catch (Exception e) {
1502            Slog.e(TAG, "addProximityAlert got exception:", e);
1503        }
1504    }
1505
1506    private void addProximityAlertLocked(double latitude, double longitude,
1507        float radius, long expiration, PendingIntent intent) {
1508        if (LOCAL_LOGV) {
1509            Slog.v(TAG, "addProximityAlert: latitude = " + latitude +
1510                    ", longitude = " + longitude +
1511                    ", expiration = " + expiration +
1512                    ", intent = " + intent);
1513        }
1514
1515        // Require ability to access all providers for now
1516        if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1517            !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1518            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1519        }
1520
1521        if (expiration != -1) {
1522            expiration += System.currentTimeMillis();
1523        }
1524        ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1525                latitude, longitude, radius, expiration, intent);
1526        mProximityAlerts.put(intent, alert);
1527
1528        if (mProximityReceiver == null) {
1529            mProximityListener = new ProximityListener();
1530            mProximityReceiver = new Receiver(mProximityListener);
1531
1532            for (int i = mProviders.size() - 1; i >= 0; i--) {
1533                LocationProviderInterface provider = mProviders.get(i);
1534                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f,
1535                        false, mProximityReceiver);
1536            }
1537        }
1538    }
1539
1540    public void removeProximityAlert(PendingIntent intent) {
1541        try {
1542            synchronized (mLock) {
1543               removeProximityAlertLocked(intent);
1544            }
1545        } catch (SecurityException se) {
1546            throw se;
1547        } catch (IllegalArgumentException iae) {
1548            throw iae;
1549        } catch (Exception e) {
1550            Slog.e(TAG, "removeProximityAlert got exception:", e);
1551        }
1552    }
1553
1554    private void removeProximityAlertLocked(PendingIntent intent) {
1555        if (LOCAL_LOGV) {
1556            Slog.v(TAG, "removeProximityAlert: intent = " + intent);
1557        }
1558
1559        mProximityAlerts.remove(intent);
1560        if (mProximityAlerts.size() == 0) {
1561            removeUpdatesLocked(mProximityReceiver);
1562            mProximityReceiver = null;
1563            mProximityListener = null;
1564        }
1565     }
1566
1567    /**
1568     * @return null if the provider does not exist
1569     * @throws SecurityException if the provider is not allowed to be
1570     * accessed by the caller
1571     */
1572    public Bundle getProviderInfo(String provider) {
1573        try {
1574            synchronized (mLock) {
1575                return _getProviderInfoLocked(provider);
1576            }
1577        } catch (SecurityException se) {
1578            throw se;
1579        } catch (IllegalArgumentException iae) {
1580            throw iae;
1581        } catch (Exception e) {
1582            Slog.e(TAG, "_getProviderInfo got exception:", e);
1583            return null;
1584        }
1585    }
1586
1587    private Bundle _getProviderInfoLocked(String provider) {
1588        LocationProviderInterface p = mProvidersByName.get(provider);
1589        if (p == null) {
1590            return null;
1591        }
1592
1593        checkPermissionsSafe(provider);
1594
1595        Bundle b = new Bundle();
1596        b.putBoolean("network", p.requiresNetwork());
1597        b.putBoolean("satellite", p.requiresSatellite());
1598        b.putBoolean("cell", p.requiresCell());
1599        b.putBoolean("cost", p.hasMonetaryCost());
1600        b.putBoolean("altitude", p.supportsAltitude());
1601        b.putBoolean("speed", p.supportsSpeed());
1602        b.putBoolean("bearing", p.supportsBearing());
1603        b.putInt("power", p.getPowerRequirement());
1604        b.putInt("accuracy", p.getAccuracy());
1605
1606        return b;
1607    }
1608
1609    public boolean isProviderEnabled(String provider) {
1610        try {
1611            synchronized (mLock) {
1612                return _isProviderEnabledLocked(provider);
1613            }
1614        } catch (SecurityException se) {
1615            throw se;
1616        } catch (IllegalArgumentException iae) {
1617            throw iae;
1618        } catch (Exception e) {
1619            Slog.e(TAG, "isProviderEnabled got exception:", e);
1620            return false;
1621        }
1622    }
1623
1624    public void reportLocation(Location location, boolean passive) {
1625        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1626                != PackageManager.PERMISSION_GRANTED) {
1627            throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1628        }
1629
1630        mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1631        Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1632        m.arg1 = (passive ? 1 : 0);
1633        mLocationHandler.sendMessageAtFrontOfQueue(m);
1634    }
1635
1636    private boolean _isProviderEnabledLocked(String provider) {
1637        checkPermissionsSafe(provider);
1638
1639        LocationProviderInterface p = mProvidersByName.get(provider);
1640        if (p == null) {
1641            throw new IllegalArgumentException("provider=" + provider);
1642        }
1643        return isAllowedBySettingsLocked(provider);
1644    }
1645
1646    public Location getLastKnownLocation(String provider) {
1647        try {
1648            synchronized (mLock) {
1649                return _getLastKnownLocationLocked(provider);
1650            }
1651        } catch (SecurityException se) {
1652            throw se;
1653        } catch (IllegalArgumentException iae) {
1654            throw iae;
1655        } catch (Exception e) {
1656            Slog.e(TAG, "getLastKnownLocation got exception:", e);
1657            return null;
1658        }
1659    }
1660
1661    private Location _getLastKnownLocationLocked(String provider) {
1662        checkPermissionsSafe(provider);
1663
1664        LocationProviderInterface p = mProvidersByName.get(provider);
1665        if (p == null) {
1666            throw new IllegalArgumentException("provider=" + provider);
1667        }
1668
1669        if (!isAllowedBySettingsLocked(provider)) {
1670            return null;
1671        }
1672
1673        return mLastKnownLocation.get(provider);
1674    }
1675
1676    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1677        // Always broadcast the first update
1678        if (lastLoc == null) {
1679            return true;
1680        }
1681
1682        // Don't broadcast same location again regardless of condition
1683        // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1684        if (loc.getTime() == lastLoc.getTime()) {
1685            return false;
1686        }
1687
1688        // Check whether sufficient distance has been traveled
1689        double minDistance = record.mMinDistance;
1690        if (minDistance > 0.0) {
1691            if (loc.distanceTo(lastLoc) <= minDistance) {
1692                return false;
1693            }
1694        }
1695
1696        return true;
1697    }
1698
1699    private void handleLocationChangedLocked(Location location, boolean passive) {
1700        String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
1701        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1702        if (records == null || records.size() == 0) {
1703            return;
1704        }
1705
1706        LocationProviderInterface p = mProvidersByName.get(provider);
1707        if (p == null) {
1708            return;
1709        }
1710
1711        // Update last known location for provider
1712        Location lastLocation = mLastKnownLocation.get(provider);
1713        if (lastLocation == null) {
1714            mLastKnownLocation.put(provider, new Location(location));
1715        } else {
1716            lastLocation.set(location);
1717        }
1718
1719        // Fetch latest status update time
1720        long newStatusUpdateTime = p.getStatusUpdateTime();
1721
1722       // Get latest status
1723        Bundle extras = new Bundle();
1724        int status = p.getStatus(extras);
1725
1726        ArrayList<Receiver> deadReceivers = null;
1727
1728        // Broadcast location or status to all listeners
1729        final int N = records.size();
1730        for (int i=0; i<N; i++) {
1731            UpdateRecord r = records.get(i);
1732            Receiver receiver = r.mReceiver;
1733            boolean receiverDead = false;
1734
1735            Location lastLoc = r.mLastFixBroadcast;
1736            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1737                if (lastLoc == null) {
1738                    lastLoc = new Location(location);
1739                    r.mLastFixBroadcast = lastLoc;
1740                } else {
1741                    lastLoc.set(location);
1742                }
1743                if (!receiver.callLocationChangedLocked(location)) {
1744                    Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1745                    receiverDead = true;
1746                }
1747            }
1748
1749            long prevStatusUpdateTime = r.mLastStatusBroadcast;
1750            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1751                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1752
1753                r.mLastStatusBroadcast = newStatusUpdateTime;
1754                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1755                    receiverDead = true;
1756                    Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1757                }
1758            }
1759
1760            // remove receiver if it is dead or we just processed a single shot request
1761            if (receiverDead || r.mSingleShot) {
1762                if (deadReceivers == null) {
1763                    deadReceivers = new ArrayList<Receiver>();
1764                }
1765                if (!deadReceivers.contains(receiver)) {
1766                    deadReceivers.add(receiver);
1767                }
1768            }
1769        }
1770
1771        if (deadReceivers != null) {
1772            for (int i=deadReceivers.size()-1; i>=0; i--) {
1773                removeUpdatesLocked(deadReceivers.get(i));
1774            }
1775        }
1776    }
1777
1778    private class LocationWorkerHandler extends Handler {
1779
1780        @Override
1781        public void handleMessage(Message msg) {
1782            try {
1783                if (msg.what == MESSAGE_LOCATION_CHANGED) {
1784                    // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
1785
1786                    synchronized (mLock) {
1787                        Location location = (Location) msg.obj;
1788                        String provider = location.getProvider();
1789                        boolean passive = (msg.arg1 == 1);
1790
1791                        if (!passive) {
1792                            // notify other providers of the new location
1793                            for (int i = mProviders.size() - 1; i >= 0; i--) {
1794                                LocationProviderInterface p = mProviders.get(i);
1795                                if (!provider.equals(p.getName())) {
1796                                    p.updateLocation(location);
1797                                }
1798                            }
1799                        }
1800
1801                        if (isAllowedBySettingsLocked(provider)) {
1802                            handleLocationChangedLocked(location, passive);
1803                        }
1804                    }
1805                }
1806            } catch (Exception e) {
1807                // Log, don't crash!
1808                Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1809            }
1810        }
1811    }
1812
1813    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1814        @Override
1815        public void onReceive(Context context, Intent intent) {
1816            String action = intent.getAction();
1817            boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
1818            if (queryRestart
1819                    || action.equals(Intent.ACTION_PACKAGE_REMOVED)
1820                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
1821                    || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1822                synchronized (mLock) {
1823                    int uidList[] = null;
1824                    if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1825                        uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1826                    } else {
1827                        uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
1828                    }
1829                    if (uidList == null || uidList.length == 0) {
1830                        return;
1831                    }
1832                    for (int uid : uidList) {
1833                        if (uid >= 0) {
1834                            ArrayList<Receiver> removedRecs = null;
1835                            for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1836                                for (int j=i.size()-1; j>=0; j--) {
1837                                    UpdateRecord ur = i.get(j);
1838                                    if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1839                                        if (queryRestart) {
1840                                            setResultCode(Activity.RESULT_OK);
1841                                            return;
1842                                        }
1843                                        if (removedRecs == null) {
1844                                            removedRecs = new ArrayList<Receiver>();
1845                                        }
1846                                        if (!removedRecs.contains(ur.mReceiver)) {
1847                                            removedRecs.add(ur.mReceiver);
1848                                        }
1849                                    }
1850                                }
1851                            }
1852                            ArrayList<ProximityAlert> removedAlerts = null;
1853                            for (ProximityAlert i : mProximityAlerts.values()) {
1854                                if (i.mUid == uid) {
1855                                    if (queryRestart) {
1856                                        setResultCode(Activity.RESULT_OK);
1857                                        return;
1858                                    }
1859                                    if (removedAlerts == null) {
1860                                        removedAlerts = new ArrayList<ProximityAlert>();
1861                                    }
1862                                    if (!removedAlerts.contains(i)) {
1863                                        removedAlerts.add(i);
1864                                    }
1865                                }
1866                            }
1867                            if (removedRecs != null) {
1868                                for (int i=removedRecs.size()-1; i>=0; i--) {
1869                                    removeUpdatesLocked(removedRecs.get(i));
1870                                }
1871                            }
1872                            if (removedAlerts != null) {
1873                                for (int i=removedAlerts.size()-1; i>=0; i--) {
1874                                    removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1875                                }
1876                            }
1877                        }
1878                    }
1879                }
1880            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1881                boolean noConnectivity =
1882                    intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1883                if (!noConnectivity) {
1884                    mNetworkState = LocationProvider.AVAILABLE;
1885                } else {
1886                    mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
1887                }
1888                NetworkInfo info =
1889                    (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
1890
1891                // Notify location providers of current network state
1892                synchronized (mLock) {
1893                    for (int i = mProviders.size() - 1; i >= 0; i--) {
1894                        LocationProviderInterface provider = mProviders.get(i);
1895                        if (provider.requiresNetwork()) {
1896                            provider.updateNetworkState(mNetworkState, info);
1897                        }
1898                    }
1899                }
1900            }
1901        }
1902    };
1903
1904    // Wake locks
1905
1906    private void incrementPendingBroadcasts() {
1907        synchronized (mWakeLock) {
1908            if (mPendingBroadcasts++ == 0) {
1909                try {
1910                    mWakeLock.acquire();
1911                    log("Acquired wakelock");
1912                } catch (Exception e) {
1913                    // This is to catch a runtime exception thrown when we try to release an
1914                    // already released lock.
1915                    Slog.e(TAG, "exception in acquireWakeLock()", e);
1916                }
1917            }
1918        }
1919    }
1920
1921    private void decrementPendingBroadcasts() {
1922        synchronized (mWakeLock) {
1923            if (--mPendingBroadcasts == 0) {
1924                try {
1925                    // Release wake lock
1926                    if (mWakeLock.isHeld()) {
1927                        mWakeLock.release();
1928                        log("Released wakelock");
1929                    } else {
1930                        log("Can't release wakelock again!");
1931                    }
1932                } catch (Exception e) {
1933                    // This is to catch a runtime exception thrown when we try to release an
1934                    // already released lock.
1935                    Slog.e(TAG, "exception in releaseWakeLock()", e);
1936                }
1937            }
1938        }
1939    }
1940
1941    // Geocoder
1942
1943    public Boolean geocoderIsImplemented() {
1944        return mGeocodeProvider != null;
1945    }
1946
1947    public String getFromLocation(double latitude, double longitude, int maxResults,
1948            GeocoderParams params, List<Address> addrs) {
1949        if (mGeocodeProvider != null) {
1950            return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1951                    params, addrs);
1952        }
1953        return null;
1954    }
1955
1956
1957    public String getFromLocationName(String locationName,
1958            double lowerLeftLatitude, double lowerLeftLongitude,
1959            double upperRightLatitude, double upperRightLongitude, int maxResults,
1960            GeocoderParams params, List<Address> addrs) {
1961
1962        if (mGeocodeProvider != null) {
1963            return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1964                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1965                    maxResults, params, addrs);
1966        }
1967        return null;
1968    }
1969
1970    // Mock Providers
1971
1972    private void checkMockPermissionsSafe() {
1973        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1974                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1975        if (!allowMocks) {
1976            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1977        }
1978
1979        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1980            PackageManager.PERMISSION_GRANTED) {
1981            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1982        }
1983    }
1984
1985    public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1986        boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1987        boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1988        checkMockPermissionsSafe();
1989
1990        if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1991            throw new IllegalArgumentException("Cannot mock the passive location provider");
1992        }
1993
1994        long identity = Binder.clearCallingIdentity();
1995        synchronized (mLock) {
1996            MockProvider provider = new MockProvider(name, this,
1997                requiresNetwork, requiresSatellite,
1998                requiresCell, hasMonetaryCost, supportsAltitude,
1999                supportsSpeed, supportsBearing, powerRequirement, accuracy);
2000            // remove the real provider if we are replacing GPS or network provider
2001            if (LocationManager.GPS_PROVIDER.equals(name)
2002                    || LocationManager.NETWORK_PROVIDER.equals(name)) {
2003                LocationProviderInterface p = mProvidersByName.get(name);
2004                if (p != null) {
2005                    p.enableLocationTracking(false);
2006                    removeProvider(p);
2007                }
2008            }
2009            if (mProvidersByName.get(name) != null) {
2010                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2011            }
2012            addProvider(provider);
2013            mMockProviders.put(name, provider);
2014            mLastKnownLocation.put(name, null);
2015            updateProvidersLocked();
2016        }
2017        Binder.restoreCallingIdentity(identity);
2018    }
2019
2020    public void removeTestProvider(String provider) {
2021        checkMockPermissionsSafe();
2022        synchronized (mLock) {
2023            MockProvider mockProvider = mMockProviders.get(provider);
2024            if (mockProvider == null) {
2025                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2026            }
2027            long identity = Binder.clearCallingIdentity();
2028            removeProvider(mProvidersByName.get(provider));
2029            mMockProviders.remove(mockProvider);
2030            // reinstall real provider if we were mocking GPS or network provider
2031            if (LocationManager.GPS_PROVIDER.equals(provider) &&
2032                    mGpsLocationProvider != null) {
2033                addProvider(mGpsLocationProvider);
2034            } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
2035                    mNetworkLocationProvider != null) {
2036                addProvider(mNetworkLocationProvider);
2037            }
2038            mLastKnownLocation.put(provider, null);
2039            updateProvidersLocked();
2040            Binder.restoreCallingIdentity(identity);
2041        }
2042    }
2043
2044    public void setTestProviderLocation(String provider, Location loc) {
2045        checkMockPermissionsSafe();
2046        synchronized (mLock) {
2047            MockProvider mockProvider = mMockProviders.get(provider);
2048            if (mockProvider == null) {
2049                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2050            }
2051            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
2052            long identity = Binder.clearCallingIdentity();
2053            mockProvider.setLocation(loc);
2054            Binder.restoreCallingIdentity(identity);
2055        }
2056    }
2057
2058    public void clearTestProviderLocation(String provider) {
2059        checkMockPermissionsSafe();
2060        synchronized (mLock) {
2061            MockProvider mockProvider = mMockProviders.get(provider);
2062            if (mockProvider == null) {
2063                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2064            }
2065            mockProvider.clearLocation();
2066        }
2067    }
2068
2069    public void setTestProviderEnabled(String provider, boolean enabled) {
2070        checkMockPermissionsSafe();
2071        synchronized (mLock) {
2072            MockProvider mockProvider = mMockProviders.get(provider);
2073            if (mockProvider == null) {
2074                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2075            }
2076            long identity = Binder.clearCallingIdentity();
2077            if (enabled) {
2078                mockProvider.enable();
2079                mEnabledProviders.add(provider);
2080                mDisabledProviders.remove(provider);
2081            } else {
2082                mockProvider.disable();
2083                mEnabledProviders.remove(provider);
2084                mDisabledProviders.add(provider);
2085            }
2086            updateProvidersLocked();
2087            Binder.restoreCallingIdentity(identity);
2088        }
2089    }
2090
2091    public void clearTestProviderEnabled(String provider) {
2092        checkMockPermissionsSafe();
2093        synchronized (mLock) {
2094            MockProvider mockProvider = mMockProviders.get(provider);
2095            if (mockProvider == null) {
2096                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2097            }
2098            long identity = Binder.clearCallingIdentity();
2099            mEnabledProviders.remove(provider);
2100            mDisabledProviders.remove(provider);
2101            updateProvidersLocked();
2102            Binder.restoreCallingIdentity(identity);
2103        }
2104    }
2105
2106    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2107        checkMockPermissionsSafe();
2108        synchronized (mLock) {
2109            MockProvider mockProvider = mMockProviders.get(provider);
2110            if (mockProvider == null) {
2111                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2112            }
2113            mockProvider.setStatus(status, extras, updateTime);
2114        }
2115    }
2116
2117    public void clearTestProviderStatus(String provider) {
2118        checkMockPermissionsSafe();
2119        synchronized (mLock) {
2120            MockProvider mockProvider = mMockProviders.get(provider);
2121            if (mockProvider == null) {
2122                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2123            }
2124            mockProvider.clearStatus();
2125        }
2126    }
2127
2128    private void log(String log) {
2129        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2130            Slog.d(TAG, log);
2131        }
2132    }
2133
2134    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2135        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2136                != PackageManager.PERMISSION_GRANTED) {
2137            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
2138                    + Binder.getCallingPid()
2139                    + ", uid=" + Binder.getCallingUid());
2140            return;
2141        }
2142
2143        synchronized (mLock) {
2144            pw.println("Current Location Manager state:");
2145            pw.println("  sProvidersLoaded=" + sProvidersLoaded);
2146            pw.println("  Listeners:");
2147            int N = mReceivers.size();
2148            for (int i=0; i<N; i++) {
2149                pw.println("    " + mReceivers.get(i));
2150            }
2151            pw.println("  Location Listeners:");
2152            for (Receiver i : mReceivers.values()) {
2153                pw.println("    " + i + ":");
2154                for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
2155                    pw.println("      " + j.getKey() + ":");
2156                    j.getValue().dump(pw, "        ");
2157                }
2158            }
2159            pw.println("  Records by Provider:");
2160            for (Map.Entry<String, ArrayList<UpdateRecord>> i
2161                    : mRecordsByProvider.entrySet()) {
2162                pw.println("    " + i.getKey() + ":");
2163                for (UpdateRecord j : i.getValue()) {
2164                    pw.println("      " + j + ":");
2165                    j.dump(pw, "        ");
2166                }
2167            }
2168            pw.println("  Last Known Locations:");
2169            for (Map.Entry<String, Location> i
2170                    : mLastKnownLocation.entrySet()) {
2171                pw.println("    " + i.getKey() + ":");
2172                i.getValue().dump(new PrintWriterPrinter(pw), "      ");
2173            }
2174            if (mProximityAlerts.size() > 0) {
2175                pw.println("  Proximity Alerts:");
2176                for (Map.Entry<PendingIntent, ProximityAlert> i
2177                        : mProximityAlerts.entrySet()) {
2178                    pw.println("    " + i.getKey() + ":");
2179                    i.getValue().dump(pw, "      ");
2180                }
2181            }
2182            if (mProximitiesEntered.size() > 0) {
2183                pw.println("  Proximities Entered:");
2184                for (ProximityAlert i : mProximitiesEntered) {
2185                    pw.println("    " + i + ":");
2186                    i.dump(pw, "      ");
2187                }
2188            }
2189            pw.println("  mProximityReceiver=" + mProximityReceiver);
2190            pw.println("  mProximityListener=" + mProximityListener);
2191            if (mEnabledProviders.size() > 0) {
2192                pw.println("  Enabled Providers:");
2193                for (String i : mEnabledProviders) {
2194                    pw.println("    " + i);
2195                }
2196
2197            }
2198            if (mDisabledProviders.size() > 0) {
2199                pw.println("  Disabled Providers:");
2200                for (String i : mDisabledProviders) {
2201                    pw.println("    " + i);
2202                }
2203
2204            }
2205            if (mMockProviders.size() > 0) {
2206                pw.println("  Mock Providers:");
2207                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2208                    i.getValue().dump(pw, "      ");
2209                }
2210            }
2211            for (LocationProviderInterface provider: mProviders) {
2212                String state = provider.getInternalState();
2213                if (state != null) {
2214                    pw.println(provider.getName() + " Internal State:");
2215                    pw.write(state);
2216                }
2217            }
2218        }
2219    }
2220}
2221