blob: 468f6967a62da662446678a17a02dc3adaf44faa [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019import android.app.PendingIntent;
Victoria Lease38389b62012-09-30 11:44:22 -070020import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
Victoria Lease38389b62012-09-30 11:44:22 -070024import android.content.IntentFilter;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070025import android.content.pm.ApplicationInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.pm.PackageManager;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070027import android.content.pm.PackageManager.NameNotFoundException;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050028import android.content.res.Resources;
Brian Muramatsubb95cb92012-08-29 10:43:21 -070029import android.database.ContentObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070031import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050032import android.location.GeocoderParams;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070033import android.location.Geofence;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070042import android.location.LocationRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.os.Binder;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070047import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Message;
49import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070050import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.os.RemoteException;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070052import android.os.SystemClock;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070053import android.os.UserHandle;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070054import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
Mike Lockwoode97ae402010-09-29 15:23:46 -040059import com.android.internal.content.PackageMonitor;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070060import com.android.internal.location.ProviderProperties;
61import com.android.internal.location.ProviderRequest;
Mike Lockwood43e33f22010-03-26 10:41:48 -040062import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070063import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GpsLocationProvider;
Nick Pelly4035f5a2012-08-17 14:43:49 -070065import com.android.server.location.LocationBlacklist;
Nick Pelly74fa7ea2012-08-13 19:36:38 -070066import com.android.server.location.LocationFudger;
Mike Lockwood43e33f22010-03-26 10:41:48 -040067import com.android.server.location.LocationProviderInterface;
68import com.android.server.location.LocationProviderProxy;
69import com.android.server.location.MockProvider;
70import com.android.server.location.PassiveProvider;
71
72import java.io.FileDescriptor;
73import java.io.PrintWriter;
74import java.util.ArrayList;
Nick Pelly6fa9ad42012-07-16 12:18:23 -070075import java.util.Arrays;
Mike Lockwood43e33f22010-03-26 10:41:48 -040076import java.util.HashMap;
77import java.util.HashSet;
78import java.util.List;
79import java.util.Map;
Mike Lockwood43e33f22010-03-26 10:41:48 -040080import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Brian Muramatsubb95cb92012-08-29 10:43:21 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
Nick Pelly6fa9ad42012-07-16 12:18:23 -070088 public static final boolean D = false;
89
90 private static final String WAKELOCK_KEY = TAG;
91 private static final String THREAD_NAME = TAG;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
Victoria Lease37425c32012-10-16 16:08:48 -070093 // Location resolution level: no location data whatsoever
94 private static final int RESOLUTION_LEVEL_NONE = 0;
95 // Location resolution level: coarse location data only
96 private static final int RESOLUTION_LEVEL_COARSE = 1;
97 // Location resolution level: fine location data
98 private static final int RESOLUTION_LEVEL_FINE = 2;
99
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String ACCESS_MOCK_LOCATION =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700101 android.Manifest.permission.ACCESS_MOCK_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700103 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400104 private static final String INSTALL_LOCATION_PROVIDER =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700105 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
106
107 private static final String NETWORK_LOCATION_SERVICE_ACTION =
108 "com.android.location.service.v2.NetworkLocationProvider";
109 private static final String FUSED_LOCATION_SERVICE_ACTION =
110 "com.android.location.service.FusedLocationProvider";
111
112 private static final int MSG_LOCATION_CHANGED = 1;
113
Nick Pellyf1be6862012-05-15 10:53:42 -0700114 // Location Providers may sometimes deliver location updates
115 // slightly faster that requested - provide grace period so
116 // we don't unnecessarily filter events that are otherwise on
117 // time
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700118 private static final int MAX_PROVIDER_SCHEDULING_JITTER_MS = 100;
Nick Pellyf1be6862012-05-15 10:53:42 -0700119
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700120 private static final LocationRequest DEFAULT_LOCATION_REQUEST = new LocationRequest();
121
122 private final Context mContext;
123
124 // used internally for synchronization
125 private final Object mLock = new Object();
126
127 // --- fields below are final after init() ---
Nick Pelly74fa7ea2012-08-13 19:36:38 -0700128 private LocationFudger mLocationFudger;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700129 private GeofenceManager mGeofenceManager;
130 private PowerManager.WakeLock mWakeLock;
131 private PackageManager mPackageManager;
132 private GeocoderProxy mGeocodeProvider;
133 private IGpsStatusProvider mGpsStatusProvider;
134 private INetInitiatedListener mNetInitiatedListener;
135 private LocationWorkerHandler mLocationHandler;
Nick Pelly4035f5a2012-08-17 14:43:49 -0700136 private PassiveProvider mPassiveProvider; // track passive provider for special cases
137 private LocationBlacklist mBlacklist;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700138
139 // --- fields below are protected by mWakeLock ---
140 private int mPendingBroadcasts;
141
142 // --- fields below are protected by mLock ---
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 // Set of providers that are explicitly enabled
144 private final Set<String> mEnabledProviders = new HashSet<String>();
145
146 // Set of providers that are explicitly disabled
147 private final Set<String> mDisabledProviders = new HashSet<String>();
148
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700149 // Mock (test) providers
150 private final HashMap<String, MockProvider> mMockProviders =
151 new HashMap<String, MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700153 // all receivers
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400154 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700156 // currently installed providers (with mocks replacing real providers)
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500157 private final ArrayList<LocationProviderInterface> mProviders =
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700158 new ArrayList<LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400159
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700160 // real providers, saved here when mocked out
161 private final HashMap<String, LocationProviderInterface> mRealProviders =
162 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700164 // mapping from provider name to provider
165 private final HashMap<String, LocationProviderInterface> mProvidersByName =
166 new HashMap<String, LocationProviderInterface>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700168 // mapping from provider name to all its UpdateRecords
169 private final HashMap<String, ArrayList<UpdateRecord>> mRecordsByProvider =
170 new HashMap<String, ArrayList<UpdateRecord>>();
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700171
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700172 // mapping from provider name to last known location
173 private final HashMap<String, Location> mLastLocation = new HashMap<String, Location>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700175 // all providers that operate over proxy, for authorizing incoming location
176 private final ArrayList<LocationProviderProxy> mProxyProviders =
177 new ArrayList<LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178
Victoria Lease38389b62012-09-30 11:44:22 -0700179 // current active user on the device - other users are denied location data
180 private int mCurrentUserId = UserHandle.USER_OWNER;
181
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700182 public LocationManagerService(Context context) {
183 super();
184 mContext = context;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800185
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700186 if (D) Log.d(TAG, "Constructed");
187
188 // most startup is deferred until systemReady()
189 }
190
191 public void systemReady() {
192 Thread thread = new Thread(null, this, THREAD_NAME);
193 thread.start();
194 }
195
196 @Override
197 public void run() {
198 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
199 Looper.prepare();
200 mLocationHandler = new LocationWorkerHandler();
201 init();
202 Looper.loop();
203 }
204
205 private void init() {
206 if (D) Log.d(TAG, "init()");
207
208 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
209 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
210 mPackageManager = mContext.getPackageManager();
211
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700212 mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
213 mBlacklist.init();
Victoria Leasedf9ec612012-09-11 15:16:25 -0700214 mLocationFudger = new LocationFudger(mContext, mLocationHandler);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700215
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700216 synchronized (mLock) {
217 loadProvidersLocked();
218 }
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700219
Nick Pelly4035f5a2012-08-17 14:43:49 -0700220 mGeofenceManager = new GeofenceManager(mContext, mBlacklist);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700221
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700222 // listen for settings changes
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700223 mContext.getContentResolver().registerContentObserver(
224 Settings.Secure.getUriFor(Settings.Secure.LOCATION_PROVIDERS_ALLOWED), true,
225 new ContentObserver(mLocationHandler) {
226 @Override
227 public void onChange(boolean selfChange) {
228 synchronized (mLock) {
229 updateProvidersLocked();
230 }
231 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700232 }, UserHandle.USER_ALL);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700233 mPackageMonitor.register(mContext, Looper.myLooper(), true);
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700234
Victoria Lease38389b62012-09-30 11:44:22 -0700235 // listen for user change
236 IntentFilter intentFilter = new IntentFilter();
237 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
238
239 mContext.registerReceiverAsUser(new BroadcastReceiver() {
240 @Override
241 public void onReceive(Context context, Intent intent) {
242 String action = intent.getAction();
243 if (Intent.ACTION_USER_SWITCHED.equals(action)) {
244 switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
245 }
246 }
247 }, UserHandle.ALL, intentFilter, null, null);
248
Brian Muramatsubb95cb92012-08-29 10:43:21 -0700249 updateProvidersLocked();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700250 }
251
252 private void loadProvidersLocked() {
Victoria Lease5c24fd02012-10-01 11:00:50 -0700253 // create a passive location provider, which is always enabled
254 PassiveProvider passiveProvider = new PassiveProvider(this);
255 addProviderLocked(passiveProvider);
256 mEnabledProviders.add(passiveProvider.getName());
257 mPassiveProvider = passiveProvider;
258
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700259 if (GpsLocationProvider.isSupported()) {
260 // Create a gps location provider
261 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
262 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
263 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
264 addProviderLocked(gpsProvider);
265 mRealProviders.put(LocationManager.GPS_PROVIDER, gpsProvider);
266 }
267
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700268 /*
269 Load package name(s) containing location provider support.
270 These packages can contain services implementing location providers:
271 Geocoder Provider, Network Location Provider, and
272 Fused Location Provider. They will each be searched for
273 service components implementing these providers.
274 The location framework also has support for installation
275 of new location providers at run-time. The new package does not
276 have to be explicitly listed here, however it must have a signature
277 that matches the signature of at least one package on this list.
278 */
279 Resources resources = mContext.getResources();
280 ArrayList<String> providerPackageNames = new ArrayList<String>();
281 String[] pkgs1 = resources.getStringArray(
282 com.android.internal.R.array.config_locationProviderPackageNames);
283 String[] pkgs2 = resources.getStringArray(
284 com.android.internal.R.array.config_overlay_locationProviderPackageNames);
285 if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
286 if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
287 if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
288 if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
289
290 // bind to network provider
291 LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
292 mContext,
293 LocationManager.NETWORK_PROVIDER,
294 NETWORK_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700295 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700296 if (networkProvider != null) {
297 mRealProviders.put(LocationManager.NETWORK_PROVIDER, networkProvider);
298 mProxyProviders.add(networkProvider);
299 addProviderLocked(networkProvider);
300 } else {
301 Slog.w(TAG, "no network location provider found");
302 }
303
304 // bind to fused provider
305 LocationProviderProxy fusedLocationProvider = LocationProviderProxy.createAndBind(
306 mContext,
307 LocationManager.FUSED_PROVIDER,
308 FUSED_LOCATION_SERVICE_ACTION,
Victoria Leaseb711d572012-10-02 13:14:11 -0700309 providerPackageNames, mLocationHandler, mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700310 if (fusedLocationProvider != null) {
311 addProviderLocked(fusedLocationProvider);
312 mProxyProviders.add(fusedLocationProvider);
313 mEnabledProviders.add(fusedLocationProvider.getName());
Kenny Rootc3575182012-10-09 12:44:40 -0700314 mRealProviders.put(LocationManager.FUSED_PROVIDER, fusedLocationProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700315 } else {
316 Slog.e(TAG, "no fused location provider found",
317 new IllegalStateException("Location service needs a fused location provider"));
318 }
319
320 // bind to geocoder provider
Victoria Leaseb711d572012-10-02 13:14:11 -0700321 mGeocodeProvider = GeocoderProxy.createAndBind(mContext, providerPackageNames,
322 mCurrentUserId);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700323 if (mGeocodeProvider == null) {
324 Slog.e(TAG, "no geocoder provider found");
325 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700326 }
Mike Lockwood9637d472009-04-02 21:41:57 -0700327
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 /**
Victoria Lease38389b62012-09-30 11:44:22 -0700329 * Called when the device's active user changes.
330 * @param userId the new active user's UserId
331 */
332 private void switchUser(int userId) {
Victoria Lease83762d22012-10-03 13:51:17 -0700333 mBlacklist.switchUser(userId);
Victoria Lease38389b62012-09-30 11:44:22 -0700334 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700335 mLastLocation.clear();
336 for (LocationProviderInterface p : mProviders) {
337 updateProviderListenersLocked(p.getName(), false, mCurrentUserId);
338 p.switchUser(userId);
339 }
Victoria Lease38389b62012-09-30 11:44:22 -0700340 mCurrentUserId = userId;
Victoria Leaseb711d572012-10-02 13:14:11 -0700341 updateProvidersLocked();
Victoria Lease38389b62012-09-30 11:44:22 -0700342 }
343 }
344
345 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
347 * location updates.
348 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700349 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700350 final int mUid; // uid of receiver
351 final int mPid; // pid of receiver
352 final String mPackageName; // package name of receiver
Victoria Lease37425c32012-10-16 16:08:48 -0700353 final int mAllowedResolutionLevel; // resolution level allowed to receiver
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700354
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 final ILocationListener mListener;
356 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 final Object mKey;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700358
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400359 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700360
Mike Lockwood48f17512009-04-23 09:12:08 -0700361 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800362
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700363 Receiver(ILocationListener listener, PendingIntent intent, int pid, int uid,
364 String packageName) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 mListener = listener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 mPendingIntent = intent;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700367 if (listener != null) {
368 mKey = listener.asBinder();
369 } else {
370 mKey = intent;
371 }
Victoria Lease37425c32012-10-16 16:08:48 -0700372 mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700373 mUid = uid;
374 mPid = pid;
375 mPackageName = packageName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 }
377
378 @Override
379 public boolean equals(Object otherObj) {
380 if (otherObj instanceof Receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700381 return mKey.equals(((Receiver)otherObj).mKey);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 }
383 return false;
384 }
385
386 @Override
387 public int hashCode() {
388 return mKey.hashCode();
389 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400390
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 @Override
392 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700393 StringBuilder s = new StringBuilder();
394 s.append("Reciever[");
395 s.append(Integer.toHexString(System.identityHashCode(this)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 if (mListener != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700397 s.append(" listener");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 } else {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700399 s.append(" intent");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800400 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700401 for (String p : mUpdateRecords.keySet()) {
402 s.append(" ").append(mUpdateRecords.get(p).toString());
403 }
404 s.append("]");
405 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 }
407
408 public boolean isListener() {
409 return mListener != null;
410 }
411
412 public boolean isPendingIntent() {
413 return mPendingIntent != null;
414 }
415
416 public ILocationListener getListener() {
417 if (mListener != null) {
418 return mListener;
419 }
420 throw new IllegalStateException("Request for non-existent listener");
421 }
422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
424 if (mListener != null) {
425 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700426 synchronized (this) {
427 // synchronize to ensure incrementPendingBroadcastsLocked()
428 // is called before decrementPendingBroadcasts()
429 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700430 // call this after broadcasting so we do not increment
431 // if we throw an exeption.
432 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800434 } catch (RemoteException e) {
435 return false;
436 }
437 } else {
438 Intent statusChanged = new Intent();
439 statusChanged.putExtras(extras);
440 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
441 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700442 synchronized (this) {
443 // synchronize to ensure incrementPendingBroadcastsLocked()
444 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700445 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700446 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700447 // call this after broadcasting so we do not increment
448 // if we throw an exeption.
449 incrementPendingBroadcastsLocked();
450 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 } catch (PendingIntent.CanceledException e) {
452 return false;
453 }
454 }
455 return true;
456 }
457
458 public boolean callLocationChangedLocked(Location location) {
459 if (mListener != null) {
460 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700461 synchronized (this) {
462 // synchronize to ensure incrementPendingBroadcastsLocked()
463 // is called before decrementPendingBroadcasts()
464 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700465 // call this after broadcasting so we do not increment
466 // if we throw an exeption.
467 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700468 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469 } catch (RemoteException e) {
470 return false;
471 }
472 } else {
473 Intent locationChanged = new Intent();
474 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
475 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700476 synchronized (this) {
477 // synchronize to ensure incrementPendingBroadcastsLocked()
478 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700479 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700480 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700481 // call this after broadcasting so we do not increment
482 // if we throw an exeption.
483 incrementPendingBroadcastsLocked();
484 }
485 } catch (PendingIntent.CanceledException e) {
486 return false;
487 }
488 }
489 return true;
490 }
491
492 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
493 if (mListener != null) {
494 try {
495 synchronized (this) {
496 // synchronize to ensure incrementPendingBroadcastsLocked()
497 // is called before decrementPendingBroadcasts()
498 if (enabled) {
499 mListener.onProviderEnabled(provider);
500 } else {
501 mListener.onProviderDisabled(provider);
502 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700503 // call this after broadcasting so we do not increment
504 // if we throw an exeption.
505 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700506 }
507 } catch (RemoteException e) {
508 return false;
509 }
510 } else {
511 Intent providerIntent = new Intent();
512 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
513 try {
514 synchronized (this) {
515 // synchronize to ensure incrementPendingBroadcastsLocked()
516 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700517 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Victoria Lease37425c32012-10-16 16:08:48 -0700518 getResolutionPermission(mAllowedResolutionLevel));
Mike Lockwood48f17512009-04-23 09:12:08 -0700519 // call this after broadcasting so we do not increment
520 // if we throw an exeption.
521 incrementPendingBroadcastsLocked();
522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 } catch (PendingIntent.CanceledException e) {
524 return false;
525 }
526 }
527 return true;
528 }
529
Nick Pellyf1be6862012-05-15 10:53:42 -0700530 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 public void binderDied() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700532 if (D) Log.d(TAG, "Location listener died");
533
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400534 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 removeUpdatesLocked(this);
536 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700537 synchronized (this) {
538 if (mPendingBroadcasts > 0) {
539 LocationManagerService.this.decrementPendingBroadcasts();
540 mPendingBroadcasts = 0;
541 }
542 }
543 }
544
Nick Pellye0fd6932012-07-11 10:26:13 -0700545 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700546 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
547 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400548 synchronized (this) {
549 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700550 }
551 }
552
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400553 // this must be called while synchronized by caller in a synchronized block
554 // containing the sending of the broadcaset
555 private void incrementPendingBroadcastsLocked() {
556 if (mPendingBroadcasts++ == 0) {
557 LocationManagerService.this.incrementPendingBroadcasts();
558 }
559 }
560
561 private void decrementPendingBroadcastsLocked() {
562 if (--mPendingBroadcasts == 0) {
563 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700564 }
565 }
566 }
567
Nick Pellye0fd6932012-07-11 10:26:13 -0700568 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700569 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400570 //Do not use getReceiver here as that will add the ILocationListener to
571 //the receiver list if it is not found. If it is not found then the
572 //LocationListener was removed when it had a pending broadcast and should
573 //not be added back.
574 IBinder binder = listener.asBinder();
575 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700576 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400577 synchronized (receiver) {
578 // so wakelock calls will succeed
579 long identity = Binder.clearCallingIdentity();
580 receiver.decrementPendingBroadcastsLocked();
581 Binder.restoreCallingIdentity(identity);
582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
584 }
585
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700586 private void addProviderLocked(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400587 mProviders.add(provider);
588 mProvidersByName.put(provider.getName(), provider);
589 }
590
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700591 private void removeProviderLocked(LocationProviderInterface provider) {
592 provider.disable();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400593 mProviders.remove(provider);
594 mProvidersByName.remove(provider.getName());
595 }
596
Mike Lockwood3d12b512009-04-21 23:25:35 -0700597
Victoria Leaseb711d572012-10-02 13:14:11 -0700598 private boolean isAllowedBySettingsLocked(String provider, int userId) {
599 if (userId != mCurrentUserId) {
600 return false;
601 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800602 if (mEnabledProviders.contains(provider)) {
603 return true;
604 }
605 if (mDisabledProviders.contains(provider)) {
606 return false;
607 }
608 // Use system settings
609 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610
Victoria Leaseb711d572012-10-02 13:14:11 -0700611 return Settings.Secure.isLocationProviderEnabledForUser(resolver, provider, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 }
613
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700614 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700615 * Returns the permission string associated with the specified resolution level.
616 *
617 * @param resolutionLevel the resolution level
618 * @return the permission string
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700619 */
Victoria Lease37425c32012-10-16 16:08:48 -0700620 private String getResolutionPermission(int resolutionLevel) {
621 switch (resolutionLevel) {
622 case RESOLUTION_LEVEL_FINE:
623 return android.Manifest.permission.ACCESS_FINE_LOCATION;
624 case RESOLUTION_LEVEL_COARSE:
625 return android.Manifest.permission.ACCESS_COARSE_LOCATION;
626 default:
627 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 }
Victoria Leaseda479c52012-10-15 15:24:16 -0700629 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700630
Victoria Leaseda479c52012-10-15 15:24:16 -0700631 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700632 * Returns the resolution level allowed to the given PID/UID pair.
633 *
634 * @param pid the PID
635 * @param uid the UID
636 * @return resolution level allowed to the pid/uid pair
Victoria Leaseda479c52012-10-15 15:24:16 -0700637 */
Victoria Lease37425c32012-10-16 16:08:48 -0700638 private int getAllowedResolutionLevel(int pid, int uid) {
639 if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
640 pid, uid) == PackageManager.PERMISSION_GRANTED) {
641 return RESOLUTION_LEVEL_FINE;
642 } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
643 pid, uid) == PackageManager.PERMISSION_GRANTED) {
644 return RESOLUTION_LEVEL_COARSE;
645 } else {
646 return RESOLUTION_LEVEL_NONE;
Victoria Leaseda479c52012-10-15 15:24:16 -0700647 }
Victoria Lease4fab68b2012-09-13 13:20:59 -0700648 }
649
650 /**
Victoria Lease37425c32012-10-16 16:08:48 -0700651 * Returns the resolution level allowed to the caller
652 *
653 * @return resolution level allowed to caller
Victoria Lease4fab68b2012-09-13 13:20:59 -0700654 */
Victoria Lease37425c32012-10-16 16:08:48 -0700655 private int getCallerAllowedResolutionLevel() {
656 return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
657 }
658
659 /**
660 * Throw SecurityException if specified resolution level is insufficient to use geofences.
661 *
662 * @param allowedResolutionLevel resolution level allowed to caller
663 */
664 private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
665 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Lease4fab68b2012-09-13 13:20:59 -0700666 throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
667 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 }
669
Victoria Lease37425c32012-10-16 16:08:48 -0700670 /**
671 * Return the minimum resolution level required to use the specified location provider.
672 *
673 * @param provider the name of the location provider
674 * @return minimum resolution level required for provider
675 */
676 private int getMinimumResolutionLevelForProviderUse(String provider) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700677 if (LocationManager.GPS_PROVIDER.equals(provider) ||
678 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
679 // gps and passive providers require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700680 return RESOLUTION_LEVEL_FINE;
Victoria Lease8dbb6342012-09-21 16:55:53 -0700681 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
682 LocationManager.FUSED_PROVIDER.equals(provider)) {
683 // network and fused providers are ok with COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700684 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700685 } else {
686 // mock providers
687 LocationProviderInterface lp = mMockProviders.get(provider);
688 if (lp != null) {
689 ProviderProperties properties = lp.getProperties();
690 if (properties != null) {
691 if (properties.mRequiresSatellite) {
692 // provider requiring satellites require FINE permission
Victoria Lease37425c32012-10-16 16:08:48 -0700693 return RESOLUTION_LEVEL_FINE;
Laurent Tu941221c2012-10-04 14:21:52 -0700694 } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
695 // provider requiring network and or cell require COARSE or FINE
Victoria Lease37425c32012-10-16 16:08:48 -0700696 return RESOLUTION_LEVEL_COARSE;
Laurent Tu941221c2012-10-04 14:21:52 -0700697 }
698 }
699 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700700 }
Victoria Lease37425c32012-10-16 16:08:48 -0700701 return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
Victoria Leaseda479c52012-10-15 15:24:16 -0700702 }
703
Victoria Lease37425c32012-10-16 16:08:48 -0700704 /**
705 * Throw SecurityException if specified resolution level is insufficient to use the named
706 * location provider.
707 *
708 * @param allowedResolutionLevel resolution level allowed to caller
709 * @param providerName the name of the location provider
710 */
711 private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
712 String providerName) {
713 int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
714 if (allowedResolutionLevel < requiredResolutionLevel) {
715 switch (requiredResolutionLevel) {
716 case RESOLUTION_LEVEL_FINE:
717 throw new SecurityException("\"" + providerName + "\" location provider " +
718 "requires ACCESS_FINE_LOCATION permission.");
719 case RESOLUTION_LEVEL_COARSE:
720 throw new SecurityException("\"" + providerName + "\" location provider " +
721 "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
722 default:
723 throw new SecurityException("Insufficient permission for \"" + providerName +
724 "\" location provider.");
Victoria Leaseda479c52012-10-15 15:24:16 -0700725 }
726 }
Victoria Lease8dbb6342012-09-21 16:55:53 -0700727 }
728
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700729 /**
730 * Returns all providers by name, including passive, but excluding
Laurent Tu0d21e212012-10-02 15:33:48 -0700731 * fused, also including ones that are not permitted to
732 * be accessed by the calling activity or are currently disabled.
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700733 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700734 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 public List<String> getAllProviders() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700736 ArrayList<String> out;
737 synchronized (mLock) {
738 out = new ArrayList<String>(mProviders.size());
739 for (LocationProviderInterface provider : mProviders) {
740 String name = provider.getName();
741 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700742 continue;
743 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 out.add(name);
745 }
746 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700747
748 if (D) Log.d(TAG, "getAllProviders()=" + out);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 return out;
750 }
751
Mike Lockwood03ca2162010-04-01 08:10:09 -0700752 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700753 * Return all providers by name, that match criteria and are optionally
754 * enabled.
755 * Can return passive provider, but never returns fused provider.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700756 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700757 @Override
758 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
Victoria Lease37425c32012-10-16 16:08:48 -0700759 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700760 ArrayList<String> out;
Victoria Leaseb711d572012-10-02 13:14:11 -0700761 int callingUserId = UserHandle.getCallingUserId();
762 long identity = Binder.clearCallingIdentity();
763 try {
764 synchronized (mLock) {
765 out = new ArrayList<String>(mProviders.size());
766 for (LocationProviderInterface provider : mProviders) {
767 String name = provider.getName();
768 if (LocationManager.FUSED_PROVIDER.equals(name)) {
Victoria Lease8dbb6342012-09-21 16:55:53 -0700769 continue;
770 }
Victoria Lease37425c32012-10-16 16:08:48 -0700771 if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700772 if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
773 continue;
774 }
775 if (criteria != null && !LocationProvider.propertiesMeetCriteria(
776 name, provider.getProperties(), criteria)) {
777 continue;
778 }
779 out.add(name);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700780 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700781 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700782 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700783 } finally {
784 Binder.restoreCallingIdentity(identity);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700785 }
786
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700787 if (D) Log.d(TAG, "getProviders()=" + out);
788 return out;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700789 }
790
791 /**
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700792 * Return the name of the best provider given a Criteria object.
793 * This method has been deprecated from the public API,
Victoria Lease8dbb6342012-09-21 16:55:53 -0700794 * and the whole LocationProvider (including #meetsCriteria)
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700795 * has been deprecated as well. So this method now uses
796 * some simplified logic.
Mike Lockwood03ca2162010-04-01 08:10:09 -0700797 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700798 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700799 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700800 String result = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700801
802 List<String> providers = getProviders(criteria, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700803 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700804 result = pickBest(providers);
805 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
806 return result;
807 }
808 providers = getProviders(null, enabledOnly);
Victoria Lease8dbb6342012-09-21 16:55:53 -0700809 if (!providers.isEmpty()) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700810 result = pickBest(providers);
811 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
812 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700813 }
814
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700815 if (D) Log.d(TAG, "getBestProvider(" + criteria + ", " + enabledOnly + ")=" + result);
Mike Lockwood03ca2162010-04-01 08:10:09 -0700816 return null;
817 }
818
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700819 private String pickBest(List<String> providers) {
Victoria Lease1925e292012-09-24 17:00:18 -0700820 if (providers.contains(LocationManager.GPS_PROVIDER)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700821 return LocationManager.GPS_PROVIDER;
Victoria Lease1925e292012-09-24 17:00:18 -0700822 } else if (providers.contains(LocationManager.NETWORK_PROVIDER)) {
823 return LocationManager.NETWORK_PROVIDER;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700824 } else {
825 return providers.get(0);
826 }
827 }
828
Nick Pellye0fd6932012-07-11 10:26:13 -0700829 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700830 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
831 LocationProviderInterface p = mProvidersByName.get(provider);
832 if (p == null) {
833 throw new IllegalArgumentException("provider=" + provider);
834 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700835
836 boolean result = LocationProvider.propertiesMeetCriteria(
837 p.getName(), p.getProperties(), criteria);
838 if (D) Log.d(TAG, "providerMeetsCriteria(" + provider + ", " + criteria + ")=" + result);
839 return result;
Mike Lockwood03ca2162010-04-01 08:10:09 -0700840 }
841
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700843 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400844 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500845 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846 boolean isEnabled = p.isEnabled();
847 String name = p.getName();
Victoria Leaseb711d572012-10-02 13:14:11 -0700848 boolean shouldBeEnabled = isAllowedBySettingsLocked(name, mCurrentUserId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849 if (isEnabled && !shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700850 updateProviderListenersLocked(name, false, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700851 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 } else if (!isEnabled && shouldBeEnabled) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700853 updateProviderListenersLocked(name, true, mCurrentUserId);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700854 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700856 }
857 if (changesMade) {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700858 mContext.sendBroadcastAsUser(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION),
859 UserHandle.ALL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860 }
861 }
862
Victoria Leaseb711d572012-10-02 13:14:11 -0700863 private void updateProviderListenersLocked(String provider, boolean enabled, int userId) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 int listeners = 0;
865
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500866 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700867 if (p == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800868
869 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
872 if (records != null) {
873 final int N = records.size();
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700874 for (int i = 0; i < N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 UpdateRecord record = records.get(i);
Victoria Leaseb711d572012-10-02 13:14:11 -0700876 if (UserHandle.getUserId(record.mReceiver.mUid) == userId) {
877 // Sends a notification message to the receiver
878 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
879 if (deadReceivers == null) {
880 deadReceivers = new ArrayList<Receiver>();
881 }
882 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 }
Victoria Leaseb711d572012-10-02 13:14:11 -0700884 listeners++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 }
887 }
888
889 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700890 for (int i = deadReceivers.size() - 1; i >= 0; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 removeUpdatesLocked(deadReceivers.get(i));
892 }
893 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700894
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 if (enabled) {
896 p.enable();
897 if (listeners > 0) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700898 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 }
900 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 }
904
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700905 private void applyRequirementsLocked(String provider) {
906 LocationProviderInterface p = mProvidersByName.get(provider);
907 if (p == null) return;
908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700910 WorkSource worksource = new WorkSource();
911 ProviderRequest providerRequest = new ProviderRequest();
912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 if (records != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700914 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700915 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
916 LocationRequest locationRequest = record.mRequest;
917 providerRequest.locationRequests.add(locationRequest);
918 if (locationRequest.getInterval() < providerRequest.interval) {
919 providerRequest.reportLocation = true;
920 providerRequest.interval = locationRequest.getInterval();
921 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700922 }
923 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700924
925 if (providerRequest.reportLocation) {
926 // calculate who to blame for power
927 // This is somewhat arbitrary. We pick a threshold interval
928 // that is slightly higher that the minimum interval, and
929 // spread the blame across all applications with a request
930 // under that threshold.
931 long thresholdInterval = (providerRequest.interval + 1000) * 3 / 2;
932 for (UpdateRecord record : records) {
Victoria Leaseb711d572012-10-02 13:14:11 -0700933 if (UserHandle.getUserId(record.mReceiver.mUid) == mCurrentUserId) {
934 LocationRequest locationRequest = record.mRequest;
935 if (locationRequest.getInterval() <= thresholdInterval) {
936 worksource.add(record.mReceiver.mUid);
937 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700938 }
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700939 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940 }
941 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700942
943 if (D) Log.d(TAG, "provider request: " + provider + " " + providerRequest);
944 p.setRequest(providerRequest, worksource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800945 }
946
947 private class UpdateRecord {
948 final String mProvider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700949 final LocationRequest mRequest;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800950 final Receiver mReceiver;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400951 Location mLastFixBroadcast;
952 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953
954 /**
955 * Note: must be constructed with lock held.
956 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700957 UpdateRecord(String provider, LocationRequest request, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800958 mProvider = provider;
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700959 mRequest = request;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 mReceiver = receiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961
962 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
963 if (records == null) {
964 records = new ArrayList<UpdateRecord>();
965 mRecordsByProvider.put(provider, records);
966 }
967 if (!records.contains(this)) {
968 records.add(this);
969 }
970 }
971
972 /**
973 * Method to be called when a record will no longer be used. Calling this multiple times
974 * must have the same effect as calling it once.
975 */
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700976 void disposeLocked(boolean removeReceiver) {
977 // remove from mRecordsByProvider
978 ArrayList<UpdateRecord> globalRecords = mRecordsByProvider.get(this.mProvider);
979 if (globalRecords != null) {
980 globalRecords.remove(this);
981 }
982
983 if (!removeReceiver) return; // the caller will handle the rest
984
985 // remove from Receiver#mUpdateRecords
986 HashMap<String, UpdateRecord> receiverRecords = mReceiver.mUpdateRecords;
987 if (receiverRecords != null) {
988 receiverRecords.remove(this.mProvider);
989
990 // and also remove the Receiver if it has no more update records
991 if (removeReceiver && receiverRecords.size() == 0) {
992 removeUpdatesLocked(mReceiver);
993 }
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400994 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 }
996
997 @Override
998 public String toString() {
Nick Pelly6fa9ad42012-07-16 12:18:23 -0700999 StringBuilder s = new StringBuilder();
1000 s.append("UpdateRecord[");
1001 s.append(mProvider);
1002 s.append(' ').append(mReceiver.mPackageName).append('(');
1003 s.append(mReceiver.mUid).append(')');
1004 s.append(' ').append(mRequest);
1005 s.append(']');
1006 return s.toString();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001010 private Receiver getReceiver(ILocationListener listener, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001011 IBinder binder = listener.asBinder();
1012 Receiver receiver = mReceivers.get(binder);
1013 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001014 receiver = new Receiver(listener, null, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001015 mReceivers.put(binder, receiver);
1016
1017 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001018 receiver.getListener().asBinder().linkToDeath(receiver, 0);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001019 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001020 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 return null;
1022 }
1023 }
1024 return receiver;
1025 }
1026
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001027 private Receiver getReceiver(PendingIntent intent, int pid, int uid, String packageName) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001028 Receiver receiver = mReceivers.get(intent);
1029 if (receiver == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001030 receiver = new Receiver(null, intent, pid, uid, packageName);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001031 mReceivers.put(intent, receiver);
1032 }
1033 return receiver;
1034 }
1035
Victoria Lease37425c32012-10-16 16:08:48 -07001036 /**
1037 * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
1038 * and consistency requirements.
1039 *
1040 * @param request the LocationRequest from which to create a sanitized version
1041 * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
1042 * constraints
1043 * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
1044 * @return a version of request that meets the given resolution and consistency requirements
1045 * @hide
1046 */
1047 private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
1048 LocationRequest sanitizedRequest = new LocationRequest(request);
1049 if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
1050 switch (sanitizedRequest.getQuality()) {
Victoria Lease09016ab2012-09-16 12:33:15 -07001051 case LocationRequest.ACCURACY_FINE:
Victoria Lease37425c32012-10-16 16:08:48 -07001052 sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
Victoria Lease09016ab2012-09-16 12:33:15 -07001053 break;
1054 case LocationRequest.POWER_HIGH:
Victoria Lease37425c32012-10-16 16:08:48 -07001055 sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
Victoria Lease09016ab2012-09-16 12:33:15 -07001056 break;
1057 }
1058 // throttle
Victoria Lease37425c32012-10-16 16:08:48 -07001059 if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1060 sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001061 }
Victoria Lease37425c32012-10-16 16:08:48 -07001062 if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
1063 sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
Victoria Lease09016ab2012-09-16 12:33:15 -07001064 }
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001065 }
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001066 // make getFastestInterval() the minimum of interval and fastest interval
Victoria Lease37425c32012-10-16 16:08:48 -07001067 if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001068 request.setFastestInterval(request.getInterval());
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001069 }
Victoria Lease37425c32012-10-16 16:08:48 -07001070 return sanitizedRequest;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001071 }
1072
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001073 private void checkPackageName(String packageName) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001074 if (packageName == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001075 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001076 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001077 int uid = Binder.getCallingUid();
Nick Pellye0fd6932012-07-11 10:26:13 -07001078 String[] packages = mPackageManager.getPackagesForUid(uid);
1079 if (packages == null) {
1080 throw new SecurityException("invalid UID " + uid);
1081 }
1082 for (String pkg : packages) {
1083 if (packageName.equals(pkg)) return;
1084 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001085 throw new SecurityException("invalid package name: " + packageName);
Nick Pellye0fd6932012-07-11 10:26:13 -07001086 }
1087
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001088 private void checkPendingIntent(PendingIntent intent) {
1089 if (intent == null) {
1090 throw new IllegalArgumentException("invalid pending intent: " + intent);
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001091 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001092 }
1093
1094 private Receiver checkListenerOrIntent(ILocationListener listener, PendingIntent intent,
1095 int pid, int uid, String packageName) {
1096 if (intent == null && listener == null) {
1097 throw new IllegalArgumentException("need eiter listener or intent");
1098 } else if (intent != null && listener != null) {
1099 throw new IllegalArgumentException("cannot register both listener and intent");
1100 } else if (intent != null) {
1101 checkPendingIntent(intent);
1102 return getReceiver(intent, pid, uid, packageName);
1103 } else {
1104 return getReceiver(listener, pid, uid, packageName);
1105 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001106 }
1107
Nick Pellye0fd6932012-07-11 10:26:13 -07001108 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001109 public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
1110 PendingIntent intent, String packageName) {
1111 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1112 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001113 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1114 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1115 request.getProvider());
1116 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001117
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001118 final int pid = Binder.getCallingPid();
1119 final int uid = Binder.getCallingUid();
1120 Receiver recevier = checkListenerOrIntent(listener, intent, pid, uid, packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001121
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001122 // providers may use public location API's, need to clear identity
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 long identity = Binder.clearCallingIdentity();
1124 try {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001125 synchronized (mLock) {
Victoria Lease37425c32012-10-16 16:08:48 -07001126 requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 } finally {
1129 Binder.restoreCallingIdentity(identity);
1130 }
1131 }
1132
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001133 private void requestLocationUpdatesLocked(LocationRequest request, Receiver receiver,
1134 int pid, int uid, String packageName) {
1135 // Figure out the provider. Either its explicitly request (legacy use cases), or
1136 // use the fused provider
1137 if (request == null) request = DEFAULT_LOCATION_REQUEST;
1138 String name = request.getProvider();
Victoria Lease09016ab2012-09-16 12:33:15 -07001139 if (name == null) {
1140 throw new IllegalArgumentException("provider name must not be null");
1141 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001142 LocationProviderInterface provider = mProvidersByName.get(name);
1143 if (provider == null) {
1144 throw new IllegalArgumentException("provider doesn't exisit: " + provider);
1145 }
1146
1147 Log.i(TAG, "request " + Integer.toHexString(System.identityHashCode(receiver)) + " " +
1148 name + " " + request + " from " + packageName + "(" + uid + ")");
1149
1150 UpdateRecord record = new UpdateRecord(name, request, receiver);
1151 UpdateRecord oldRecord = receiver.mUpdateRecords.put(name, record);
1152 if (oldRecord != null) {
1153 oldRecord.disposeLocked(false);
1154 }
1155
Victoria Leaseb711d572012-10-02 13:14:11 -07001156 boolean isProviderEnabled = isAllowedBySettingsLocked(name, UserHandle.getUserId(uid));
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001157 if (isProviderEnabled) {
1158 applyRequirementsLocked(name);
1159 } else {
1160 // Notify the listener that updates are currently disabled
1161 receiver.callProviderEnabledLocked(name, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164
Nick Pellye0fd6932012-07-11 10:26:13 -07001165 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001166 public void removeUpdates(ILocationListener listener, PendingIntent intent,
1167 String packageName) {
1168 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001169
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001170 final int pid = Binder.getCallingPid();
1171 final int uid = Binder.getCallingUid();
1172 Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
1173
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001174 // providers may use public location API's, need to clear identity
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001175 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001177 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001178 removeUpdatesLocked(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001179 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001180 } finally {
1181 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 }
1183 }
1184
1185 private void removeUpdatesLocked(Receiver receiver) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001186 Log.i(TAG, "remove " + Integer.toHexString(System.identityHashCode(receiver)));
1187
1188 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1189 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
1190 synchronized (receiver) {
1191 if (receiver.mPendingBroadcasts > 0) {
1192 decrementPendingBroadcasts();
1193 receiver.mPendingBroadcasts = 0;
1194 }
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001198 // Record which providers were associated with this listener
1199 HashSet<String> providers = new HashSet<String>();
1200 HashMap<String, UpdateRecord> oldRecords = receiver.mUpdateRecords;
1201 if (oldRecords != null) {
1202 // Call dispose() on the obsolete update records.
1203 for (UpdateRecord record : oldRecords.values()) {
1204 record.disposeLocked(false);
1205 }
1206 // Accumulate providers
1207 providers.addAll(oldRecords.keySet());
1208 }
1209
1210 // update provider
1211 for (String provider : providers) {
1212 // If provider is already disabled, don't need to do anything
Victoria Leaseb711d572012-10-02 13:14:11 -07001213 if (!isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001214 continue;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001217 applyRequirementsLocked(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 }
1219 }
1220
Nick Pellye0fd6932012-07-11 10:26:13 -07001221 @Override
Nick Pelly4035f5a2012-08-17 14:43:49 -07001222 public Location getLastLocation(LocationRequest request, String packageName) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001223 if (D) Log.d(TAG, "getLastLocation: " + request);
1224 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001225 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
Nick Pelly4035f5a2012-08-17 14:43:49 -07001226 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001227 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1228 request.getProvider());
1229 // no need to sanitize this request, as only the provider name is used
Nick Pelly4035f5a2012-08-17 14:43:49 -07001230
Victoria Leaseb711d572012-10-02 13:14:11 -07001231 long identity = Binder.clearCallingIdentity();
1232 try {
1233 if (mBlacklist.isBlacklisted(packageName)) {
1234 if (D) Log.d(TAG, "not returning last loc for blacklisted app: " +
1235 packageName);
Victoria Lease09016ab2012-09-16 12:33:15 -07001236 return null;
1237 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001238
1239 synchronized (mLock) {
1240 // Figure out the provider. Either its explicitly request (deprecated API's),
1241 // or use the fused provider
1242 String name = request.getProvider();
1243 if (name == null) name = LocationManager.FUSED_PROVIDER;
1244 LocationProviderInterface provider = mProvidersByName.get(name);
1245 if (provider == null) return null;
1246
1247 if (!isAllowedBySettingsLocked(name, mCurrentUserId)) return null;
1248
1249 Location location = mLastLocation.get(name);
1250 if (location == null) {
1251 return null;
1252 }
Victoria Lease37425c32012-10-16 16:08:48 -07001253 if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001254 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1255 if (noGPSLocation != null) {
1256 return mLocationFudger.getOrCreate(noGPSLocation);
1257 }
Victoria Lease37425c32012-10-16 16:08:48 -07001258 } else {
1259 return location;
Victoria Lease09016ab2012-09-16 12:33:15 -07001260 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001261 }
Victoria Leaseb711d572012-10-02 13:14:11 -07001262 return null;
1263 } finally {
1264 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001265 }
1266 }
1267
1268 @Override
1269 public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
1270 String packageName) {
1271 if (request == null) request = DEFAULT_LOCATION_REQUEST;
Victoria Lease37425c32012-10-16 16:08:48 -07001272 int allowedResolutionLevel = getCallerAllowedResolutionLevel();
1273 checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001274 checkPendingIntent(intent);
1275 checkPackageName(packageName);
Victoria Lease37425c32012-10-16 16:08:48 -07001276 checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
1277 request.getProvider());
1278 LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001279
Victoria Lease37425c32012-10-16 16:08:48 -07001280 if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001281
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001282 // geo-fence manager uses the public location API, need to clear identity
1283 int uid = Binder.getCallingUid();
1284 long identity = Binder.clearCallingIdentity();
1285 try {
Victoria Lease37425c32012-10-16 16:08:48 -07001286 mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001287 } finally {
1288 Binder.restoreCallingIdentity(identity);
1289 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001290 }
1291
1292 @Override
1293 public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
Victoria Lease37425c32012-10-16 16:08:48 -07001294 checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001295 checkPendingIntent(intent);
1296 checkPackageName(packageName);
1297
1298 if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
1299
Nick Pelly2b7a0d02012-08-17 15:09:44 -07001300 // geo-fence manager uses the public location API, need to clear identity
1301 long identity = Binder.clearCallingIdentity();
1302 try {
1303 mGeofenceManager.removeFence(geofence, intent);
1304 } finally {
1305 Binder.restoreCallingIdentity(identity);
1306 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001307 }
1308
1309
1310 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001312 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001313 return false;
1314 }
Victoria Lease37425c32012-10-16 16:08:48 -07001315 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1316 LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317
1318 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001319 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001321 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 return false;
1323 }
1324 return true;
1325 }
1326
Nick Pellye0fd6932012-07-11 10:26:13 -07001327 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001329 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001330 try {
1331 mGpsStatusProvider.removeGpsStatusListener(listener);
1332 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001333 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001335 }
1336 }
1337
Nick Pellye0fd6932012-07-11 10:26:13 -07001338 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001339 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001340 if (provider == null) {
1341 // throw NullPointerException to remain compatible with previous implementation
1342 throw new NullPointerException();
1343 }
Victoria Lease37425c32012-10-16 16:08:48 -07001344 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1345 provider);
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001346
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001347 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001348 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001349 != PackageManager.PERMISSION_GRANTED)) {
1350 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1351 }
1352
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001353 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001354 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001355 if (p == null) return false;
Nick Pellye0fd6932012-07-11 10:26:13 -07001356
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001357 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 }
1359 }
1360
Nick Pellye0fd6932012-07-11 10:26:13 -07001361 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001362 public boolean sendNiResponse(int notifId, int userResponse) {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001363 if (Binder.getCallingUid() != Process.myUid()) {
1364 throw new SecurityException(
1365 "calling sendNiResponse from outside of the system is not allowed");
1366 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001367 try {
1368 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001369 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001370 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001371 return false;
1372 }
1373 }
1374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001376 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001377 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 * accessed by the caller
1379 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001380 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001381 public ProviderProperties getProviderProperties(String provider) {
Laurent Tub7f9d252012-10-16 14:25:00 -07001382 if (mProvidersByName.get(provider) == null) {
1383 return null;
1384 }
1385
Victoria Lease37425c32012-10-16 16:08:48 -07001386 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1387 provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001389 LocationProviderInterface p;
1390 synchronized (mLock) {
1391 p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 }
1393
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001394 if (p == null) return null;
1395 return p.getProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 }
1397
Nick Pellye0fd6932012-07-11 10:26:13 -07001398 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001399 public boolean isProviderEnabled(String provider) {
Victoria Lease37425c32012-10-16 16:08:48 -07001400 checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
1401 provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001402 if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
1403
Victoria Leaseb711d572012-10-02 13:14:11 -07001404 long identity = Binder.clearCallingIdentity();
1405 try {
1406 synchronized (mLock) {
1407 LocationProviderInterface p = mProvidersByName.get(provider);
1408 if (p == null) return false;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001409
Victoria Leaseb711d572012-10-02 13:14:11 -07001410 return isAllowedBySettingsLocked(provider, mCurrentUserId);
1411 }
1412 } finally {
1413 Binder.restoreCallingIdentity(identity);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001414 }
1415 }
1416
1417 private void checkCallerIsProvider() {
1418 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1419 == PackageManager.PERMISSION_GRANTED) {
1420 return;
1421 }
1422
1423 // Previously we only used the INSTALL_LOCATION_PROVIDER
1424 // check. But that is system or signature
1425 // protection level which is not flexible enough for
1426 // providers installed oustide the system image. So
1427 // also allow providers with a UID matching the
1428 // currently bound package name
1429
1430 int uid = Binder.getCallingUid();
1431
1432 if (mGeocodeProvider != null) {
1433 if (doesPackageHaveUid(uid, mGeocodeProvider.getConnectedPackageName())) return;
1434 }
1435 for (LocationProviderProxy proxy : mProxyProviders) {
1436 if (doesPackageHaveUid(uid, proxy.getConnectedPackageName())) return;
1437 }
1438 throw new SecurityException("need INSTALL_LOCATION_PROVIDER permission, " +
1439 "or UID of a currently bound location provider");
1440 }
1441
1442 private boolean doesPackageHaveUid(int uid, String packageName) {
1443 if (packageName == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 return false;
1445 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001446 try {
1447 ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, 0);
1448 if (appInfo.uid != uid) {
1449 return false;
1450 }
1451 } catch (NameNotFoundException e) {
1452 return false;
1453 }
1454 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455 }
1456
Nick Pellye0fd6932012-07-11 10:26:13 -07001457 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001458 public void reportLocation(Location location, boolean passive) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001459 checkCallerIsProvider();
Mike Lockwood275555c2009-05-01 11:30:34 -04001460
Nick Pelly2eeeec22012-07-18 13:13:37 -07001461 if (!location.isComplete()) {
1462 Log.w(TAG, "Dropping incomplete location: " + location);
1463 return;
1464 }
1465
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001466 mLocationHandler.removeMessages(MSG_LOCATION_CHANGED, location);
1467 Message m = Message.obtain(mLocationHandler, MSG_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001468 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001469 mLocationHandler.sendMessageAtFrontOfQueue(m);
1470 }
1471
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472
1473 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1474 // Always broadcast the first update
1475 if (lastLoc == null) {
1476 return true;
1477 }
1478
Nick Pellyf1be6862012-05-15 10:53:42 -07001479 // Check whether sufficient time has passed
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001480 long minTime = record.mRequest.getFastestInterval();
Philip Milne41180122012-09-26 11:29:25 -07001481 long delta = (loc.getElapsedRealtimeNanos() - lastLoc.getElapsedRealtimeNanos()) / 1000000L;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001482 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER_MS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 return false;
1484 }
1485
1486 // Check whether sufficient distance has been traveled
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001487 double minDistance = record.mRequest.getSmallestDisplacement();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 if (minDistance > 0.0) {
1489 if (loc.distanceTo(lastLoc) <= minDistance) {
1490 return false;
1491 }
1492 }
1493
1494 return true;
1495 }
1496
Mike Lockwooda4903f22010-02-17 06:42:23 -05001497 private void handleLocationChangedLocked(Location location, boolean passive) {
Nick Pelly4e31c4f2012-08-13 19:35:39 -07001498 if (D) Log.d(TAG, "incoming location: " + location);
1499
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001500 long now = SystemClock.elapsedRealtime();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001501 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502
Laurent Tu60ec50a2012-10-04 17:00:10 -07001503 // Skip if the provider is unknown.
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001504 LocationProviderInterface p = mProvidersByName.get(provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001505 if (p == null) return;
1506
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001507 // Update last known locations
Victoria Lease09016ab2012-09-16 12:33:15 -07001508 Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1509 Location lastNoGPSLocation = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001510 Location lastLocation = mLastLocation.get(provider);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001511 if (lastLocation == null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001512 lastLocation = new Location(provider);
1513 mLastLocation.put(provider, lastLocation);
Victoria Lease09016ab2012-09-16 12:33:15 -07001514 } else {
1515 lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
1516 if (noGPSLocation == null && lastNoGPSLocation != null) {
1517 // New location has no no-GPS location: adopt last no-GPS location. This is set
1518 // directly into location because we do not want to notify COARSE clients.
1519 location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
1520 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001521 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001522 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523
Laurent Tu60ec50a2012-10-04 17:00:10 -07001524 // Skip if there are no UpdateRecords for this provider.
1525 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1526 if (records == null || records.size() == 0) return;
1527
Victoria Lease09016ab2012-09-16 12:33:15 -07001528 // Fetch coarse location
1529 Location coarseLocation = null;
1530 if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
1531 coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
1532 }
1533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 // Fetch latest status update time
1535 long newStatusUpdateTime = p.getStatusUpdateTime();
1536
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001537 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 Bundle extras = new Bundle();
1539 int status = p.getStatus(extras);
1540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 ArrayList<Receiver> deadReceivers = null;
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001542 ArrayList<UpdateRecord> deadUpdateRecords = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001544 // Broadcast location or status to all listeners
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001545 for (UpdateRecord r : records) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001547 boolean receiverDead = false;
Nick Pelly4035f5a2012-08-17 14:43:49 -07001548
Victoria Leaseb711d572012-10-02 13:14:11 -07001549 int receiverUserId = UserHandle.getUserId(receiver.mUid);
1550 if (receiverUserId != mCurrentUserId) {
1551 if (D) {
1552 Log.d(TAG, "skipping loc update for background user " + receiverUserId +
1553 " (current user: " + mCurrentUserId + ", app: " +
1554 receiver.mPackageName + ")");
1555 }
1556 continue;
1557 }
1558
Nick Pelly4035f5a2012-08-17 14:43:49 -07001559 if (mBlacklist.isBlacklisted(receiver.mPackageName)) {
1560 if (D) Log.d(TAG, "skipping loc update for blacklisted app: " +
1561 receiver.mPackageName);
1562 continue;
1563 }
1564
Victoria Lease09016ab2012-09-16 12:33:15 -07001565 Location notifyLocation = null;
Victoria Lease37425c32012-10-16 16:08:48 -07001566 if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
1567 notifyLocation = coarseLocation; // use coarse location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001568 } else {
Victoria Lease37425c32012-10-16 16:08:48 -07001569 notifyLocation = lastLocation; // use fine location
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001570 }
Victoria Lease09016ab2012-09-16 12:33:15 -07001571 if (notifyLocation != null) {
1572 Location lastLoc = r.mLastFixBroadcast;
1573 if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
1574 if (lastLoc == null) {
1575 lastLoc = new Location(notifyLocation);
1576 r.mLastFixBroadcast = lastLoc;
1577 } else {
1578 lastLoc.set(notifyLocation);
1579 }
1580 if (!receiver.callLocationChangedLocked(notifyLocation)) {
1581 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1582 receiverDead = true;
1583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
1585 }
1586
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001587 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
Victoria Lease09016ab2012-09-16 12:33:15 -07001589 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001591 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001593 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001594 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001595 }
1596 }
1597
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001598 // track expired records
1599 if (r.mRequest.getNumUpdates() == 0 || r.mRequest.getExpireAt() < now) {
1600 if (deadUpdateRecords == null) {
1601 deadUpdateRecords = new ArrayList<UpdateRecord>();
1602 }
1603 deadUpdateRecords.add(r);
1604 }
1605 // track dead receivers
1606 if (receiverDead) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001607 if (deadReceivers == null) {
1608 deadReceivers = new ArrayList<Receiver>();
1609 }
1610 if (!deadReceivers.contains(receiver)) {
1611 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 }
1613 }
1614 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001615
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001616 // remove dead records and receivers outside the loop
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 if (deadReceivers != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001618 for (Receiver receiver : deadReceivers) {
1619 removeUpdatesLocked(receiver);
1620 }
1621 }
1622 if (deadUpdateRecords != null) {
1623 for (UpdateRecord r : deadUpdateRecords) {
1624 r.disposeLocked(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625 }
1626 }
1627 }
1628
1629 private class LocationWorkerHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 @Override
1631 public void handleMessage(Message msg) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001632 switch (msg.what) {
1633 case MSG_LOCATION_CHANGED:
1634 handleLocationChanged((Location) msg.obj, msg.arg1 == 1);
1635 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 }
1637 }
1638 }
1639
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001640 private void handleLocationChanged(Location location, boolean passive) {
1641 String provider = location.getProvider();
Jeff Sharkey5e613312012-01-30 11:16:20 -08001642
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001643 if (!passive) {
1644 // notify passive provider of the new location
1645 mPassiveProvider.updateLocation(location);
1646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001648 synchronized (mLock) {
Victoria Leaseb711d572012-10-02 13:14:11 -07001649 if (isAllowedBySettingsLocked(provider, mCurrentUserId)) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001650 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654
Mike Lockwoode97ae402010-09-29 15:23:46 -04001655 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1656 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001657 public void onPackageDisappeared(String packageName, int reason) {
1658 // remove all receivers associated with this package name
1659 synchronized (mLock) {
1660 ArrayList<Receiver> deadReceivers = null;
1661
1662 for (Receiver receiver : mReceivers.values()) {
1663 if (receiver.mPackageName.equals(packageName)) {
1664 if (deadReceivers == null) {
1665 deadReceivers = new ArrayList<Receiver>();
1666 }
1667 deadReceivers.add(receiver);
1668 }
1669 }
1670
1671 // perform removal outside of mReceivers loop
1672 if (deadReceivers != null) {
1673 for (Receiver receiver : deadReceivers) {
1674 removeUpdatesLocked(receiver);
1675 }
1676 }
1677 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001678 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001679 };
1680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001681 // Wake locks
1682
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001683 private void incrementPendingBroadcasts() {
1684 synchronized (mWakeLock) {
1685 if (mPendingBroadcasts++ == 0) {
1686 try {
1687 mWakeLock.acquire();
1688 log("Acquired wakelock");
1689 } catch (Exception e) {
1690 // This is to catch a runtime exception thrown when we try to release an
1691 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001692 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001693 }
1694 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001695 }
1696 }
1697
1698 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001699 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001700 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001701 try {
1702 // Release wake lock
1703 if (mWakeLock.isHeld()) {
1704 mWakeLock.release();
1705 log("Released wakelock");
1706 } else {
1707 log("Can't release wakelock again!");
1708 }
1709 } catch (Exception e) {
1710 // This is to catch a runtime exception thrown when we try to release an
1711 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001712 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001713 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001714 }
1715 }
1716 }
1717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001718 // Geocoder
1719
Nick Pellye0fd6932012-07-11 10:26:13 -07001720 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001721 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001722 return mGeocodeProvider != null;
1723 }
1724
Nick Pellye0fd6932012-07-11 10:26:13 -07001725 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001727 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001728 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001729 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1730 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001732 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
1734
Mike Lockwooda55c3212009-04-15 11:10:11 -04001735
Nick Pellye0fd6932012-07-11 10:26:13 -07001736 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001738 double lowerLeftLatitude, double lowerLeftLongitude,
1739 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001740 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001741
1742 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001743 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1744 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1745 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001747 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
1749
1750 // Mock Providers
1751
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 private void checkMockPermissionsSafe() {
1753 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1754 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1755 if (!allowMocks) {
1756 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1757 }
1758
1759 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1760 PackageManager.PERMISSION_GRANTED) {
1761 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 }
1764
Nick Pellye0fd6932012-07-11 10:26:13 -07001765 @Override
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001766 public void addTestProvider(String name, ProviderProperties properties) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 checkMockPermissionsSafe();
1768
Mike Lockwooda4903f22010-02-17 06:42:23 -05001769 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1770 throw new IllegalArgumentException("Cannot mock the passive location provider");
1771 }
1772
Mike Lockwood86328a92009-10-23 08:38:25 -04001773 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001774 synchronized (mLock) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001775 MockProvider provider = new MockProvider(name, this, properties);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001776 // remove the real provider if we are replacing GPS or network provider
1777 if (LocationManager.GPS_PROVIDER.equals(name)
Nick Pelly1332b532012-08-21 16:25:47 -07001778 || LocationManager.NETWORK_PROVIDER.equals(name)
1779 || LocationManager.FUSED_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001780 LocationProviderInterface p = mProvidersByName.get(name);
1781 if (p != null) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001782 removeProviderLocked(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001783 }
1784 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001785 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1787 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001788 addProviderLocked(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001789 mMockProviders.put(name, provider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001790 mLastLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001791 updateProvidersLocked();
1792 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001793 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 }
1795
Nick Pellye0fd6932012-07-11 10:26:13 -07001796 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797 public void removeTestProvider(String provider) {
1798 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001799 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001800 MockProvider mockProvider = mMockProviders.get(provider);
1801 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1803 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001804 long identity = Binder.clearCallingIdentity();
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001805 removeProviderLocked(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001806 mMockProviders.remove(mockProvider);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001807
1808 // reinstate real provider if available
1809 LocationProviderInterface realProvider = mRealProviders.get(provider);
1810 if (realProvider != null) {
1811 addProviderLocked(realProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001812 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001813 mLastLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001815 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 }
1817 }
1818
Nick Pellye0fd6932012-07-11 10:26:13 -07001819 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 public void setTestProviderLocation(String provider, Location loc) {
1821 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001822 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001823 MockProvider mockProvider = mMockProviders.get(provider);
1824 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001825 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1826 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001827 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1828 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001829 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001830 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 }
1832 }
1833
Nick Pellye0fd6932012-07-11 10:26:13 -07001834 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 public void clearTestProviderLocation(String provider) {
1836 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001837 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001838 MockProvider mockProvider = mMockProviders.get(provider);
1839 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1841 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001842 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 }
1844 }
1845
Nick Pellye0fd6932012-07-11 10:26:13 -07001846 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 public void setTestProviderEnabled(String provider, boolean enabled) {
1848 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001849 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001850 MockProvider mockProvider = mMockProviders.get(provider);
1851 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1853 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001854 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001856 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001857 mEnabledProviders.add(provider);
1858 mDisabledProviders.remove(provider);
1859 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001860 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 mEnabledProviders.remove(provider);
1862 mDisabledProviders.add(provider);
1863 }
1864 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001865 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 }
1868
Nick Pellye0fd6932012-07-11 10:26:13 -07001869 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 public void clearTestProviderEnabled(String provider) {
1871 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001872 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001873 MockProvider mockProvider = mMockProviders.get(provider);
1874 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1876 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001877 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 mEnabledProviders.remove(provider);
1879 mDisabledProviders.remove(provider);
1880 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001881 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 }
1883 }
1884
Nick Pellye0fd6932012-07-11 10:26:13 -07001885 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1887 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001888 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001889 MockProvider mockProvider = mMockProviders.get(provider);
1890 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1892 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001893 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 }
1895 }
1896
Nick Pellye0fd6932012-07-11 10:26:13 -07001897 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001898 public void clearTestProviderStatus(String provider) {
1899 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001900 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001901 MockProvider mockProvider = mMockProviders.get(provider);
1902 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1904 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001905 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
1907 }
1908
1909 private void log(String log) {
1910 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001911 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 }
1913 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001914
1915 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001916 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1917 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1918 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001919 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 + Binder.getCallingPid()
1921 + ", uid=" + Binder.getCallingUid());
1922 return;
1923 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001924
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001925 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 pw.println("Current Location Manager state:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 pw.println(" Location Listeners:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001928 for (Receiver receiver : mReceivers.values()) {
1929 pw.println(" " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 pw.println(" Records by Provider:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001932 for (Map.Entry<String, ArrayList<UpdateRecord>> entry : mRecordsByProvider.entrySet()) {
1933 pw.println(" " + entry.getKey() + ":");
1934 for (UpdateRecord record : entry.getValue()) {
1935 pw.println(" " + record);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001936 }
1937 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 pw.println(" Last Known Locations:");
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001939 for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
1940 String provider = entry.getKey();
1941 Location location = entry.getValue();
1942 pw.println(" " + provider + ": " + location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001943 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001944
Nick Pellye0fd6932012-07-11 10:26:13 -07001945 mGeofenceManager.dump(pw);
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 if (mEnabledProviders.size() > 0) {
1948 pw.println(" Enabled Providers:");
1949 for (String i : mEnabledProviders) {
1950 pw.println(" " + i);
1951 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 }
1954 if (mDisabledProviders.size() > 0) {
1955 pw.println(" Disabled Providers:");
1956 for (String i : mDisabledProviders) {
1957 pw.println(" " + i);
1958 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 }
Nick Pelly4035f5a2012-08-17 14:43:49 -07001960 pw.append(" ");
1961 mBlacklist.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 if (mMockProviders.size() > 0) {
1963 pw.println(" Mock Providers:");
1964 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001965 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 }
1967 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001968
Nick Pelly74fa7ea2012-08-13 19:36:38 -07001969 pw.append(" fudger: ");
1970 mLocationFudger.dump(fd, pw, args);
1971
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001972 if (args.length > 0 && "short".equals(args[0])) {
1973 return;
1974 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001975 for (LocationProviderInterface provider: mProviders) {
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001976 pw.print(provider.getName() + " Internal State");
1977 if (provider instanceof LocationProviderProxy) {
1978 LocationProviderProxy proxy = (LocationProviderProxy) provider;
1979 pw.print(" (" + proxy.getConnectedPackageName() + ")");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001980 }
Nick Pelly6fa9ad42012-07-16 12:18:23 -07001981 pw.println(":");
1982 provider.dump(fd, pw, args);
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001983 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 }
1985 }
1986}