blob: d679a5e97616a42e54f648a87031a966c59e80b4 [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 java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import java.io.PrintWriter;
21import java.util.ArrayList;
22import java.util.HashMap;
23import java.util.HashSet;
24import java.util.List;
25import java.util.Map;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070026import java.util.Observable;
27import java.util.Observer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.app.PendingIntent;
31import android.content.BroadcastReceiver;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070032import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.content.ContentResolver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.pm.PackageManager;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070038import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Address;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070040import android.location.IGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.location.IGpsStatusListener;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070042import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.location.ILocationListener;
44import android.location.ILocationManager;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070045import android.location.ILocationProvider;
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -080046import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047import android.location.Location;
48import android.location.LocationManager;
49import android.location.LocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.net.ConnectivityManager;
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -080051import android.net.NetworkInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.Binder;
54import android.os.Bundle;
55import android.os.Handler;
56import android.os.IBinder;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070057import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Message;
59import android.os.PowerManager;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070060import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.os.RemoteException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.util.Log;
64import android.util.PrintWriterPrinter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import com.android.internal.location.GpsLocationProvider;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070067import com.android.internal.location.LocationProviderProxy;
68import com.android.internal.location.MockProvider;
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -080069import com.android.internal.location.GpsNetInitiatedHandler;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070
71/**
72 * The service class that manages LocationProviders and issues location
73 * updates and alerts.
74 *
75 * {@hide}
76 */
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070077public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078 private static final String TAG = "LocationManagerService";
The Android Open Source Project10592532009-03-18 17:39:46 -070079 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081 // The last time a location was written, by provider name.
82 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
83
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 private static final String ACCESS_FINE_LOCATION =
85 android.Manifest.permission.ACCESS_FINE_LOCATION;
86 private static final String ACCESS_COARSE_LOCATION =
87 android.Manifest.permission.ACCESS_COARSE_LOCATION;
88 private static final String ACCESS_MOCK_LOCATION =
89 android.Manifest.permission.ACCESS_MOCK_LOCATION;
90 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
91 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -070092 private static final String INSTALL_LOCATION_PROVIDER =
93 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080094
95 // Set of providers that are explicitly enabled
96 private final Set<String> mEnabledProviders = new HashSet<String>();
97
98 // Set of providers that are explicitly disabled
99 private final Set<String> mDisabledProviders = new HashSet<String>();
100
101 // Locations, status values, and extras for mock providers
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700102 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
104 private static boolean sProvidersLoaded = false;
105
106 private final Context mContext;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700107 private IGeocodeProvider mGeocodeProvider;
108 private IGpsStatusProvider mGpsStatusProvider;
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -0800109 private INetInitiatedListener mNetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private LocationWorkerHandler mLocationHandler;
111
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700112 // Cache the real providers for use in addTestProvider() and removeTestProvider()
113 LocationProviderProxy mNetworkLocationProvider;
114 LocationProviderProxy mGpsLocationProvider;
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 // Handler messages
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700117 private static final int MESSAGE_LOCATION_CHANGED = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700119 // wakelock variables
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 private final static String WAKELOCK_KEY = "LocationManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private PowerManager.WakeLock mWakeLock = null;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700122 private int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
124 /**
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700125 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 */
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700127 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 /**
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700131 * List of location providers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 */
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700133 private final ArrayList<LocationProviderProxy> mProviders =
134 new ArrayList<LocationProviderProxy>();
135 private final HashMap<String, LocationProviderProxy> mProvidersByName
136 = new HashMap<String, LocationProviderProxy>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137
138 /**
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700139 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 */
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700141 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
143 /**
144 * Mapping from provider name to all its UpdateRecords
145 */
146 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
147 new HashMap<String,ArrayList<UpdateRecord>>();
148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800149 // Proximity listeners
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700150 private Receiver mProximityReceiver = null;
151 private ILocationListener mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
153 new HashMap<PendingIntent,ProximityAlert>();
154 private HashSet<ProximityAlert> mProximitiesEntered =
155 new HashSet<ProximityAlert>();
156
157 // Last known location for each provider
158 private HashMap<String,Location> mLastKnownLocation =
159 new HashMap<String,Location>();
160
The Android Open Source Project4df24232009-03-05 14:34:35 -0800161 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700162
163 // for Settings change notification
164 private ContentQueryMap mSettings;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 /**
167 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
168 * location updates.
169 */
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700170 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 final ILocationListener mListener;
172 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 final Object mKey;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700174 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
175 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700177 Receiver(ILocationListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 mListener = listener;
179 mPendingIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 mKey = listener.asBinder();
181 }
182
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700183 Receiver(PendingIntent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 mPendingIntent = intent;
185 mListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 mKey = intent;
187 }
188
189 @Override
190 public boolean equals(Object otherObj) {
191 if (otherObj instanceof Receiver) {
192 return mKey.equals(
193 ((Receiver)otherObj).mKey);
194 }
195 return false;
196 }
197
198 @Override
199 public int hashCode() {
200 return mKey.hashCode();
201 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800203 @Override
204 public String toString() {
205 if (mListener != null) {
206 return "Receiver{"
207 + Integer.toHexString(System.identityHashCode(this))
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700208 + " Listener " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 } else {
210 return "Receiver{"
211 + Integer.toHexString(System.identityHashCode(this))
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700212 + " Intent " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 }
214 }
215
216 public boolean isListener() {
217 return mListener != null;
218 }
219
220 public boolean isPendingIntent() {
221 return mPendingIntent != null;
222 }
223
224 public ILocationListener getListener() {
225 if (mListener != null) {
226 return mListener;
227 }
228 throw new IllegalStateException("Request for non-existent listener");
229 }
230
231 public PendingIntent getPendingIntent() {
232 if (mPendingIntent != null) {
233 return mPendingIntent;
234 }
235 throw new IllegalStateException("Request for non-existent intent");
236 }
237
238 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
239 if (mListener != null) {
240 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700241 synchronized (this) {
242 // synchronize to ensure incrementPendingBroadcastsLocked()
243 // is called before decrementPendingBroadcasts()
244 mListener.onStatusChanged(provider, status, extras);
245 if (mListener != mProximityListener) {
246 // call this after broadcasting so we do not increment
247 // if we throw an exeption.
248 incrementPendingBroadcastsLocked();
249 }
250 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 } catch (RemoteException e) {
252 return false;
253 }
254 } else {
255 Intent statusChanged = new Intent();
256 statusChanged.putExtras(extras);
257 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
258 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700259 synchronized (this) {
260 // synchronize to ensure incrementPendingBroadcastsLocked()
261 // is called before decrementPendingBroadcasts()
262 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
263 // call this after broadcasting so we do not increment
264 // if we throw an exeption.
265 incrementPendingBroadcastsLocked();
266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 } catch (PendingIntent.CanceledException e) {
268 return false;
269 }
270 }
271 return true;
272 }
273
274 public boolean callLocationChangedLocked(Location location) {
275 if (mListener != null) {
276 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700277 synchronized (this) {
278 // synchronize to ensure incrementPendingBroadcastsLocked()
279 // is called before decrementPendingBroadcasts()
280 mListener.onLocationChanged(location);
281 if (mListener != mProximityListener) {
282 // call this after broadcasting so we do not increment
283 // if we throw an exeption.
284 incrementPendingBroadcastsLocked();
285 }
286 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 } catch (RemoteException e) {
288 return false;
289 }
290 } else {
291 Intent locationChanged = new Intent();
292 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
293 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700294 synchronized (this) {
295 // synchronize to ensure incrementPendingBroadcastsLocked()
296 // is called before decrementPendingBroadcasts()
297 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
298 // call this after broadcasting so we do not increment
299 // if we throw an exeption.
300 incrementPendingBroadcastsLocked();
301 }
302 } catch (PendingIntent.CanceledException e) {
303 return false;
304 }
305 }
306 return true;
307 }
308
309 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
310 if (mListener != null) {
311 try {
312 synchronized (this) {
313 // synchronize to ensure incrementPendingBroadcastsLocked()
314 // is called before decrementPendingBroadcasts()
315 if (enabled) {
316 mListener.onProviderEnabled(provider);
317 } else {
318 mListener.onProviderDisabled(provider);
319 }
320 if (mListener != mProximityListener) {
321 // call this after broadcasting so we do not increment
322 // if we throw an exeption.
323 incrementPendingBroadcastsLocked();
324 }
325 }
326 } catch (RemoteException e) {
327 return false;
328 }
329 } else {
330 Intent providerIntent = new Intent();
331 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
332 try {
333 synchronized (this) {
334 // synchronize to ensure incrementPendingBroadcastsLocked()
335 // is called before decrementPendingBroadcasts()
336 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
337 // call this after broadcasting so we do not increment
338 // if we throw an exeption.
339 incrementPendingBroadcastsLocked();
340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 } catch (PendingIntent.CanceledException e) {
342 return false;
343 }
344 }
345 return true;
346 }
347
348 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700349 if (LOCAL_LOGV) {
350 Log.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800351 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700352 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 removeUpdatesLocked(this);
354 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700355 synchronized (this) {
356 if (mPendingBroadcasts > 0) {
357 LocationManagerService.this.decrementPendingBroadcasts();
358 mPendingBroadcasts = 0;
359 }
360 }
361 }
362
363 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
364 int resultCode, String resultData, Bundle resultExtras) {
365 synchronized (this) {
366 decrementPendingBroadcastsLocked();
367 }
368 }
369
370 // this must be called while synchronized by caller in a synchronized block
371 // containing the sending of the broadcaset
372 private void incrementPendingBroadcastsLocked() {
373 if (mPendingBroadcasts++ == 0) {
374 LocationManagerService.this.incrementPendingBroadcasts();
375 }
376 }
377
378 private void decrementPendingBroadcastsLocked() {
379 if (--mPendingBroadcasts == 0) {
380 LocationManagerService.this.decrementPendingBroadcasts();
381 }
382 }
383 }
384
385 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel9ff67a52009-10-05 12:44:46 -0400386 //Do not use getReceiver here as that will add the ILocationListener to
387 //the receiver list if it is not found. If it is not found then the
388 //LocationListener was removed when it had a pending broadcast and should
389 //not be added back.
390 IBinder binder = listener.asBinder();
391 Receiver receiver = mReceivers.get(binder);
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700392 if (receiver != null) {
393 synchronized (receiver) {
394 // so wakelock calls will succeed
395 long identity = Binder.clearCallingIdentity();
396 receiver.decrementPendingBroadcastsLocked();
397 Binder.restoreCallingIdentity(identity);
398 }
399 }
400 }
401
402 private final class SettingsObserver implements Observer {
403 public void update(Observable o, Object arg) {
404 synchronized (mLock) {
405 updateProvidersLocked();
406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 }
408 }
409
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700410 private void addProvider(LocationProviderProxy provider) {
411 mProviders.add(provider);
412 mProvidersByName.put(provider.getName(), provider);
413 }
414
415 private void removeProvider(LocationProviderProxy provider) {
416 mProviders.remove(provider);
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700417 provider.unlinkProvider();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700418 mProvidersByName.remove(provider.getName());
419 }
420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 private void loadProviders() {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700422 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 if (sProvidersLoaded) {
424 return;
425 }
426
427 // Load providers
428 loadProvidersLocked();
429 sProvidersLoaded = true;
430 }
431 }
432
433 private void loadProvidersLocked() {
434 try {
435 _loadProvidersLocked();
436 } catch (Exception e) {
437 Log.e(TAG, "Exception loading providers:", e);
438 }
439 }
440
441 private void _loadProvidersLocked() {
442 // Attempt to load "real" providers first
443 if (GpsLocationProvider.isSupported()) {
444 // Create a gps location provider
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700445 GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
446 mGpsStatusProvider = provider.getGpsStatusProvider();
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -0800447 mNetInitiatedListener = provider.getNetInitiatedListener();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700448 LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
449 addProvider(proxy);
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700450 mGpsLocationProvider = proxy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
452
453 updateProvidersLocked();
454 }
455
456 /**
457 * @param context the context that the LocationManagerService runs in
458 */
459 public LocationManagerService(Context context) {
460 super();
461 mContext = context;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700462
463 Thread thread = new Thread(null, this, "LocationManagerService");
464 thread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465
The Android Open Source Project10592532009-03-18 17:39:46 -0700466 if (LOCAL_LOGV) {
467 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700471 private void initialize() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 // Create a wake lock, needs to be done before calling loadProviders() below
473 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
474 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800475
476 // Load providers
477 loadProviders();
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 // Register for Network (Wifi or Mobile) updates
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 IntentFilter intentFilter = new IntentFilter();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700481 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
482 // Register for Package Manager updates
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
484 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700485 mContext.registerReceiver(mBroadcastReceiver, intentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700487 // listen for settings changes
488 ContentResolver resolver = mContext.getContentResolver();
489 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
490 "(" + Settings.System.NAME + "=?)",
491 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
492 null);
493 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
494 SettingsObserver settingsObserver = new SettingsObserver();
495 mSettings.addObserver(settingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800496 }
497
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700498 public void run()
499 {
500 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
501 Looper.prepare();
502 mLocationHandler = new LocationWorkerHandler();
503 initialize();
504 Looper.loop();
505 }
506
507 public void installLocationProvider(String name, ILocationProvider provider) {
508 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
509 != PackageManager.PERMISSION_GRANTED) {
510 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700513 synchronized (mLock) {
514 // check to see if we are reinstalling a dead provider
515 LocationProviderProxy oldProvider = mProvidersByName.get(name);
516 if (oldProvider != null) {
517 if (oldProvider.isDead()) {
518 Log.d(TAG, "replacing dead provider");
519 removeProvider(oldProvider);
520 } else {
521 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
522 }
523 }
524
525 LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
526 addProvider(proxy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 updateProvidersLocked();
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -0700528 if (LocationManager.NETWORK_PROVIDER.equals(name)) {
529 mNetworkLocationProvider = proxy;
530 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800531
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700532 // notify provider of current network state
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -0800533 proxy.updateNetworkState(mNetworkState, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 }
535 }
536
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700537 public void installGeocodeProvider(IGeocodeProvider provider) {
538 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
539 != PackageManager.PERMISSION_GRANTED) {
540 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700542
543 mGeocodeProvider = provider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545
546 private boolean isAllowedBySettingsLocked(String provider) {
547 if (mEnabledProviders.contains(provider)) {
548 return true;
549 }
550 if (mDisabledProviders.contains(provider)) {
551 return false;
552 }
553 // Use system settings
554 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555
Brad Larson86568d72009-12-29 11:47:55 -0600556 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
559 private void checkPermissionsSafe(String provider) {
560 if (LocationManager.GPS_PROVIDER.equals(provider)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700561 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 != PackageManager.PERMISSION_GRANTED)) {
563 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
564 }
565 if (LocationManager.NETWORK_PROVIDER.equals(provider)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700566 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 != PackageManager.PERMISSION_GRANTED)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700568 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 != PackageManager.PERMISSION_GRANTED)) {
570 throw new SecurityException(
571 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
572 }
573 }
574
575 private boolean isAllowedProviderSafe(String provider) {
576 if (LocationManager.GPS_PROVIDER.equals(provider)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700577 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 != PackageManager.PERMISSION_GRANTED)) {
579 return false;
580 }
581 if (LocationManager.NETWORK_PROVIDER.equals(provider)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700582 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 != PackageManager.PERMISSION_GRANTED)
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700584 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 != PackageManager.PERMISSION_GRANTED)) {
586 return false;
587 }
588
589 return true;
590 }
591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 public List<String> getAllProviders() {
593 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700594 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 return _getAllProvidersLocked();
596 }
597 } catch (SecurityException se) {
598 throw se;
599 } catch (Exception e) {
600 Log.e(TAG, "getAllProviders got exception:", e);
601 return null;
602 }
603 }
604
605 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700606 if (LOCAL_LOGV) {
607 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700609 ArrayList<String> out = new ArrayList<String>(mProviders.size());
610 for (int i = mProviders.size() - 1; i >= 0; i--) {
611 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 out.add(p.getName());
613 }
614 return out;
615 }
616
617 public List<String> getProviders(boolean enabledOnly) {
618 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700619 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 return _getProvidersLocked(enabledOnly);
621 }
622 } catch (SecurityException se) {
623 throw se;
624 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700625 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 return null;
627 }
628 }
629
630 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700631 if (LOCAL_LOGV) {
632 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700634 ArrayList<String> out = new ArrayList<String>(mProviders.size());
635 for (int i = mProviders.size() - 1; i >= 0; i--) {
636 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 String name = p.getName();
638 if (isAllowedProviderSafe(name)) {
639 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
640 continue;
641 }
642 out.add(name);
643 }
644 }
645 return out;
646 }
647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 private void updateProvidersLocked() {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700649 for (int i = mProviders.size() - 1; i >= 0; i--) {
650 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 boolean isEnabled = p.isEnabled();
652 String name = p.getName();
653 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 if (isEnabled && !shouldBeEnabled) {
656 updateProviderListenersLocked(name, false);
657 } else if (!isEnabled && shouldBeEnabled) {
658 updateProviderListenersLocked(name, true);
659 }
660
661 }
662 }
663
664 private void updateProviderListenersLocked(String provider, boolean enabled) {
665 int listeners = 0;
666
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700667 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 if (p == null) {
669 return;
670 }
671
672 ArrayList<Receiver> deadReceivers = null;
673
674 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
675 if (records != null) {
676 final int N = records.size();
677 for (int i=0; i<N; i++) {
678 UpdateRecord record = records.get(i);
679 // Sends a notification message to the receiver
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700680 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
681 if (deadReceivers == null) {
682 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800683 }
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700684 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 }
686 listeners++;
687 }
688 }
689
690 if (deadReceivers != null) {
691 for (int i=deadReceivers.size()-1; i>=0; i--) {
692 removeUpdatesLocked(deadReceivers.get(i));
693 }
694 }
695
696 if (enabled) {
697 p.enable();
698 if (listeners > 0) {
699 p.setMinTime(getMinTimeLocked(provider));
700 p.enableLocationTracking(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 }
702 } else {
703 p.enableLocationTracking(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
706 }
707
708 private long getMinTimeLocked(String provider) {
709 long minTime = Long.MAX_VALUE;
710 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
711 if (records != null) {
712 for (int i=records.size()-1; i>=0; i--) {
713 minTime = Math.min(minTime, records.get(i).mMinTime);
714 }
715 }
716 return minTime;
717 }
718
719 private class UpdateRecord {
720 final String mProvider;
721 final Receiver mReceiver;
722 final long mMinTime;
723 final float mMinDistance;
724 final int mUid;
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700725 Location mLastFixBroadcast;
726 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727
728 /**
729 * Note: must be constructed with lock held.
730 */
731 UpdateRecord(String provider, long minTime, float minDistance,
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700732 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 mProvider = provider;
734 mReceiver = receiver;
735 mMinTime = minTime;
736 mMinDistance = minDistance;
737 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738
739 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
740 if (records == null) {
741 records = new ArrayList<UpdateRecord>();
742 mRecordsByProvider.put(provider, records);
743 }
744 if (!records.contains(this)) {
745 records.add(this);
746 }
747 }
748
749 /**
750 * Method to be called when a record will no longer be used. Calling this multiple times
751 * must have the same effect as calling it once.
752 */
753 void disposeLocked() {
754 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -0800755 if (records != null) {
756 records.remove(this);
757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
759
760 @Override
761 public String toString() {
762 return "UpdateRecord{"
763 + Integer.toHexString(System.identityHashCode(this))
764 + " " + mProvider + " " + mReceiver + "}";
765 }
766
767 void dump(PrintWriter pw, String prefix) {
768 pw.println(prefix + this);
769 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
770 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700771 pw.println(prefix + "mUid=" + mUid);
772 pw.println(prefix + "mLastFixBroadcast:");
773 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
774 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 }
777
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700778 private Receiver getReceiver(ILocationListener listener) {
779 IBinder binder = listener.asBinder();
780 Receiver receiver = mReceivers.get(binder);
781 if (receiver == null) {
782 receiver = new Receiver(listener);
783 mReceivers.put(binder, receiver);
784
785 try {
786 if (receiver.isListener()) {
787 receiver.getListener().asBinder().linkToDeath(receiver, 0);
788 }
789 } catch (RemoteException e) {
790 Log.e(TAG, "linkToDeath failed:", e);
791 return null;
792 }
793 }
794 return receiver;
795 }
796
797 private Receiver getReceiver(PendingIntent intent) {
798 Receiver receiver = mReceivers.get(intent);
799 if (receiver == null) {
800 receiver = new Receiver(intent);
801 mReceivers.put(intent, receiver);
802 }
803 return receiver;
804 }
805
806 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
807 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
808 if (records != null) {
809 for (int i = records.size() - 1; i >= 0; i--) {
810 UpdateRecord record = records.get(i);
811 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
812 return true;
813 }
814 }
815 }
816 for (ProximityAlert alert : mProximityAlerts.values()) {
817 if (alert.mUid == uid) {
818 return true;
819 }
820 }
821 return false;
822 }
823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 public void requestLocationUpdates(String provider,
825 long minTime, float minDistance, ILocationListener listener) {
826
827 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700828 synchronized (mLock) {
829 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800830 }
831 } catch (SecurityException se) {
832 throw se;
833 } catch (Exception e) {
834 Log.e(TAG, "requestUpdates got exception:", e);
835 }
836 }
837
838 public void requestLocationUpdatesPI(String provider,
839 long minTime, float minDistance, PendingIntent intent) {
840 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700841 synchronized (mLock) {
842 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 }
844 } catch (SecurityException se) {
845 throw se;
846 } catch (Exception e) {
847 Log.e(TAG, "requestUpdates got exception:", e);
848 }
849 }
850
851 private void requestLocationUpdatesLocked(String provider,
852 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700853 if (LOCAL_LOGV) {
854 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 }
856
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700857 LocationProviderProxy proxy = mProvidersByName.get(provider);
858 if (proxy == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 throw new IllegalArgumentException("provider=" + provider);
860 }
861
862 checkPermissionsSafe(provider);
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 // so wakelock calls will succeed
865 final int callingUid = Binder.getCallingUid();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700866 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 long identity = Binder.clearCallingIdentity();
868 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700869 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
870 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800871 if (oldRecord != null) {
872 oldRecord.disposeLocked();
873 }
874
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700875 if (newUid) {
876 proxy.addListener(callingUid);
877 }
878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
880 if (isProviderEnabled) {
881 long minTimeForProvider = getMinTimeLocked(provider);
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700882 proxy.setMinTime(minTimeForProvider);
883 proxy.enableLocationTracking(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 } else {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700885 // Notify the listener that updates are currently disabled
886 receiver.callProviderEnabledLocked(provider, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 }
888 } finally {
889 Binder.restoreCallingIdentity(identity);
890 }
891 }
892
893 public void removeUpdates(ILocationListener listener) {
894 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700895 synchronized (mLock) {
896 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 }
898 } catch (SecurityException se) {
899 throw se;
900 } catch (Exception e) {
901 Log.e(TAG, "removeUpdates got exception:", e);
902 }
903 }
904
905 public void removeUpdatesPI(PendingIntent intent) {
906 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700907 synchronized (mLock) {
908 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800909 }
910 } catch (SecurityException se) {
911 throw se;
912 } catch (Exception e) {
913 Log.e(TAG, "removeUpdates got exception:", e);
914 }
915 }
916
917 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700918 if (LOCAL_LOGV) {
919 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800920 }
921
922 // so wakelock calls will succeed
923 final int callingUid = Binder.getCallingUid();
924 long identity = Binder.clearCallingIdentity();
925 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700926 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
927 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
Joshua Bartel9ff67a52009-10-05 12:44:46 -0400928 synchronized(receiver) {
929 if(receiver.mPendingBroadcasts > 0) {
930 decrementPendingBroadcasts();
931 receiver.mPendingBroadcasts = 0;
932 }
933 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800934 }
935
936 // Record which providers were associated with this listener
937 HashSet<String> providers = new HashSet<String>();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700938 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800939 if (oldRecords != null) {
940 // Call dispose() on the obsolete update records.
941 for (UpdateRecord record : oldRecords.values()) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700942 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
943 LocationProviderProxy proxy = mProvidersByName.get(record.mProvider);
944 if (proxy != null) {
945 proxy.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 }
947 }
948 record.disposeLocked();
949 }
950 // Accumulate providers
951 providers.addAll(oldRecords.keySet());
952 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953
954 // See if the providers associated with this listener have any
955 // other listeners; if one does, inform it of the new smallest minTime
956 // value; if one does not, disable location tracking for it
957 for (String provider : providers) {
958 // If provider is already disabled, don't need to do anything
959 if (!isAllowedBySettingsLocked(provider)) {
960 continue;
961 }
962
963 boolean hasOtherListener = false;
964 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
965 if (recordsForProvider != null && recordsForProvider.size() > 0) {
966 hasOtherListener = true;
967 }
968
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700969 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 if (p != null) {
971 if (hasOtherListener) {
972 p.setMinTime(getMinTimeLocked(provider));
973 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974 p.enableLocationTracking(false);
975 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 }
977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 } finally {
979 Binder.restoreCallingIdentity(identity);
980 }
981 }
982
983 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700984 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 return false;
986 }
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -0700987 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 PackageManager.PERMISSION_GRANTED) {
989 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
990 }
991
992 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700993 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 } catch (RemoteException e) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -0700995 Log.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 return false;
997 }
998 return true;
999 }
1000
1001 public void removeGpsStatusListener(IGpsStatusListener listener) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001002 synchronized (mLock) {
1003 try {
1004 mGpsStatusProvider.removeGpsStatusListener(listener);
1005 } catch (Exception e) {
1006 Log.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1007 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
1009 }
1010
1011 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001012 if (provider == null) {
1013 // throw NullPointerException to remain compatible with previous implementation
1014 throw new NullPointerException();
1015 }
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 // first check for permission to the provider
1018 checkPermissionsSafe(provider);
1019 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001020 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001021 != PackageManager.PERMISSION_GRANTED)) {
1022 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1023 }
1024
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001025 synchronized (mLock) {
1026 LocationProviderProxy proxy = mProvidersByName.get(provider);
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001027 if (proxy == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 return false;
1029 }
1030
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001031 return proxy.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 }
1033 }
1034
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001035 public boolean sendNiResponse(int notifId, int userResponse)
1036 {
1037 if (Binder.getCallingUid() != Process.myUid()) {
1038 throw new SecurityException(
1039 "calling sendNiResponse from outside of the system is not allowed");
1040 }
1041 try {
1042 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1043 }
1044 catch (RemoteException e)
1045 {
1046 Log.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
1047 return false;
1048 }
1049 }
1050
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 class ProximityAlert {
1052 final int mUid;
1053 final double mLatitude;
1054 final double mLongitude;
1055 final float mRadius;
1056 final long mExpiration;
1057 final PendingIntent mIntent;
1058 final Location mLocation;
1059
1060 public ProximityAlert(int uid, double latitude, double longitude,
1061 float radius, long expiration, PendingIntent intent) {
1062 mUid = uid;
1063 mLatitude = latitude;
1064 mLongitude = longitude;
1065 mRadius = radius;
1066 mExpiration = expiration;
1067 mIntent = intent;
1068
1069 mLocation = new Location("");
1070 mLocation.setLatitude(latitude);
1071 mLocation.setLongitude(longitude);
1072 }
1073
1074 long getExpiration() {
1075 return mExpiration;
1076 }
1077
1078 PendingIntent getIntent() {
1079 return mIntent;
1080 }
1081
Yusuf T. Mobile5550ef42009-07-14 15:46:26 -07001082 boolean isInProximity(double latitude, double longitude, float accuracy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 Location loc = new Location("");
1084 loc.setLatitude(latitude);
1085 loc.setLongitude(longitude);
1086
1087 double radius = loc.distanceTo(mLocation);
Yusuf T. Mobile5550ef42009-07-14 15:46:26 -07001088 return radius <= Math.max(mRadius,accuracy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 }
1090
1091 @Override
1092 public String toString() {
1093 return "ProximityAlert{"
1094 + Integer.toHexString(System.identityHashCode(this))
1095 + " uid " + mUid + mIntent + "}";
1096 }
1097
1098 void dump(PrintWriter pw, String prefix) {
1099 pw.println(prefix + this);
1100 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1101 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1102 pw.println(prefix + "mIntent=" + mIntent);
1103 pw.println(prefix + "mLocation:");
1104 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1105 }
1106 }
1107
1108 // Listener for receiving locations to trigger proximity alerts
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001109 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110
1111 boolean isGpsAvailable = false;
1112
1113 // Note: this is called with the lock held.
1114 public void onLocationChanged(Location loc) {
1115
1116 // If Gps is available, then ignore updates from NetworkLocationProvider
1117 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1118 isGpsAvailable = true;
1119 }
1120 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1121 return;
1122 }
1123
1124 // Process proximity alerts
1125 long now = System.currentTimeMillis();
1126 double latitude = loc.getLatitude();
1127 double longitude = loc.getLongitude();
Yusuf T. Mobile5550ef42009-07-14 15:46:26 -07001128 float accuracy = loc.getAccuracy();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001129 ArrayList<PendingIntent> intentsToRemove = null;
1130
1131 for (ProximityAlert alert : mProximityAlerts.values()) {
1132 PendingIntent intent = alert.getIntent();
1133 long expiration = alert.getExpiration();
1134
1135 if ((expiration == -1) || (now <= expiration)) {
1136 boolean entered = mProximitiesEntered.contains(alert);
1137 boolean inProximity =
Yusuf T. Mobile5550ef42009-07-14 15:46:26 -07001138 alert.isInProximity(latitude, longitude, accuracy);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001140 if (LOCAL_LOGV) {
1141 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 }
1143 mProximitiesEntered.add(alert);
1144 Intent enteredIntent = new Intent();
1145 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1146 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001147 synchronized (this) {
1148 // synchronize to ensure incrementPendingBroadcasts()
1149 // is called before decrementPendingBroadcasts()
1150 intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
1151 // call this after broadcasting so we do not increment
1152 // if we throw an exeption.
1153 incrementPendingBroadcasts();
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001156 if (LOCAL_LOGV) {
1157 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 }
1159 if (intentsToRemove == null) {
1160 intentsToRemove = new ArrayList<PendingIntent>();
1161 }
1162 intentsToRemove.add(intent);
1163 }
1164 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001165 if (LOCAL_LOGV) {
1166 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001167 }
1168 mProximitiesEntered.remove(alert);
1169 Intent exitedIntent = new Intent();
1170 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1171 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001172 synchronized (this) {
1173 // synchronize to ensure incrementPendingBroadcasts()
1174 // is called before decrementPendingBroadcasts()
1175 intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
1176 // call this after broadcasting so we do not increment
1177 // if we throw an exeption.
1178 incrementPendingBroadcasts();
1179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001181 if (LOCAL_LOGV) {
1182 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
1184 if (intentsToRemove == null) {
1185 intentsToRemove = new ArrayList<PendingIntent>();
1186 }
1187 intentsToRemove.add(intent);
1188 }
1189 }
1190 } else {
1191 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001192 if (LOCAL_LOGV) {
1193 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001194 }
1195 if (intentsToRemove == null) {
1196 intentsToRemove = new ArrayList<PendingIntent>();
1197 }
1198 intentsToRemove.add(alert.getIntent());
1199 }
1200 }
1201
1202 // Remove expired alerts
1203 if (intentsToRemove != null) {
1204 for (PendingIntent i : intentsToRemove) {
Sean Foy26abeae2010-03-04 12:17:54 -06001205 ProximityAlert alert = mProximityAlerts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001206 mProximitiesEntered.remove(alert);
Sean Foy26abeae2010-03-04 12:17:54 -06001207 removeProximityAlertLocked(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
1211
1212 // Note: this is called with the lock held.
1213 public void onProviderDisabled(String provider) {
1214 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1215 isGpsAvailable = false;
1216 }
1217 }
1218
1219 // Note: this is called with the lock held.
1220 public void onProviderEnabled(String provider) {
1221 // ignore
1222 }
1223
1224 // Note: this is called with the lock held.
1225 public void onStatusChanged(String provider, int status, Bundle extras) {
1226 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1227 (status != LocationProvider.AVAILABLE)) {
1228 isGpsAvailable = false;
1229 }
1230 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001231
1232 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1233 int resultCode, String resultData, Bundle resultExtras) {
1234 // synchronize to ensure incrementPendingBroadcasts()
1235 // is called before decrementPendingBroadcasts()
1236 synchronized (this) {
1237 decrementPendingBroadcasts();
1238 }
1239 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001240 }
1241
1242 public void addProximityAlert(double latitude, double longitude,
1243 float radius, long expiration, PendingIntent intent) {
1244 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001245 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1247 }
1248 } catch (SecurityException se) {
1249 throw se;
1250 } catch (Exception e) {
1251 Log.e(TAG, "addProximityAlert got exception:", e);
1252 }
1253 }
1254
1255 private void addProximityAlertLocked(double latitude, double longitude,
1256 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001257 if (LOCAL_LOGV) {
1258 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001259 ", longitude = " + longitude +
1260 ", expiration = " + expiration +
1261 ", intent = " + intent);
1262 }
1263
1264 // Require ability to access all providers for now
1265 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1266 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1267 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1268 }
1269
1270 if (expiration != -1) {
1271 expiration += System.currentTimeMillis();
1272 }
1273 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1274 latitude, longitude, radius, expiration, intent);
1275 mProximityAlerts.put(intent, alert);
1276
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001277 if (mProximityReceiver == null) {
1278 mProximityListener = new ProximityListener();
1279 mProximityReceiver = new Receiver(mProximityListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001280
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001281 for (int i = mProviders.size() - 1; i >= 0; i--) {
1282 LocationProviderProxy provider = mProviders.get(i);
1283 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
1286 }
1287
1288 public void removeProximityAlert(PendingIntent intent) {
1289 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001290 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 removeProximityAlertLocked(intent);
1292 }
1293 } catch (SecurityException se) {
1294 throw se;
1295 } catch (Exception e) {
1296 Log.e(TAG, "removeProximityAlert got exception:", e);
1297 }
1298 }
1299
1300 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001301 if (LOCAL_LOGV) {
1302 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001303 }
1304
1305 mProximityAlerts.remove(intent);
1306 if (mProximityAlerts.size() == 0) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001307 removeUpdatesLocked(mProximityReceiver);
1308 mProximityReceiver = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 }
1311 }
1312
1313 /**
1314 * @return null if the provider does not exits
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001315 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 * accessed by the caller
1317 */
1318 public Bundle getProviderInfo(String provider) {
1319 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001320 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 return _getProviderInfoLocked(provider);
1322 }
1323 } catch (SecurityException se) {
1324 throw se;
1325 } catch (Exception e) {
1326 Log.e(TAG, "_getProviderInfo got exception:", e);
1327 return null;
1328 }
1329 }
1330
1331 private Bundle _getProviderInfoLocked(String provider) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001332 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001333 if (p == null) {
1334 return null;
1335 }
1336
1337 checkPermissionsSafe(provider);
1338
1339 Bundle b = new Bundle();
1340 b.putBoolean("network", p.requiresNetwork());
1341 b.putBoolean("satellite", p.requiresSatellite());
1342 b.putBoolean("cell", p.requiresCell());
1343 b.putBoolean("cost", p.hasMonetaryCost());
1344 b.putBoolean("altitude", p.supportsAltitude());
1345 b.putBoolean("speed", p.supportsSpeed());
1346 b.putBoolean("bearing", p.supportsBearing());
1347 b.putInt("power", p.getPowerRequirement());
1348 b.putInt("accuracy", p.getAccuracy());
1349
1350 return b;
1351 }
1352
1353 public boolean isProviderEnabled(String provider) {
1354 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001355 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 return _isProviderEnabledLocked(provider);
1357 }
1358 } catch (SecurityException se) {
1359 throw se;
1360 } catch (Exception e) {
1361 Log.e(TAG, "isProviderEnabled got exception:", e);
1362 return false;
1363 }
1364 }
1365
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001366 public void reportLocation(Location location) {
1367 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1368 != PackageManager.PERMISSION_GRANTED) {
1369 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1370 }
1371
1372 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1373 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1374 mLocationHandler.sendMessageAtFrontOfQueue(m);
1375 }
1376
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 private boolean _isProviderEnabledLocked(String provider) {
1378 checkPermissionsSafe(provider);
1379
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001380 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 if (p == null) {
1382 throw new IllegalArgumentException("provider=" + provider);
1383 }
1384 return isAllowedBySettingsLocked(provider);
1385 }
1386
1387 public Location getLastKnownLocation(String provider) {
1388 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001389 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 return _getLastKnownLocationLocked(provider);
1391 }
1392 } catch (SecurityException se) {
1393 throw se;
1394 } catch (Exception e) {
1395 Log.e(TAG, "getLastKnownLocation got exception:", e);
1396 return null;
1397 }
1398 }
1399
1400 private Location _getLastKnownLocationLocked(String provider) {
1401 checkPermissionsSafe(provider);
1402
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001403 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 if (p == null) {
1405 throw new IllegalArgumentException("provider=" + provider);
1406 }
1407
1408 if (!isAllowedBySettingsLocked(provider)) {
1409 return null;
1410 }
1411
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001412 return mLastKnownLocation.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001413 }
1414
1415 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1416 // Always broadcast the first update
1417 if (lastLoc == null) {
1418 return true;
1419 }
1420
1421 // Don't broadcast same location again regardless of condition
1422 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1423 if (loc.getTime() == lastLoc.getTime()) {
1424 return false;
1425 }
1426
1427 // Check whether sufficient distance has been traveled
1428 double minDistance = record.mMinDistance;
1429 if (minDistance > 0.0) {
1430 if (loc.distanceTo(lastLoc) <= minDistance) {
1431 return false;
1432 }
1433 }
1434
1435 return true;
1436 }
1437
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001438 private void handleLocationChangedLocked(Location location) {
1439 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1441 if (records == null || records.size() == 0) {
1442 return;
1443 }
1444
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001445 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001446 if (p == null) {
1447 return;
1448 }
1449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001450 // Update last known location for provider
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001451 Location lastLocation = mLastKnownLocation.get(provider);
1452 if (lastLocation == null) {
1453 mLastKnownLocation.put(provider, new Location(location));
1454 } else {
1455 lastLocation.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457
1458 // Fetch latest status update time
1459 long newStatusUpdateTime = p.getStatusUpdateTime();
1460
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001461 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001462 Bundle extras = new Bundle();
1463 int status = p.getStatus(extras);
1464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 ArrayList<Receiver> deadReceivers = null;
1466
1467 // Broadcast location or status to all listeners
1468 final int N = records.size();
1469 for (int i=0; i<N; i++) {
1470 UpdateRecord r = records.get(i);
1471 Receiver receiver = r.mReceiver;
1472
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001473 Location lastLoc = r.mLastFixBroadcast;
1474 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1475 if (lastLoc == null) {
1476 lastLoc = new Location(location);
1477 r.mLastFixBroadcast = lastLoc;
1478 } else {
1479 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001481 if (!receiver.callLocationChangedLocked(location)) {
1482 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1483 if (deadReceivers == null) {
1484 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001486 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001487 }
1488 }
1489
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001490 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1492 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1493
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001494 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1496 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1497 if (deadReceivers == null) {
1498 deadReceivers = new ArrayList<Receiver>();
1499 }
1500 if (!deadReceivers.contains(receiver)) {
1501 deadReceivers.add(receiver);
1502 }
1503 }
1504 }
1505 }
1506
1507 if (deadReceivers != null) {
1508 for (int i=deadReceivers.size()-1; i>=0; i--) {
1509 removeUpdatesLocked(deadReceivers.get(i));
1510 }
1511 }
1512 }
1513
1514 private class LocationWorkerHandler extends Handler {
1515
1516 @Override
1517 public void handleMessage(Message msg) {
1518 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001519 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1520 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001522 synchronized (mLock) {
1523 Location location = (Location) msg.obj;
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001524 String provider = location.getProvider();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001525
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001526 // notify other providers of the new location
1527 for (int i = mProviders.size() - 1; i >= 0; i--) {
1528 LocationProviderProxy proxy = mProviders.get(i);
1529 if (!provider.equals(proxy.getName())) {
1530 proxy.updateLocation(location);
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001531 }
1532 }
1533
Jean-Baptiste Querucf4550c2009-07-21 11:16:54 -07001534 if (isAllowedBySettingsLocked(provider)) {
1535 handleLocationChangedLocked(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 }
1538 }
1539 } catch (Exception e) {
1540 // Log, don't crash!
1541 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1542 }
1543 }
1544 }
1545
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001546 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 @Override
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001548 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 String action = intent.getAction();
1550
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001551 if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001553 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1555 if (uid >= 0) {
1556 ArrayList<Receiver> removedRecs = null;
1557 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1558 for (int j=i.size()-1; j>=0; j--) {
1559 UpdateRecord ur = i.get(j);
1560 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1561 if (removedRecs == null) {
1562 removedRecs = new ArrayList<Receiver>();
1563 }
1564 if (!removedRecs.contains(ur.mReceiver)) {
1565 removedRecs.add(ur.mReceiver);
1566 }
1567 }
1568 }
1569 }
1570 ArrayList<ProximityAlert> removedAlerts = null;
1571 for (ProximityAlert i : mProximityAlerts.values()) {
1572 if (i.mUid == uid) {
1573 if (removedAlerts == null) {
1574 removedAlerts = new ArrayList<ProximityAlert>();
1575 }
1576 if (!removedAlerts.contains(i)) {
1577 removedAlerts.add(i);
1578 }
1579 }
1580 }
1581 if (removedRecs != null) {
1582 for (int i=removedRecs.size()-1; i>=0; i--) {
1583 removeUpdatesLocked(removedRecs.get(i));
1584 }
1585 }
1586 if (removedAlerts != null) {
1587 for (int i=removedAlerts.size()-1; i>=0; i--) {
1588 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1589 }
1590 }
1591 }
1592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 boolean noConnectivity =
1595 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1596 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001597 mNetworkState = LocationProvider.AVAILABLE;
1598 } else {
1599 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600 }
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001601 NetworkInfo info =
1602 (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603
1604 // Notify location providers of current network state
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001605 synchronized (mLock) {
1606 for (int i = mProviders.size() - 1; i >= 0; i--) {
1607 LocationProviderProxy provider = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 if (provider.requiresNetwork()) {
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001609 provider.updateNetworkState(mNetworkState, info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 }
1611 }
1612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001613 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001615 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616
1617 // Wake locks
1618
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001619 private void incrementPendingBroadcasts() {
1620 synchronized (mWakeLock) {
1621 if (mPendingBroadcasts++ == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001622 try {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001623 mWakeLock.acquire();
1624 log("Acquired wakelock");
1625 } catch (Exception e) {
1626 // This is to catch a runtime exception thrown when we try to release an
1627 // already released lock.
1628 Log.e(TAG, "exception in acquireWakeLock()", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 }
1631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 }
1633
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001634 private void decrementPendingBroadcasts() {
1635 synchronized (mWakeLock) {
1636 if (--mPendingBroadcasts == 0) {
1637 try {
1638 // Release wake lock
1639 if (mWakeLock.isHeld()) {
1640 mWakeLock.release();
1641 log("Released wakelock");
1642 } else {
1643 log("Can't release wakelock again!");
1644 }
1645 } catch (Exception e) {
1646 // This is to catch a runtime exception thrown when we try to release an
1647 // already released lock.
1648 Log.e(TAG, "exception in releaseWakeLock()", e);
1649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 }
1651 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 }
1653
1654 // Geocoder
1655
1656 public String getFromLocation(double latitude, double longitude, int maxResults,
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001657 String language, String country, String variant, String appName, List<Address> addrs) {
1658 if (mGeocodeProvider != null) {
1659 try {
1660 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1661 variant, appName, addrs);
1662 } catch (RemoteException e) {
1663 Log.e(TAG, "getFromLocation failed", e);
1664 mGeocodeProvider = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 }
1666 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001667 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001668 }
1669
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001670
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 public String getFromLocationName(String locationName,
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001672 double lowerLeftLatitude, double lowerLeftLongitude,
1673 double upperRightLatitude, double upperRightLongitude, int maxResults,
1674 String language, String country, String variant, String appName, List<Address> addrs) {
1675
1676 if (mGeocodeProvider != null) {
1677 try {
1678 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1679 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1680 maxResults, language, country, variant, appName, addrs);
1681 } catch (RemoteException e) {
1682 Log.e(TAG, "getFromLocationName failed", e);
1683 mGeocodeProvider = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 }
1685 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001686 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001687 }
1688
1689 // Mock Providers
1690
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 private void checkMockPermissionsSafe() {
1692 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1693 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1694 if (!allowMocks) {
1695 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1696 }
1697
1698 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1699 PackageManager.PERMISSION_GRANTED) {
1700 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1701 }
1702 }
1703
1704 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1705 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1706 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1707 checkMockPermissionsSafe();
1708
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001709 long identity = Binder.clearCallingIdentity();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001710 synchronized (mLock) {
1711 MockProvider provider = new MockProvider(name, this,
1712 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 requiresCell, hasMonetaryCost, supportsAltitude,
1714 supportsSpeed, supportsBearing, powerRequirement, accuracy);
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -07001715 // remove the real provider if we are replacing GPS or network provider
1716 if (LocationManager.GPS_PROVIDER.equals(name)
1717 || LocationManager.NETWORK_PROVIDER.equals(name)) {
1718 LocationProviderProxy proxy = mProvidersByName.get(name);
1719 if (proxy != null) {
1720 proxy.enableLocationTracking(false);
1721 removeProvider(proxy);
1722 }
1723 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001724 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001725 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1726 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001727 addProvider(new LocationProviderProxy(name, provider));
1728 mMockProviders.put(name, provider);
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -07001729 mLastKnownLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001730 updateProvidersLocked();
1731 }
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001732 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 }
1734
1735 public void removeTestProvider(String provider) {
1736 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001737 synchronized (mLock) {
1738 MockProvider mockProvider = mMockProviders.get(provider);
1739 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1741 }
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001742 long identity = Binder.clearCallingIdentity();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001743 removeProvider(mProvidersByName.get(provider));
1744 mMockProviders.remove(mockProvider);
Jean-Baptiste Queru72b1f372009-08-31 09:17:57 -07001745 // reinstall real provider if we were mocking GPS or network provider
1746 if (LocationManager.GPS_PROVIDER.equals(provider) &&
1747 mGpsLocationProvider != null) {
1748 addProvider(mGpsLocationProvider);
1749 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
1750 mNetworkLocationProvider != null) {
1751 addProvider(mNetworkLocationProvider);
1752 }
1753 mLastKnownLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 updateProvidersLocked();
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001755 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001756 }
1757 }
1758
1759 public void setTestProviderLocation(String provider, Location loc) {
1760 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001761 synchronized (mLock) {
1762 MockProvider mockProvider = mMockProviders.get(provider);
1763 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1765 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001766 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1767 long identity = Binder.clearCallingIdentity();
1768 mockProvider.setLocation(loc);
1769 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 }
1771 }
1772
1773 public void clearTestProviderLocation(String provider) {
1774 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001775 synchronized (mLock) {
1776 MockProvider mockProvider = mMockProviders.get(provider);
1777 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001778 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1779 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001780 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001781 }
1782 }
1783
1784 public void setTestProviderEnabled(String provider, boolean enabled) {
1785 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001786 synchronized (mLock) {
1787 MockProvider mockProvider = mMockProviders.get(provider);
1788 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1790 }
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001791 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 if (enabled) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001793 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 mEnabledProviders.add(provider);
1795 mDisabledProviders.remove(provider);
1796 } else {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001797 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001798 mEnabledProviders.remove(provider);
1799 mDisabledProviders.add(provider);
1800 }
1801 updateProvidersLocked();
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001802 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 }
1804 }
1805
1806 public void clearTestProviderEnabled(String provider) {
1807 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001808 synchronized (mLock) {
1809 MockProvider mockProvider = mMockProviders.get(provider);
1810 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1812 }
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001813 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 mEnabledProviders.remove(provider);
1815 mDisabledProviders.remove(provider);
1816 updateProvidersLocked();
Jean-Baptiste Queru9db3d072009-11-12 18:45:53 -08001817 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001818 }
1819 }
1820
1821 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1822 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001823 synchronized (mLock) {
1824 MockProvider mockProvider = mMockProviders.get(provider);
1825 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001826 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1827 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001828 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001829 }
1830 }
1831
1832 public void clearTestProviderStatus(String provider) {
1833 checkMockPermissionsSafe();
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001834 synchronized (mLock) {
1835 MockProvider mockProvider = mMockProviders.get(provider);
1836 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001837 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1838 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001839 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001840 }
1841 }
1842
1843 private void log(String log) {
1844 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1845 Log.d(TAG, log);
1846 }
1847 }
1848
1849 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1850 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1851 != PackageManager.PERMISSION_GRANTED) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001852 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001853 + Binder.getCallingPid()
1854 + ", uid=" + Binder.getCallingUid());
1855 return;
1856 }
1857
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001858 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001859 pw.println("Current Location Manager state:");
1860 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001861 pw.println(" Listeners:");
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001862 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001863 for (int i=0; i<N; i++) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001864 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001865 }
1866 pw.println(" Location Listeners:");
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001867 for (Receiver i : mReceivers.values()) {
1868 pw.println(" " + i + ":");
1869 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001870 pw.println(" " + j.getKey() + ":");
1871 j.getValue().dump(pw, " ");
1872 }
1873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001874 pw.println(" Records by Provider:");
1875 for (Map.Entry<String, ArrayList<UpdateRecord>> i
1876 : mRecordsByProvider.entrySet()) {
1877 pw.println(" " + i.getKey() + ":");
1878 for (UpdateRecord j : i.getValue()) {
1879 pw.println(" " + j + ":");
1880 j.dump(pw, " ");
1881 }
1882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001883 pw.println(" Last Known Locations:");
1884 for (Map.Entry<String, Location> i
1885 : mLastKnownLocation.entrySet()) {
1886 pw.println(" " + i.getKey() + ":");
1887 i.getValue().dump(new PrintWriterPrinter(pw), " ");
1888 }
1889 if (mProximityAlerts.size() > 0) {
1890 pw.println(" Proximity Alerts:");
1891 for (Map.Entry<PendingIntent, ProximityAlert> i
1892 : mProximityAlerts.entrySet()) {
1893 pw.println(" " + i.getKey() + ":");
1894 i.getValue().dump(pw, " ");
1895 }
1896 }
1897 if (mProximitiesEntered.size() > 0) {
1898 pw.println(" Proximities Entered:");
1899 for (ProximityAlert i : mProximitiesEntered) {
1900 pw.println(" " + i + ":");
1901 i.dump(pw, " ");
1902 }
1903 }
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001904 pw.println(" mProximityReceiver=" + mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 pw.println(" mProximityListener=" + mProximityListener);
1906 if (mEnabledProviders.size() > 0) {
1907 pw.println(" Enabled Providers:");
1908 for (String i : mEnabledProviders) {
1909 pw.println(" " + i);
1910 }
1911
1912 }
1913 if (mDisabledProviders.size() > 0) {
1914 pw.println(" Disabled Providers:");
1915 for (String i : mDisabledProviders) {
1916 pw.println(" " + i);
1917 }
1918
1919 }
1920 if (mMockProviders.size() > 0) {
1921 pw.println(" Mock Providers:");
1922 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Jean-Baptiste Queru843ef362009-05-20 11:28:04 -07001923 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 }
1925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 }
1927 }
1928}