LocationManagerService.java revision fff2fda0199dedbf1079454dca98a81190dce765
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.server;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.BufferedReader;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileDescriptor;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileReader;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.FileWriter;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.PrintWriter;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashMap;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.HashSet;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.List;
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Map;
319637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwoodimport java.util.Observable;
329637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwoodimport java.util.Observer;
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Set;
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.regex.Pattern;
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.PendingIntent;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.BroadcastReceiver;
389637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwoodimport android.content.ContentQueryMap;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.IntentFilter;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
449637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwoodimport android.database.Cursor;
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Address;
46a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwoodimport android.location.IGeocodeProvider;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.IGpsStatusListener;
4815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwoodimport android.location.IGpsStatusProvider;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.ILocationListener;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.ILocationManager;
51e932f7f2a47b770c636443d411436bd29cc4bb43Mike Lockwoodimport android.location.ILocationProvider;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.Location;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.LocationManager;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.location.LocationProvider;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.ConnectivityManager;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
613d12b51ee38537f6760a833618948f936e75561dMike Lockwoodimport android.os.Looper;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager;
64e932f7f2a47b770c636443d411436bd29cc4bb43Mike Lockwoodimport android.os.Process;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.PrintWriterPrinter;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.location.GpsLocationProvider;
72e932f7f2a47b770c636443d411436bd29cc4bb43Mike Lockwoodimport com.android.internal.location.LocationProviderProxy;
737ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwoodimport com.android.internal.location.MockProvider;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The service class that manages LocationProviders and issues location
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * updates and alerts.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@hide}
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
813d12b51ee38537f6760a833618948f936e75561dMike Lockwoodpublic class LocationManagerService extends ILocationManager.Stub implements Runnable {
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "LocationManagerService";
83105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project    private static final boolean LOCAL_LOGV = false;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Minimum time interval between last known location writes, in milliseconds.
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L;
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Max time to hold wake lock for, in milliseconds.
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // The last time a location was written, by provider name.
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final Pattern PATTERN_COMMA = Pattern.compile(",");
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ACCESS_FINE_LOCATION =
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        android.Manifest.permission.ACCESS_FINE_LOCATION;
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ACCESS_COARSE_LOCATION =
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        android.Manifest.permission.ACCESS_COARSE_LOCATION;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ACCESS_MOCK_LOCATION =
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        android.Manifest.permission.ACCESS_MOCK_LOCATION;
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
104275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood    private static final String INSTALL_LOCATION_PROVIDER =
105275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood        android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Set of providers that are explicitly enabled
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Set<String> mEnabledProviders = new HashSet<String>();
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Set of providers that are explicitly disabled
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Set<String> mDisabledProviders = new HashSet<String>();
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Locations, status values, and extras for mock providers
1147ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood    private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean sProvidersLoaded = false;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Context mContext;
119a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood    private IGeocodeProvider mGeocodeProvider;
12015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private IGpsStatusProvider mGpsStatusProvider;
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private LocationWorkerHandler mLocationHandler;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Handler messages
1244e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood    private static final int MESSAGE_LOCATION_CHANGED = 1;
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1260528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    // wakelock variables
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final static String WAKELOCK_KEY = "LocationManagerService";
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private PowerManager.WakeLock mWakeLock = null;
12948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    private int mPendingBroadcasts;
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1322f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood     * List of all receivers.
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1342f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
13715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    /**
13815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood     * List of location providers.
13915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood     */
14015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private final ArrayList<LocationProviderProxy> mProviders =
14115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        new ArrayList<LocationProviderProxy>();
14215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private final HashMap<String, LocationProviderProxy> mProvidersByName
14315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        = new HashMap<String, LocationProviderProxy>();
14415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1462f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood     * Object used internally for synchronization
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1482f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private final Object mLock = new Object();
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Mapping from provider name to all its UpdateRecords
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashMap<String,ArrayList<UpdateRecord>>();
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Proximity listeners
15748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    private Receiver mProximityReceiver = null;
15848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    private ILocationListener mProximityListener = null;
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashMap<PendingIntent,ProximityAlert>();
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private HashSet<ProximityAlert> mProximitiesEntered =
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashSet<ProximityAlert>();
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Last known location for each provider
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private HashMap<String,Location> mLastKnownLocation =
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        new HashMap<String,Location>();
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1684df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project    private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
1694df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project
1709637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood    // for Settings change notification
1719637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood    private ContentQueryMap mSettings;
1729637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A wrapper class holding either an ILocationListener or a PendingIntent to receive
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * location updates.
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
17748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ILocationListener mListener;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PendingIntent mPendingIntent;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Object mKey;
1812f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
18248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        int mPendingBroadcasts;
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1842f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        Receiver(ILocationListener listener) {
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mListener = listener;
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPendingIntent = null;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mKey = listener.asBinder();
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1902f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        Receiver(PendingIntent intent) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mPendingIntent = intent;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mListener = null;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mKey = intent;
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean equals(Object otherObj) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (otherObj instanceof Receiver) {
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mKey.equals(
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ((Receiver)otherObj).mKey);
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int hashCode() {
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mKey.hashCode();
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2093681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mListener != null) {
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return "Receiver{"
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + Integer.toHexString(System.identityHashCode(this))
2152f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                        + " Listener " + mKey + "}";
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return "Receiver{"
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + Integer.toHexString(System.identityHashCode(this))
2192f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                        + " Intent " + mKey + "}";
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isListener() {
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mListener != null;
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isPendingIntent() {
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mPendingIntent != null;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ILocationListener getListener() {
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mListener != null) {
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mListener;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("Request for non-existent listener");
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public PendingIntent getPendingIntent() {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mPendingIntent != null) {
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mPendingIntent;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("Request for non-existent intent");
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mListener != null) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
24848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
24948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
25048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
25148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        mListener.onStatusChanged(provider, status, extras);
25248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        if (mListener != mProximityListener) {
25348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // call this after broadcasting so we do not increment
25448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // if we throw an exeption.
25548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            incrementPendingBroadcastsLocked();
25648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        }
25748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Intent statusChanged = new Intent();
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                statusChanged.putExtras(extras);
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
26648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
26748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
26848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
26948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
27048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // call this after broadcasting so we do not increment
27148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // if we throw an exeption.
27248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        incrementPendingBroadcastsLocked();
27348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (PendingIntent.CanceledException e) {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean callLocationChangedLocked(Location location) {
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mListener != null) {
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
28448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
28548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
28648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
28748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        mListener.onLocationChanged(location);
28848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        if (mListener != mProximityListener) {
28948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // call this after broadcasting so we do not increment
29048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // if we throw an exeption.
29148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            incrementPendingBroadcastsLocked();
29248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        }
29348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (RemoteException e) {
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Intent locationChanged = new Intent();
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
30148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
30248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
30348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
30448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
30548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // call this after broadcasting so we do not increment
30648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // if we throw an exeption.
30748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        incrementPendingBroadcastsLocked();
30848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
30948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                } catch (PendingIntent.CanceledException e) {
31048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    return false;
31148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                }
31248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            }
31348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            return true;
31448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
31548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
31648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        public boolean callProviderEnabledLocked(String provider, boolean enabled) {
31748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            if (mListener != null) {
31848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                try {
31948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
32048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
32148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
32248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        if (enabled) {
32348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            mListener.onProviderEnabled(provider);
32448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        } else {
32548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            mListener.onProviderDisabled(provider);
32648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        }
32748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        if (mListener != mProximityListener) {
32848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // call this after broadcasting so we do not increment
32948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            // if we throw an exeption.
33048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            incrementPendingBroadcastsLocked();
33148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        }
33248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
33348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                } catch (RemoteException e) {
33448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    return false;
33548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                }
33648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            } else {
33748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                Intent providerIntent = new Intent();
33848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
33948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                try {
34048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    synchronized (this) {
34148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // synchronize to ensure incrementPendingBroadcastsLocked()
34248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // is called before decrementPendingBroadcasts()
34348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
34448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // call this after broadcasting so we do not increment
34548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        // if we throw an exeption.
34648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        incrementPendingBroadcastsLocked();
34748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    }
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (PendingIntent.CanceledException e) {
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return false;
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void binderDied() {
356105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            if (LOCAL_LOGV) {
357105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                Log.v(TAG, "Location listener died");
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3592f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeUpdatesLocked(this);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            synchronized (this) {
36348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                if (mPendingBroadcasts > 0) {
36448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    LocationManagerService.this.decrementPendingBroadcasts();
36548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    mPendingBroadcasts = 0;
36648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                }
36748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            }
36848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
36948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
37048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
37148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                int resultCode, String resultData, Bundle resultExtras) {
3720528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            synchronized (this) {
3730528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                decrementPendingBroadcastsLocked();
3740528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            }
37548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
37648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
3770528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        // this must be called while synchronized by caller in a synchronized block
37848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        // containing the sending of the broadcaset
37948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        private void incrementPendingBroadcastsLocked() {
38048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            if (mPendingBroadcasts++ == 0) {
3810528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                LocationManagerService.this.incrementPendingBroadcasts();
38248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            }
38348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
38448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
3850528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        private void decrementPendingBroadcastsLocked() {
3860528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            if (--mPendingBroadcasts == 0) {
3870528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                LocationManagerService.this.decrementPendingBroadcasts();
38848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            }
38948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
39048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    }
39148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
39248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    public void locationCallbackFinished(ILocationListener listener) {
39348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        Receiver receiver = getReceiver(listener);
39448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        if (receiver != null) {
3950528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            synchronized (receiver) {
3960528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                // so wakelock calls will succeed
3970528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                long identity = Binder.clearCallingIdentity();
3980528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                receiver.decrementPendingBroadcastsLocked();
3990528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                Binder.restoreCallingIdentity(identity);
4000528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood           }
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4049637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood    private final class SettingsObserver implements Observer {
4059637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        public void update(Observable o, Object arg) {
4062f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
4079637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood                updateProvidersLocked();
4089637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood            }
4099637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        }
4109637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood    }
4119637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Location readLastKnownLocationLocked(String provider) {
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Location location = null;
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String s = null;
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File f = new File(LocationManager.SYSTEM_DIR + "/location."
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + provider);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!f.exists()) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            BufferedReader reader = new BufferedReader(new FileReader(f), 256);
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            s = reader.readLine();
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Unable to read last known location", e);
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (s == null) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String[] tokens = PATTERN_COMMA.split(s);
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int idx = 0;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long time = Long.parseLong(tokens[idx++]);
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double latitude = Double.parseDouble(tokens[idx++]);
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double longitude = Double.parseDouble(tokens[idx++]);
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double altitude = Double.parseDouble(tokens[idx++]);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float bearing = Float.parseFloat(tokens[idx++]);
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float speed = Float.parseFloat(tokens[idx++]);
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location = new Location(provider);
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setTime(time);
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setLatitude(latitude);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setLongitude(longitude);
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setAltitude(altitude);
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setBearing(bearing);
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location.setSpeed(speed);
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (NumberFormatException nfe) {
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "NumberFormatException reading last known location", nfe);
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return location;
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void writeLastKnownLocationLocked(String provider,
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Location location) {
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long now = SystemClock.elapsedRealtime();
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Long last = mLastWriteTime.get(provider);
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((last != null)
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLastWriteTime.put(provider, now);
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        StringBuilder sb = new StringBuilder(100);
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getTime());
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(',');
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getLatitude());
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(',');
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getLongitude());
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(',');
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getAltitude());
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(',');
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getBearing());
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(',');
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        sb.append(location.getSpeed());
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        FileWriter writer = null;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File d = new File(LocationManager.SYSTEM_DIR);
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!d.exists()) {
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!d.mkdirs()) {
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "Unable to create directory to write location");
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            writer = new FileWriter(f);
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            writer.write(sb.toString());
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (IOException e) {
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.w(TAG, "Unable to write location", e);
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (writer != null) {
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                writer.close();
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IOException e) {
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "Exception closing file", e);
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
50315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private void addProvider(LocationProviderProxy provider) {
50415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        mProviders.add(provider);
50515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        mProvidersByName.put(provider.getName(), provider);
50615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    }
50715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
50815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    private void removeProvider(LocationProviderProxy provider) {
50915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        mProviders.remove(provider);
510fff2fda0199dedbf1079454dca98a81190dce765Suchi Amalapurapu        provider.unlinkProvider();
51115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        mProvidersByName.remove(provider.getName());
51215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood    }
51315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void loadProviders() {
5152f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (sProvidersLoaded) {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Load providers
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            loadProvidersLocked();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            sProvidersLoaded = true;
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void loadProvidersLocked() {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            _loadProvidersLocked();
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "Exception loading providers:", e);
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void _loadProvidersLocked() {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Attempt to load "real" providers first
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (GpsLocationProvider.isSupported()) {
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Create a gps location provider
53815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
53915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            mGpsStatusProvider = provider.getGpsStatusProvider();
5408dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
5418dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            addProvider(proxy);
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        updateProvidersLocked();
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the context that the LocationManagerService runs in
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public LocationManagerService(Context context) {
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super();
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
5533d12b51ee38537f6760a833618948f936e75561dMike Lockwood
5543d12b51ee38537f6760a833618948f936e75561dMike Lockwood        Thread thread = new Thread(null, this, "LocationManagerService");
5553d12b51ee38537f6760a833618948f936e75561dMike Lockwood        thread.start();
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
557105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
558105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "Constructed LocationManager Service");
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5603d12b51ee38537f6760a833618948f936e75561dMike Lockwood    }
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5623d12b51ee38537f6760a833618948f936e75561dMike Lockwood    private void initialize() {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Create a wake lock, needs to be done before calling loadProviders() below
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
5660528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Load providers
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        loadProviders();
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Register for Network (Wifi or Mobile) updates
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        IntentFilter intentFilter = new IntentFilter();
5720528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
5730528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        // Register for Package Manager updates
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
5760528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        mContext.registerReceiver(mBroadcastReceiver, intentFilter);
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5789637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        // listen for settings changes
5799637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        ContentResolver resolver = mContext.getContentResolver();
5809637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
5819637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood                "(" + Settings.System.NAME + "=?)",
5829637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood                new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
5839637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood                null);
5849637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
5859637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        SettingsObserver settingsObserver = new SettingsObserver();
5869637d474899d9725da8a41fdf92b9bd1a15d301eMike Lockwood        mSettings.addObserver(settingsObserver);
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5893d12b51ee38537f6760a833618948f936e75561dMike Lockwood    public void run()
5903d12b51ee38537f6760a833618948f936e75561dMike Lockwood    {
5913d12b51ee38537f6760a833618948f936e75561dMike Lockwood        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
5923d12b51ee38537f6760a833618948f936e75561dMike Lockwood        Looper.prepare();
5933d12b51ee38537f6760a833618948f936e75561dMike Lockwood        mLocationHandler = new LocationWorkerHandler();
5943d12b51ee38537f6760a833618948f936e75561dMike Lockwood        initialize();
5953d12b51ee38537f6760a833618948f936e75561dMike Lockwood        Looper.loop();
5963d12b51ee38537f6760a833618948f936e75561dMike Lockwood    }
5973d12b51ee38537f6760a833618948f936e75561dMike Lockwood
598275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood    public void installLocationProvider(String name, ILocationProvider provider) {
599275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
600275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood                != PackageManager.PERMISSION_GRANTED) {
601275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood            throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
602e932f7f2a47b770c636443d411436bd29cc4bb43Mike Lockwood        }
603e932f7f2a47b770c636443d411436bd29cc4bb43Mike Lockwood
6042f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
6053681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood            // check to see if we are reinstalling a dead provider
6063681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood            LocationProviderProxy oldProvider = mProvidersByName.get(name);
6073681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood            if (oldProvider != null) {
6083681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                if (oldProvider.isDead()) {
6093681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                    Log.d(TAG, "replacing dead provider");
6103681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                    removeProvider(oldProvider);
6113681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                } else {
6123681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                    throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
6133681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                }
6143681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood            }
6153681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood
6168dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
6178dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            addProvider(proxy);
6188dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            updateProvidersLocked();
619275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood
6208dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            // notify provider of current network state
6218dfe5d8c6ba9cb165994f09843abaa6302d63c1dMike Lockwood            proxy.updateNetworkState(mNetworkState);
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
625275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood    public void installGeocodeProvider(IGeocodeProvider provider) {
626275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
627275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood                != PackageManager.PERMISSION_GRANTED) {
628275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood            throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
629a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        }
630a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood
631a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        mGeocodeProvider = provider;
632a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood    }
633a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isAllowedBySettingsLocked(String provider) {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mEnabledProviders.contains(provider)) {
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mDisabledProviders.contains(provider)) {
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Use system settings
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ContentResolver resolver = mContext.getContentResolver();
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String allowedProviders = Settings.Secure.getString(resolver,
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project           Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return ((allowedProviders != null) && (allowedProviders.contains(provider)));
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkPermissionsSafe(String provider) {
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LocationManager.GPS_PROVIDER.equals(provider)
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)) {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LocationManager.NETWORK_PROVIDER.equals(provider)
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)) {
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException(
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isAllowedProviderSafe(String provider) {
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LocationManager.GPS_PROVIDER.equals(provider)
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)) {
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (LocationManager.NETWORK_PROVIDER.equals(provider)
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)) {
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<String> getAllProviders() {
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
6842f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return _getAllProvidersLocked();
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "getAllProviders got exception:", e);
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private List<String> _getAllProvidersLocked() {
696105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
697105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "getAllProviders");
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
69915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        ArrayList<String> out = new ArrayList<String>(mProviders.size());
70015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        for (int i = mProviders.size() - 1; i >= 0; i--) {
70115e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            LocationProviderProxy p = mProviders.get(i);
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            out.add(p.getName());
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return out;
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public List<String> getProviders(boolean enabledOnly) {
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
7092f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return _getProvidersLocked(enabledOnly);
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
715105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.e(TAG, "getProviders got exception:", e);
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private List<String> _getProvidersLocked(boolean enabledOnly) {
721105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
722105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "getProviders");
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
72415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        ArrayList<String> out = new ArrayList<String>(mProviders.size());
72515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        for (int i = mProviders.size() - 1; i >= 0; i--) {
72615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            LocationProviderProxy p = mProviders.get(i);
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String name = p.getName();
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isAllowedProviderSafe(name)) {
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (enabledOnly && !isAllowedBySettingsLocked(name)) {
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                out.add(name);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return out;
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void updateProvidersLocked() {
73915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        for (int i = mProviders.size() - 1; i >= 0; i--) {
74015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            LocationProviderProxy p = mProviders.get(i);
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isEnabled = p.isEnabled();
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String name = p.getName();
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isEnabled && !shouldBeEnabled) {
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                updateProviderListenersLocked(name, false);
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (!isEnabled && shouldBeEnabled) {
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                updateProviderListenersLocked(name, true);
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void updateProviderListenersLocked(String provider, boolean enabled) {
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int listeners = 0;
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
75715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy p = mProvidersByName.get(provider);
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<Receiver> deadReceivers = null;
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (records != null) {
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int N = records.size();
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                UpdateRecord record = records.get(i);
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Sends a notification message to the receiver
77048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
77148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                    if (deadReceivers == null) {
77248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                        deadReceivers = new ArrayList<Receiver>();
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
7744686657cee6411eb00235d49b4a8663a96361a00Simon Schoar                    deadReceivers.add(record.mReceiver);
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                listeners++;
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (deadReceivers != null) {
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=deadReceivers.size()-1; i>=0; i--) {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeUpdatesLocked(deadReceivers.get(i));
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (enabled) {
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.enable();
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (listeners > 0) {
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.setMinTime(getMinTimeLocked(provider));
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                p.enableLocationTracking(true);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.enableLocationTracking(false);
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            p.disable();
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private long getMinTimeLocked(String provider) {
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long minTime = Long.MAX_VALUE;
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (records != null) {
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=records.size()-1; i>=0; i--) {
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                minTime = Math.min(minTime, records.get(i).mMinTime);
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return minTime;
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class UpdateRecord {
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final String mProvider;
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Receiver mReceiver;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long mMinTime;
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float mMinDistance;
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int mUid;
8152f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        Location mLastFixBroadcast;
8162f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        long mLastStatusBroadcast;
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Note: must be constructed with lock held.
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        UpdateRecord(String provider, long minTime, float minDistance,
8222f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            Receiver receiver, int uid) {
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mProvider = provider;
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mReceiver = receiver;
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinTime = minTime;
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinDistance = minDistance;
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mUid = uid;
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (records == null) {
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                records = new ArrayList<UpdateRecord>();
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mRecordsByProvider.put(provider, records);
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!records.contains(this)) {
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                records.add(this);
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Method to be called when a record will no longer be used.  Calling this multiple times
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * must have the same effect as calling it once.
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void disposeLocked() {
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            records.remove(this);
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "UpdateRecord{"
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Integer.toHexString(System.identityHashCode(this))
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " " + mProvider + " " + mReceiver + "}";
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void dump(PrintWriter pw, String prefix) {
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + this);
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
8592f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            pw.println(prefix + "mUid=" + mUid);
8602f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            pw.println(prefix + "mLastFixBroadcast:");
8612f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
8622f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Calls dispose().
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override protected void finalize() {
8692f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                disposeLocked();
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8752f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private Receiver getReceiver(ILocationListener listener) {
8762f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        IBinder binder = listener.asBinder();
8772f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        Receiver receiver = mReceivers.get(binder);
8782f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        if (receiver == null) {
8792f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            receiver = new Receiver(listener);
8802f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            mReceivers.put(binder, receiver);
8812f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
8822f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            try {
8832f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                if (receiver.isListener()) {
8842f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    receiver.getListener().asBinder().linkToDeath(receiver, 0);
8852f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                }
8862f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            } catch (RemoteException e) {
8872f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                Log.e(TAG, "linkToDeath failed:", e);
8882f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                return null;
8892f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
8902f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
8912f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        return receiver;
8922f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    }
8932f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
8942f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private Receiver getReceiver(PendingIntent intent) {
8952f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        Receiver receiver = mReceivers.get(intent);
8962f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        if (receiver == null) {
8972f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            receiver = new Receiver(intent);
8982f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            mReceivers.put(intent, receiver);
8992f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
9002f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        return receiver;
9012f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    }
9022f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
9032f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
9042f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
9052f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        if (records != null) {
9062f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            for (int i = records.size() - 1; i >= 0; i--) {
9072f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                UpdateRecord record = records.get(i);
9082f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                if (record.mUid == uid && record.mReceiver != excludedReceiver) {
9092f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    return true;
9102f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                }
9112f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood           }
9122f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
91395427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood        for (ProximityAlert alert : mProximityAlerts.values()) {
91495427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            if (alert.mUid == uid) {
91595427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood                return true;
9162f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
9172f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        }
9182f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        return false;
9192f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood    }
9202f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void requestLocationUpdates(String provider,
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long minTime, float minDistance, ILocationListener listener) {
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9252f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
9262f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "requestUpdates got exception:", e);
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void requestLocationUpdatesPI(String provider,
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long minTime, float minDistance, PendingIntent intent) {
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9382f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
9392f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "requestUpdates got exception:", e);
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void requestLocationUpdatesLocked(String provider,
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long minTime, float minDistance, Receiver receiver) {
950105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
951105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
95415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy proxy = mProvidersByName.get(provider);
95515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        if (proxy == null) {
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("provider=" + provider);
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkPermissionsSafe(provider);
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int callingUid = Binder.getCallingUid();
9632f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        boolean newUid = !providerHasListener(provider, callingUid, null);
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9662f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
9672f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldRecord != null) {
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                oldRecord.disposeLocked();
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9722f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            if (newUid) {
97315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                proxy.addListener(callingUid);
9742f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            }
9752f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isProviderEnabled) {
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long minTimeForProvider = getMinTimeLocked(provider);
97915e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                proxy.setMinTime(minTimeForProvider);
98015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                proxy.enableLocationTracking(true);
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
98248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                // Notify the listener that updates are currently disabled
98348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                receiver.callProviderEnabledLocked(provider, false);
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeUpdates(ILocationListener listener) {
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
9922f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
9932f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                removeUpdatesLocked(getReceiver(listener));
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "removeUpdates got exception:", e);
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeUpdatesPI(PendingIntent intent) {
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
10042f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
10052f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                removeUpdatesLocked(getReceiver(intent));
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "removeUpdates got exception:", e);
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeUpdatesLocked(Receiver receiver) {
1015105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
1016105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "_removeUpdates: listener = " + receiver);
10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // so wakelock calls will succeed
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int callingUid = Binder.getCallingUid();
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long identity = Binder.clearCallingIdentity();
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
10232f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
10242f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Record which providers were associated with this listener
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            HashSet<String> providers = new HashSet<String>();
10292f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (oldRecords != null) {
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Call dispose() on the obsolete update records.
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (UpdateRecord record : oldRecords.values()) {
10332f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    if (!providerHasListener(record.mProvider, callingUid, receiver)) {
103415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        LocationProviderProxy proxy = mProvidersByName.get(record.mProvider);
103515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        if (proxy != null) {
103615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                            proxy.removeListener(callingUid);
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    record.disposeLocked();
10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Accumulate providers
10429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                providers.addAll(oldRecords.keySet());
10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // See if the providers associated with this listener have any
10469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // other listeners; if one does, inform it of the new smallest minTime
10479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // value; if one does not, disable location tracking for it
10489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (String provider : providers) {
10499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If provider is already disabled, don't need to do anything
10509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!isAllowedBySettingsLocked(provider)) {
10519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
10529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean hasOtherListener = false;
10559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
10569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (recordsForProvider != null && recordsForProvider.size() > 0) {
10579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    hasOtherListener = true;
10589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
106015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                LocationProviderProxy p = mProvidersByName.get(provider);
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (p != null) {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (hasOtherListener) {
10639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        p.setMinTime(getMinTimeLocked(provider));
10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else {
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        p.enableLocationTracking(false);
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
10679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } finally {
10709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Binder.restoreCallingIdentity(identity);
10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean addGpsStatusListener(IGpsStatusListener listener) {
107515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        if (mGpsStatusProvider == null) {
10769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PackageManager.PERMISSION_GRANTED) {
10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
10819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
108415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            mGpsStatusProvider.addGpsStatusListener(listener);
10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (RemoteException e) {
108615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            Log.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
10879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
10889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeGpsStatusListener(IGpsStatusListener listener) {
10932f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
109415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            try {
109515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                mGpsStatusProvider.removeGpsStatusListener(listener);
109615e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            } catch (Exception e) {
109715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                Log.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
109815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            }
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean sendExtraCommand(String provider, String command, Bundle extras) {
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // first check for permission to the provider
11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkPermissionsSafe(provider);
11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // and check for ACCESS_LOCATION_EXTRA_COMMANDS
11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED)) {
11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11112f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
111215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            LocationProviderProxy proxy = mProvidersByName.get(provider);
11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (provider == null) {
11149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
111715e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            return proxy.sendExtraCommand(command, extras);
11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class ProximityAlert {
11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int  mUid;
11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final double mLatitude;
11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final double mLongitude;
11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final float mRadius;
11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long mExpiration;
11279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PendingIntent mIntent;
11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final Location mLocation;
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ProximityAlert(int uid, double latitude, double longitude,
11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            float radius, long expiration, PendingIntent intent) {
11329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mUid = uid;
11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLatitude = latitude;
11349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLongitude = longitude;
11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRadius = radius;
11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mExpiration = expiration;
11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mIntent = intent;
11389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocation = new Location("");
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocation.setLatitude(latitude);
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocation.setLongitude(longitude);
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long getExpiration() {
11459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mExpiration;
11469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        PendingIntent getIntent() {
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mIntent;
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isInProximity(double latitude, double longitude) {
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Location loc = new Location("");
11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            loc.setLatitude(latitude);
11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            loc.setLongitude(longitude);
11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double radius = loc.distanceTo(mLocation);
11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return radius <= mRadius;
11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public String toString() {
11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return "ProximityAlert{"
11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Integer.toHexString(System.identityHashCode(this))
11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + " uid " + mUid + mIntent + "}";
11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void dump(PrintWriter pw, String prefix) {
11699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + this);
11709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
11719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
11729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mIntent=" + mIntent);
11739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println(prefix + "mLocation:");
11749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mLocation.dump(new PrintWriterPrinter(pw), prefix + "  ");
11759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
11769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Listener for receiving locations to trigger proximity alerts
117948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
11809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isGpsAvailable = false;
11829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: this is called with the lock held.
11849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onLocationChanged(Location loc) {
11859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // If Gps is available, then ignore updates from NetworkLocationProvider
11879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
11889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isGpsAvailable = true;
11899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
11919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Process proximity alerts
11959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            long now = System.currentTimeMillis();
11969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double latitude = loc.getLatitude();
11979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            double longitude = loc.getLongitude();
11989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ArrayList<PendingIntent> intentsToRemove = null;
11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (ProximityAlert alert : mProximityAlerts.values()) {
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                PendingIntent intent = alert.getIntent();
12029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                long expiration = alert.getExpiration();
12039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((expiration == -1) || (now <= expiration)) {
12059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    boolean entered = mProximitiesEntered.contains(alert);
12069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    boolean inProximity =
12079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        alert.isInProximity(latitude, longitude);
12089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!entered && inProximity) {
1209105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        if (LOCAL_LOGV) {
1210105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            Log.v(TAG, "Entered alert");
12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mProximitiesEntered.add(alert);
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Intent enteredIntent = new Intent();
12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
12160528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                            synchronized (this) {
12170528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                                // synchronize to ensure incrementPendingBroadcasts()
121848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // is called before decrementPendingBroadcasts()
121948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
122048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // call this after broadcasting so we do not increment
122148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // if we throw an exeption.
12220528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                                incrementPendingBroadcasts();
122348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            }
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (PendingIntent.CanceledException e) {
1225105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            if (LOCAL_LOGV) {
1226105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                Log.v(TAG, "Canceled proximity alert: " + alert, e);
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (intentsToRemove == null) {
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                intentsToRemove = new ArrayList<PendingIntent>();
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            intentsToRemove.add(intent);
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    } else if (entered && !inProximity) {
1234105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        if (LOCAL_LOGV) {
1235105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            Log.v(TAG, "Exited alert");
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        mProximitiesEntered.remove(alert);
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Intent exitedIntent = new Intent();
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        try {
12410528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                            synchronized (this) {
12420528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                                // synchronize to ensure incrementPendingBroadcasts()
124348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // is called before decrementPendingBroadcasts()
124448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
124548f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // call this after broadcasting so we do not increment
124648f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                                // if we throw an exeption.
12470528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                                incrementPendingBroadcasts();
124848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                            }
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        } catch (PendingIntent.CanceledException e) {
1250105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                            if (LOCAL_LOGV) {
1251105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                                Log.v(TAG, "Canceled proximity alert: " + alert, e);
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (intentsToRemove == null) {
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                intentsToRemove = new ArrayList<PendingIntent>();
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            intentsToRemove.add(intent);
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Mark alert for expiration
1261105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                    if (LOCAL_LOGV) {
1262105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project                        Log.v(TAG, "Expiring proximity alert: " + alert);
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (intentsToRemove == null) {
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        intentsToRemove = new ArrayList<PendingIntent>();
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
12679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    intentsToRemove.add(alert.getIntent());
12689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Remove expired alerts
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (intentsToRemove != null) {
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (PendingIntent i : intentsToRemove) {
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mProximityAlerts.remove(i);
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ProximityAlert alert = mProximityAlerts.get(i);
12769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mProximitiesEntered.remove(alert);
12779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
12789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: this is called with the lock held.
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onProviderDisabled(String provider) {
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (provider.equals(LocationManager.GPS_PROVIDER)) {
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isGpsAvailable = false;
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: this is called with the lock held.
12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onProviderEnabled(String provider) {
12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // ignore
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Note: this is called with the lock held.
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onStatusChanged(String provider, int status, Bundle extras) {
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (status != LocationProvider.AVAILABLE)) {
12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                isGpsAvailable = false;
12999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
130148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
130248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        public void onSendFinished(PendingIntent pendingIntent, Intent intent,
130348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                int resultCode, String resultData, Bundle resultExtras) {
13040528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            // synchronize to ensure incrementPendingBroadcasts()
13050528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            // is called before decrementPendingBroadcasts()
13060528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            synchronized (this) {
13070528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                decrementPendingBroadcasts();
13080528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            }
130948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addProximityAlert(double latitude, double longitude,
13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float radius, long expiration, PendingIntent intent) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13152f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
13179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
13209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "addProximityAlert got exception:", e);
13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void addProximityAlertLocked(double latitude, double longitude,
13269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        float radius, long expiration, PendingIntent intent) {
1327105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
1328105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "addProximityAlert: latitude = " + latitude +
13299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ", longitude = " + longitude +
13309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ", expiration = " + expiration +
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    ", intent = " + intent);
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Require ability to access all providers for now
13359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
13369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
13379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
13389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (expiration != -1) {
13419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            expiration += System.currentTimeMillis();
13429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
13449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                latitude, longitude, radius, expiration, intent);
13459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mProximityAlerts.put(intent, alert);
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
134748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        if (mProximityReceiver == null) {
134848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            mProximityListener = new ProximityListener();
134948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            mProximityReceiver = new Receiver(mProximityListener);
13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
135195427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            for (int i = mProviders.size() - 1; i >= 0; i--) {
135295427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood                LocationProviderProxy provider = mProviders.get(i);
135348f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood                requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
13549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeProximityAlert(PendingIntent intent) {
13599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13602f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project               removeProximityAlertLocked(intent);
13629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
13649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
13659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
13669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "removeProximityAlert got exception:", e);
13679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void removeProximityAlertLocked(PendingIntent intent) {
1371105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project        if (LOCAL_LOGV) {
1372105925376f8d0f6b318c9938c7b83ef7fef094daThe Android Open Source Project            Log.v(TAG, "removeProximityAlert: intent = " + intent);
13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mProximityAlerts.remove(intent);
13769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mProximityAlerts.size() == 0) {
137748f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            removeUpdatesLocked(mProximityReceiver);
137848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            mProximityReceiver = null;
13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mProximityListener = null;
13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     }
13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
13849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return null if the provider does not exits
13859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throw SecurityException if the provider is not allowed to be
13869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * accessed by the caller
13879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Bundle getProviderInfo(String provider) {
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
13902f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return _getProviderInfoLocked(provider);
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
13959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
13969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "_getProviderInfo got exception:", e);
13979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
13989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
13999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Bundle _getProviderInfoLocked(String provider) {
140215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy p = mProvidersByName.get(provider);
14039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
14049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
14059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkPermissionsSafe(provider);
14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bundle b = new Bundle();
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("network", p.requiresNetwork());
14119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("satellite", p.requiresSatellite());
14129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("cell", p.requiresCell());
14139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("cost", p.hasMonetaryCost());
14149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("altitude", p.supportsAltitude());
14159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("speed", p.supportsSpeed());
14169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putBoolean("bearing", p.supportsBearing());
14179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putInt("power", p.getPowerRequirement());
14189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        b.putInt("accuracy", p.getAccuracy());
14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return b;
14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isProviderEnabled(String provider) {
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
14252f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return _isProviderEnabledLocked(provider);
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
14319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "isProviderEnabled got exception:", e);
14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1436275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood    public void reportLocation(Location location) {
1437275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood        if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1438275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood                != PackageManager.PERMISSION_GRANTED) {
1439275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood            throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1440275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood        }
1441275555c8eb3fb5df6e7320873b88b77cdde85a9eMike Lockwood
14424e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
14434e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
14444e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        mLocationHandler.sendMessageAtFrontOfQueue(m);
14454e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood    }
14464e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood
14479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean _isProviderEnabledLocked(String provider) {
14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkPermissionsSafe(provider);
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
145015e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy p = mProvidersByName.get(provider);
14519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
14529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("provider=" + provider);
14539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return isAllowedBySettingsLocked(provider);
14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Location getLastKnownLocation(String provider) {
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        try {
14592f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            synchronized (mLock) {
14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return _getLastKnownLocationLocked(provider);
14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (SecurityException se) {
14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw se;
14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } catch (Exception e) {
14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.e(TAG, "getLastKnownLocation got exception:", e);
14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Location _getLastKnownLocationLocked(String provider) {
14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkPermissionsSafe(provider);
14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
147315e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy p = mProvidersByName.get(provider);
14749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
14759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("provider=" + provider);
14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!isAllowedBySettingsLocked(provider)) {
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Location location = mLastKnownLocation.get(provider);
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (location == null) {
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Get the persistent last known location for the provider
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            location = readLastKnownLocationLocked(provider);
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (location != null) {
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mLastKnownLocation.put(provider, location);
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return location;
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Always broadcast the first update
14969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (lastLoc == null) {
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Don't broadcast same location again regardless of condition
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (loc.getTime() == lastLoc.getTime()) {
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check whether sufficient distance has been traveled
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        double minDistance = record.mMinDistance;
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (minDistance > 0.0) {
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (loc.distanceTo(lastLoc) <= minDistance) {
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15174e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood    private void handleLocationChangedLocked(Location location) {
15184e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        String provider = location.getProvider();
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (records == null || records.size() == 0) {
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
152415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood        LocationProviderProxy p = mProvidersByName.get(provider);
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (p == null) {
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
15279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15294e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        // Update last known location for provider
15304e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        Location lastLocation = mLastKnownLocation.get(provider);
15314e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        if (lastLocation == null) {
15324e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood            mLastKnownLocation.put(provider, new Location(location));
15339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
15344e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood            lastLocation.set(location);
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15364e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood        writeLastKnownLocationLocked(provider, location);
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Fetch latest status update time
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long newStatusUpdateTime = p.getStatusUpdateTime();
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15417ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood       // Get latest status
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bundle extras = new Bundle();
15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int status = p.getStatus(extras);
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ArrayList<Receiver> deadReceivers = null;
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast location or status to all listeners
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int N = records.size();
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i=0; i<N; i++) {
15509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            UpdateRecord r = records.get(i);
15519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Receiver receiver = r.mReceiver;
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15532f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            Location lastLoc = r.mLastFixBroadcast;
15544e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
15554e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                if (lastLoc == null) {
15564e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    lastLoc = new Location(location);
15572f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    r.mLastFixBroadcast = lastLoc;
15584e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                } else {
15594e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    lastLoc.set(location);
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15614e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                if (!receiver.callLocationChangedLocked(location)) {
15624e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
15634e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    if (deadReceivers == null) {
15644e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                        deadReceivers = new ArrayList<Receiver>();
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15664e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    deadReceivers.add(receiver);
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15702f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            long prevStatusUpdateTime = r.mLastStatusBroadcast;
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15742f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                r.mLastStatusBroadcast = newStatusUpdateTime;
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!receiver.callStatusChangedLocked(provider, status, extras)) {
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (deadReceivers == null) {
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        deadReceivers = new ArrayList<Receiver>();
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!deadReceivers.contains(receiver)) {
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        deadReceivers.add(receiver);
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (deadReceivers != null) {
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=deadReceivers.size()-1; i>=0; i--) {
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                removeUpdatesLocked(deadReceivers.get(i));
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class LocationWorkerHandler extends Handler {
15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            try {
15994e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                if (msg.what == MESSAGE_LOCATION_CHANGED) {
16004e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                    // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16022f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                    synchronized (mLock) {
16034e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                        Location location = (Location) msg.obj;
1604fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                        String provider = location.getProvider();
160598cb66797422c4ccdee6f1a07636146d784a471bMike Lockwood
1606fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                        // notify other providers of the new location
1607fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                        for (int i = mProviders.size() - 1; i >= 0; i--) {
1608fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                            LocationProviderProxy proxy = mProviders.get(i);
1609fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                            if (!provider.equals(proxy.getName())) {
1610fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                                proxy.updateLocation(location);
161198cb66797422c4ccdee6f1a07636146d784a471bMike Lockwood                            }
161298cb66797422c4ccdee6f1a07636146d784a471bMike Lockwood                        }
161398cb66797422c4ccdee6f1a07636146d784a471bMike Lockwood
1614fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                        if (isAllowedBySettingsLocked(provider)) {
1615fd6e5f0dda50e113db4ccc55338b6c4f09da37a4Mike Lockwood                            handleLocationChangedLocked(location);
16169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } catch (Exception e) {
16209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Log, don't crash!
16219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16260528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
16270528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        @Override
16280528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        public void onReceive(Context context, Intent intent) {
16299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            String action = intent.getAction();
16309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16310528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
16329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
16332f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                synchronized (mLock) {
16349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
16359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (uid >= 0) {
16369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ArrayList<Receiver> removedRecs = null;
16379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
16389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int j=i.size()-1; j>=0; j--) {
16399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                UpdateRecord ur = i.get(j);
16409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
16419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    if (removedRecs == null) {
16429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        removedRecs = new ArrayList<Receiver>();
16439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    }
16449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    if (!removedRecs.contains(ur.mReceiver)) {
16459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                        removedRecs.add(ur.mReceiver);
16469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    }
16479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
16489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
16499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        ArrayList<ProximityAlert> removedAlerts = null;
16519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        for (ProximityAlert i : mProximityAlerts.values()) {
16529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            if (i.mUid == uid) {
16539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (removedAlerts == null) {
16549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    removedAlerts = new ArrayList<ProximityAlert>();
16559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
16569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                if (!removedAlerts.contains(i)) {
16579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                    removedAlerts.add(i);
16589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
16599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
16609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (removedRecs != null) {
16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int i=removedRecs.size()-1; i>=0; i--) {
16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                removeUpdatesLocked(removedRecs.get(i));
16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (removedAlerts != null) {
16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            for (int i=removedAlerts.size()-1; i>=0; i--) {
16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                removeProximityAlertLocked(removedAlerts.get(i).mIntent);
16699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16730528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
16749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean noConnectivity =
16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!noConnectivity) {
16774df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    mNetworkState = LocationProvider.AVAILABLE;
16784df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                } else {
16794df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                    mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify location providers of current network state
16832f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                synchronized (mLock) {
168415e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                    for (int i = mProviders.size() - 1; i >= 0; i--) {
168515e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood                        LocationProviderProxy provider = mProviders.get(i);
16869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        if (provider.requiresNetwork()) {
16874df2423a947bcd3f024cc3d3a1a315a8dc428598The Android Open Source Project                            provider.updateNetworkState(mNetworkState);
16889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
16899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
16909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
16919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
16929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
16930528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    };
16949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Wake locks
16969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
16970528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood    private void incrementPendingBroadcasts() {
16980528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        synchronized (mWakeLock) {
16990528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            if (mPendingBroadcasts++ == 0) {
17000528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                try {
17010528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    mWakeLock.acquire();
17020528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    log("Acquired wakelock");
17030528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                } catch (Exception e) {
17040528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    // This is to catch a runtime exception thrown when we try to release an
17050528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    // already released lock.
17060528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    Log.e(TAG, "exception in acquireWakeLock()", e);
17070528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                }
17080528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            }
170948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
171048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    }
171148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
171248f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    private void decrementPendingBroadcasts() {
17130528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood        synchronized (mWakeLock) {
171448f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            if (--mPendingBroadcasts == 0) {
17150528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                try {
17160528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    // Release wake lock
17170528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    if (mWakeLock.isHeld()) {
17180528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                        mWakeLock.release();
17190528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                        log("Released wakelock");
17200528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    } else {
17210528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                        log("Can't release wakelock again!");
17220528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    }
17230528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                } catch (Exception e) {
17240528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    // This is to catch a runtime exception thrown when we try to release an
17250528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    // already released lock.
17260528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                    Log.e(TAG, "exception in releaseWakeLock()", e);
17270528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood                }
172848f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            }
172948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood        }
173048f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood    }
173148f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Geocoder
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getFromLocation(double latitude, double longitude, int maxResults,
1735a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            String language, String country, String variant, String appName, List<Address> addrs) {
1736a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        if (mGeocodeProvider != null) {
1737a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            try {
1738a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1739a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                        variant, appName,  addrs);
1740a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            } catch (RemoteException e) {
1741a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                Log.e(TAG, "getFromLocation failed", e);
17423681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                mGeocodeProvider = null;
17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1745a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        return null;
17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1748a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood
17499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String getFromLocationName(String locationName,
1750a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            double lowerLeftLatitude, double lowerLeftLongitude,
1751a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            double upperRightLatitude, double upperRightLongitude, int maxResults,
1752a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            String language, String country, String variant, String appName, List<Address> addrs) {
1753a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood
1754a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        if (mGeocodeProvider != null) {
1755a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            try {
1756a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1757a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                        lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1758a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                        maxResults, language, country, variant, appName, addrs);
1759a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood            } catch (RemoteException e) {
1760a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood                Log.e(TAG, "getFromLocationName failed", e);
17613681f2614fa8c10560c790f6b4287f65d6fd2663Mike Lockwood                mGeocodeProvider = null;
17629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1764a55c321329ae52a2db7a4f2bd36673a20b8f271dMike Lockwood        return null;
17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Mock Providers
17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void checkMockPermissionsSafe() {
17709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
17719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
17729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!allowMocks) {
17739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
17749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PackageManager.PERMISSION_GRANTED) {
17789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
17859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17872f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
17884e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood            MockProvider provider = new MockProvider(name, this,
17894e50b78bda9cd58be61581d2886c88ff6348a1c1Mike Lockwood                requiresNetwork, requiresSatellite,
17909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                requiresCell, hasMonetaryCost, supportsAltitude,
17919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                supportsSpeed, supportsBearing, powerRequirement, accuracy);
179215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            if (mProvidersByName.get(name) != null) {
17939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
17949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
179595427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood
179695427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
179795427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            long identity = Binder.clearCallingIdentity();
179815e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            addProvider(new LocationProviderProxy(name, provider));
17997ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mMockProviders.put(name, provider);
18009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateProvidersLocked();
180195427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            Binder.restoreCallingIdentity(identity);
18029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void removeTestProvider(String provider) {
18069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18072f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18087ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18097ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
181215e3d0f082d551f8819fbe4b0d502cc108627876Mike Lockwood            removeProvider(mProvidersByName.get(provider));
18137ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mMockProviders.remove(mockProvider);
18149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateProvidersLocked();
18159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTestProviderLocation(String provider, Location loc) {
18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18202f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18217ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18227ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
182595427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
182695427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            long identity = Binder.clearCallingIdentity();
18277ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mockProvider.setLocation(loc);
182895427cdbd802f7cb529d62bb79953c45b36a8fcfMike Lockwood            Binder.restoreCallingIdentity(identity);
18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearTestProviderLocation(String provider) {
18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18342f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18357ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18367ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18397ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mockProvider.clearLocation();
18409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTestProviderEnabled(String provider, boolean enabled) {
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18452f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18467ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18477ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (enabled) {
18517ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood                mockProvider.enable();
18529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEnabledProviders.add(provider);
18539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDisabledProviders.remove(provider);
18549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
18557ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood                mockProvider.disable();
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mEnabledProviders.remove(provider);
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDisabledProviders.add(provider);
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateProvidersLocked();
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearTestProviderEnabled(String provider) {
18649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18652f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18667ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18677ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mEnabledProviders.remove(provider);
18719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDisabledProviders.remove(provider);
18729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateProvidersLocked();
18739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
18779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18782f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18797ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18807ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18837ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mockProvider.setStatus(status, extras, updateTime);
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void clearTestProviderStatus(String provider) {
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        checkMockPermissionsSafe();
18892f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
18907ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            MockProvider mockProvider = mMockProviders.get(provider);
18917ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            if (mockProvider == null) {
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
18939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
18947ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood            mockProvider.clearStatus();
18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void log(String log) {
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (Log.isLoggable(TAG, Log.VERBOSE)) {
19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Log.d(TAG, log);
19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                != PackageManager.PERMISSION_GRANTED) {
19070528b9b26a9d64ba43acd0e334638303d514b8ebMike Lockwood            pw.println("Permission Denial: can't dump LocationManagerService from from pid="
19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + Binder.getCallingPid()
19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    + ", uid=" + Binder.getCallingUid());
19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19132f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood        synchronized (mLock) {
19149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("Current Location Manager state:");
19159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  sProvidersLoaded=" + sProvidersLoaded);
19169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  Listeners:");
19172f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            int N = mReceivers.size();
19189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i=0; i<N; i++) {
19192f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                pw.println("    " + mReceivers.get(i));
19209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  Location Listeners:");
19222f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood            for (Receiver i : mReceivers.values()) {
19232f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                pw.println("    " + i + ":");
19242f82c4eb0b4d315481ad79725ad6f52c5ec69685Mike Lockwood                for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
19259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("      " + j.getKey() + ":");
19269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    j.getValue().dump(pw, "        ");
19279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  Records by Provider:");
19309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, ArrayList<UpdateRecord>> i
19319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : mRecordsByProvider.entrySet()) {
19329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("    " + i.getKey() + ":");
19339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (UpdateRecord j : i.getValue()) {
19349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("      " + j + ":");
19359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    j.dump(pw, "        ");
19369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  Last Known Locations:");
19399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (Map.Entry<String, Location> i
19409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    : mLastKnownLocation.entrySet()) {
19419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("    " + i.getKey() + ":");
19429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                i.getValue().dump(new PrintWriterPrinter(pw), "      ");
19439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mProximityAlerts.size() > 0) {
19459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("  Proximity Alerts:");
19469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (Map.Entry<PendingIntent, ProximityAlert> i
19479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        : mProximityAlerts.entrySet()) {
19489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("    " + i.getKey() + ":");
19499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i.getValue().dump(pw, "      ");
19509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mProximitiesEntered.size() > 0) {
19539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("  Proximities Entered:");
19549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (ProximityAlert i : mProximitiesEntered) {
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("    " + i + ":");
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    i.dump(pw, "      ");
19579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
195948f17518223a2917fd82195004fbb206cb9a05a3Mike Lockwood            pw.println("  mProximityReceiver=" + mProximityReceiver);
19609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pw.println("  mProximityListener=" + mProximityListener);
19619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mEnabledProviders.size() > 0) {
19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("  Enabled Providers:");
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (String i : mEnabledProviders) {
19649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("    " + i);
19659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDisabledProviders.size() > 0) {
19699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("  Disabled Providers:");
19709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (String i : mDisabledProviders) {
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pw.println("    " + i);
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mMockProviders.size() > 0) {
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                pw.println("  Mock Providers:");
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
19787ec434e2e179776d75c8a4da66dcfd2ee630c5d8Mike Lockwood                    i.getValue().dump(pw, "      ");
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1984