blob: c17a3bcb24f24510cbb02de147af4ced6a9a3244 [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;
Mike Lockwood9637d472009-04-02 21:41:57 -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;
Mike Lockwood9637d472009-04-02 21:41:57 -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;
Mike Lockwood9637d472009-04-02 21:41:57 -070038import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Address;
Mike Lockwooda55c3212009-04-15 11:10:11 -040040import android.location.IGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040042import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.location.ILocationListener;
44import android.location.ILocationManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070045import android.location.ILocationProvider;
Danke Xie22d1f9f2009-08-18 18:28:45 -040046import 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;
Mike Lockwood03d24672009-10-08 15:45:03 -040051import 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;
Mike Lockwood3d12b512009-04-21 23:25:35 -070057import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Message;
59import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -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;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070067import com.android.internal.location.LocationProviderProxy;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070068import com.android.internal.location.MockProvider;
Danke Xie22d1f9f2009-08-18 18:28:45 -040069import 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 */
Mike Lockwood3d12b512009-04-21 23:25:35 -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;
Mike Lockwood275555c2009-05-01 11:30:34 -040092 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
Mike Lockwood7ec434e2009-03-27 07:46:48 -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;
Mike Lockwooda55c3212009-04-15 11:10:11 -0400107 private IGeocodeProvider mGeocodeProvider;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400108 private IGpsStatusProvider mGpsStatusProvider;
Danke Xie22d1f9f2009-08-18 18:28:45 -0400109 private INetInitiatedListener mNetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 private LocationWorkerHandler mLocationHandler;
111
Mike Lockwood7566c1d2009-08-25 10:05:18 -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
Mike Lockwood4e50b782009-04-03 08:24:43 -0700117 private static final int MESSAGE_LOCATION_CHANGED = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400119 // 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;
Mike Lockwood48f17512009-04-23 09:12:08 -0700122 private int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400125 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400127 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400129
130 /**
131 * List of location providers.
132 */
133 private final ArrayList<LocationProviderProxy> mProviders =
134 new ArrayList<LocationProviderProxy>();
135 private final HashMap<String, LocationProviderProxy> mProvidersByName
136 = new HashMap<String, LocationProviderProxy>();
137
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400139 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400141 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
Mike Lockwood48f17512009-04-23 09:12:08 -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;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800162
Mike Lockwood9637d472009-04-02 21:41:57 -0700163 // for Settings change notification
164 private ContentQueryMap mSettings;
165
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 */
Mike Lockwood48f17512009-04-23 09:12:08 -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;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400174 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Mike Lockwood48f17512009-04-23 09:12:08 -0700175 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800176
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400177 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
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400183 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 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400202
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))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400208 + " Listener " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 } else {
210 return "Receiver{"
211 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400212 + " 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 {
Mike Lockwood48f17512009-04-23 09:12:08 -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 {
Mike Lockwood48f17512009-04-23 09:12:08 -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 {
Mike Lockwood48f17512009-04-23 09:12:08 -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 {
Mike Lockwood48f17512009-04-23 09:12:08 -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 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400352 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 removeUpdatesLocked(this);
354 }
Mike Lockwood48f17512009-04-23 09:12:08 -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) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400365 synchronized (this) {
366 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700367 }
368 }
369
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400370 // 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();
Mike Lockwood48f17512009-04-23 09:12:08 -0700381 }
382 }
383 }
384
385 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-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);
Mike Lockwood48f17512009-04-23 09:12:08 -0700392 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400393 synchronized (receiver) {
394 // so wakelock calls will succeed
395 long identity = Binder.clearCallingIdentity();
396 receiver.decrementPendingBroadcastsLocked();
397 Binder.restoreCallingIdentity(identity);
398 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 }
400 }
401
Mike Lockwood9637d472009-04-02 21:41:57 -0700402 private final class SettingsObserver implements Observer {
403 public void update(Observable o, Object arg) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400404 synchronized (mLock) {
Mike Lockwood9637d472009-04-02 21:41:57 -0700405 updateProvidersLocked();
406 }
407 }
408 }
409
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400410 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);
Suchi Amalapurapufff2fda2009-06-30 21:36:16 -0700417 provider.unlinkProvider();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400418 mProvidersByName.remove(provider.getName());
419 }
420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800421 private void loadProviders() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400422 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
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400445 GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
446 mGpsStatusProvider = provider.getGpsStatusProvider();
Danke Xie22d1f9f2009-08-18 18:28:45 -0400447 mNetInitiatedListener = provider.getNetInitiatedListener();
Mike Lockwood8dfe5d82009-05-07 11:49:01 -0400448 LocationProviderProxy proxy = new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
449 addProvider(proxy);
Mike Lockwood7566c1d2009-08-25 10:05:18 -0700450 mGpsLocationProvider = proxy;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 }
452
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 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;
Mike Lockwood3d12b512009-04-21 23:25:35 -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 }
Mike Lockwood3d12b512009-04-21 23:25:35 -0700469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470
Mike Lockwood3d12b512009-04-21 23:25:35 -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);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 // 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();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400481 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);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400485 mContext.registerReceiver(mBroadcastReceiver, intentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800486
Mike Lockwood9637d472009-04-02 21:41:57 -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
Mike Lockwood3d12b512009-04-21 23:25:35 -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
Mike Lockwood275555c2009-05-01 11:30:34 -0400507 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");
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700511 }
512
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400513 synchronized (mLock) {
Mike Lockwood3681f262009-05-12 10:52:03 -0400514 // 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
Mike Lockwood8dfe5d82009-05-07 11:49:01 -0400525 LocationProviderProxy proxy = new LocationProviderProxy(name, provider);
526 addProvider(proxy);
527 updateProvidersLocked();
Mike Lockwood7566c1d2009-08-25 10:05:18 -0700528 if (LocationManager.NETWORK_PROVIDER.equals(name)) {
529 mNetworkLocationProvider = proxy;
530 }
Mike Lockwood275555c2009-05-01 11:30:34 -0400531
Mike Lockwood8dfe5d82009-05-07 11:49:01 -0400532 // notify provider of current network state
Mike Lockwood03d24672009-10-08 15:45:03 -0400533 proxy.updateNetworkState(mNetworkState, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 }
535 }
536
Mike Lockwood275555c2009-05-01 11:30:34 -0400537 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");
Mike Lockwooda55c3212009-04-15 11:10:11 -0400541 }
542
543 mGeocodeProvider = provider;
544 }
545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 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 Larson8eb3ea62009-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)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400561 && (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)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400566 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 != PackageManager.PERMISSION_GRANTED)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400568 && (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)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400577 && (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)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400582 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 != PackageManager.PERMISSION_GRANTED)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400584 && (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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400594 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 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400609 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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400619 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 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400634 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() {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400649 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
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400667 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
Mike Lockwood48f17512009-04-23 09:12:08 -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 }
Simon Schoar46866572009-06-10 21:12:10 +0200684 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 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
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;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400725 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,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400732 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);
Mike Lockwood3a76fd62009-09-01 07:26:56 -0400755 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);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400771 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
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400778 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 }
Mike Lockwood95427cd2009-05-07 13:27:54 -0400816 for (ProximityAlert alert : mProximityAlerts.values()) {
817 if (alert.mUid == uid) {
818 return true;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400819 }
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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400828 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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400841 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
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400857 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();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400866 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 long identity = Binder.clearCallingIdentity();
868 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400869 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
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400875 if (newUid) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400876 proxy.addListener(callingUid);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400877 }
878
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
880 if (isProviderEnabled) {
881 long minTimeForProvider = getMinTimeLocked(provider);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400882 proxy.setMinTime(minTimeForProvider);
883 proxy.enableLocationTracking(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 } else {
Mike Lockwood48f17512009-04-23 09:12:08 -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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400895 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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400907 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 {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400926 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
927 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
Joshua Bartel080b61b2009-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>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400938 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()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400942 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400943 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
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400969 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) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400984 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 return false;
986 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400987 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 {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400993 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800994 } catch (RemoteException e) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400995 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) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001002 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001003 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) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001012 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
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001020 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
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001025 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001026 LocationProviderProxy proxy = mProvidersByName.get(provider);
Mike Lockwood6ba7ae12009-08-17 08:39:12 -04001027 if (proxy == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 return false;
1029 }
1030
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001031 return proxy.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 }
1033 }
1034
Danke Xie22d1f9f2009-08-18 18:28:45 -04001035 public boolean sendNiResponse(int notifId, int userResponse)
1036 {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001037 if (Binder.getCallingUid() != Process.myUid()) {
1038 throw new SecurityException(
1039 "calling sendNiResponse from outside of the system is not allowed");
1040 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001041 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. Mobile2d2078a2009-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. Mobile2d2078a2009-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
Mike Lockwood48f17512009-04-23 09:12:08 -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. Mobile2d2078a2009-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. Mobile2d2078a2009-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 {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001147 synchronized (this) {
1148 // synchronize to ensure incrementPendingBroadcasts()
Mike Lockwood48f17512009-04-23 09:12:08 -07001149 // 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.
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001153 incrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -07001154 }
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 {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001172 synchronized (this) {
1173 // synchronize to ensure incrementPendingBroadcasts()
Mike Lockwood48f17512009-04-23 09:12:08 -07001174 // 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.
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001178 incrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -07001179 }
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) {
1205 mProximityAlerts.remove(i);
1206 ProximityAlert alert = mProximityAlerts.get(i);
1207 mProximitiesEntered.remove(alert);
1208 }
1209 }
1210
1211 }
1212
1213 // Note: this is called with the lock held.
1214 public void onProviderDisabled(String provider) {
1215 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1216 isGpsAvailable = false;
1217 }
1218 }
1219
1220 // Note: this is called with the lock held.
1221 public void onProviderEnabled(String provider) {
1222 // ignore
1223 }
1224
1225 // Note: this is called with the lock held.
1226 public void onStatusChanged(String provider, int status, Bundle extras) {
1227 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1228 (status != LocationProvider.AVAILABLE)) {
1229 isGpsAvailable = false;
1230 }
1231 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001232
1233 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1234 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001235 // synchronize to ensure incrementPendingBroadcasts()
1236 // is called before decrementPendingBroadcasts()
1237 synchronized (this) {
1238 decrementPendingBroadcasts();
1239 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001240 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001241 }
1242
1243 public void addProximityAlert(double latitude, double longitude,
1244 float radius, long expiration, PendingIntent intent) {
1245 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001246 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001247 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1248 }
1249 } catch (SecurityException se) {
1250 throw se;
1251 } catch (Exception e) {
1252 Log.e(TAG, "addProximityAlert got exception:", e);
1253 }
1254 }
1255
1256 private void addProximityAlertLocked(double latitude, double longitude,
1257 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001258 if (LOCAL_LOGV) {
1259 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 ", longitude = " + longitude +
1261 ", expiration = " + expiration +
1262 ", intent = " + intent);
1263 }
1264
1265 // Require ability to access all providers for now
1266 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1267 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1268 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1269 }
1270
1271 if (expiration != -1) {
1272 expiration += System.currentTimeMillis();
1273 }
1274 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1275 latitude, longitude, radius, expiration, intent);
1276 mProximityAlerts.put(intent, alert);
1277
Mike Lockwood48f17512009-04-23 09:12:08 -07001278 if (mProximityReceiver == null) {
1279 mProximityListener = new ProximityListener();
1280 mProximityReceiver = new Receiver(mProximityListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281
Mike Lockwood95427cd2009-05-07 13:27:54 -04001282 for (int i = mProviders.size() - 1; i >= 0; i--) {
1283 LocationProviderProxy provider = mProviders.get(i);
Mike Lockwood48f17512009-04-23 09:12:08 -07001284 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 }
1287 }
1288
1289 public void removeProximityAlert(PendingIntent intent) {
1290 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001291 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 removeProximityAlertLocked(intent);
1293 }
1294 } catch (SecurityException se) {
1295 throw se;
1296 } catch (Exception e) {
1297 Log.e(TAG, "removeProximityAlert got exception:", e);
1298 }
1299 }
1300
1301 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001302 if (LOCAL_LOGV) {
1303 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001304 }
1305
1306 mProximityAlerts.remove(intent);
1307 if (mProximityAlerts.size() == 0) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001308 removeUpdatesLocked(mProximityReceiver);
1309 mProximityReceiver = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001310 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 }
1312 }
1313
1314 /**
1315 * @return null if the provider does not exits
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001316 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 * accessed by the caller
1318 */
1319 public Bundle getProviderInfo(String provider) {
1320 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001321 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 return _getProviderInfoLocked(provider);
1323 }
1324 } catch (SecurityException se) {
1325 throw se;
1326 } catch (Exception e) {
1327 Log.e(TAG, "_getProviderInfo got exception:", e);
1328 return null;
1329 }
1330 }
1331
1332 private Bundle _getProviderInfoLocked(String provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001333 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 if (p == null) {
1335 return null;
1336 }
1337
1338 checkPermissionsSafe(provider);
1339
1340 Bundle b = new Bundle();
1341 b.putBoolean("network", p.requiresNetwork());
1342 b.putBoolean("satellite", p.requiresSatellite());
1343 b.putBoolean("cell", p.requiresCell());
1344 b.putBoolean("cost", p.hasMonetaryCost());
1345 b.putBoolean("altitude", p.supportsAltitude());
1346 b.putBoolean("speed", p.supportsSpeed());
1347 b.putBoolean("bearing", p.supportsBearing());
1348 b.putInt("power", p.getPowerRequirement());
1349 b.putInt("accuracy", p.getAccuracy());
1350
1351 return b;
1352 }
1353
1354 public boolean isProviderEnabled(String provider) {
1355 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001356 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001357 return _isProviderEnabledLocked(provider);
1358 }
1359 } catch (SecurityException se) {
1360 throw se;
1361 } catch (Exception e) {
1362 Log.e(TAG, "isProviderEnabled got exception:", e);
1363 return false;
1364 }
1365 }
1366
Mike Lockwood275555c2009-05-01 11:30:34 -04001367 public void reportLocation(Location location) {
1368 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1369 != PackageManager.PERMISSION_GRANTED) {
1370 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1371 }
1372
Mike Lockwood4e50b782009-04-03 08:24:43 -07001373 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1374 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1375 mLocationHandler.sendMessageAtFrontOfQueue(m);
1376 }
1377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 private boolean _isProviderEnabledLocked(String provider) {
1379 checkPermissionsSafe(provider);
1380
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001381 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001382 if (p == null) {
1383 throw new IllegalArgumentException("provider=" + provider);
1384 }
1385 return isAllowedBySettingsLocked(provider);
1386 }
1387
1388 public Location getLastKnownLocation(String provider) {
1389 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001390 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 return _getLastKnownLocationLocked(provider);
1392 }
1393 } catch (SecurityException se) {
1394 throw se;
1395 } catch (Exception e) {
1396 Log.e(TAG, "getLastKnownLocation got exception:", e);
1397 return null;
1398 }
1399 }
1400
1401 private Location _getLastKnownLocationLocked(String provider) {
1402 checkPermissionsSafe(provider);
1403
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001404 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001405 if (p == null) {
1406 throw new IllegalArgumentException("provider=" + provider);
1407 }
1408
1409 if (!isAllowedBySettingsLocked(provider)) {
1410 return null;
1411 }
1412
Mike Lockwood9aa1fa22009-09-01 07:51:15 -04001413 return mLastKnownLocation.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 }
1415
1416 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1417 // Always broadcast the first update
1418 if (lastLoc == null) {
1419 return true;
1420 }
1421
1422 // Don't broadcast same location again regardless of condition
1423 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1424 if (loc.getTime() == lastLoc.getTime()) {
1425 return false;
1426 }
1427
1428 // Check whether sufficient distance has been traveled
1429 double minDistance = record.mMinDistance;
1430 if (minDistance > 0.0) {
1431 if (loc.distanceTo(lastLoc) <= minDistance) {
1432 return false;
1433 }
1434 }
1435
1436 return true;
1437 }
1438
Mike Lockwood4e50b782009-04-03 08:24:43 -07001439 private void handleLocationChangedLocked(Location location) {
1440 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1442 if (records == null || records.size() == 0) {
1443 return;
1444 }
1445
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001446 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 if (p == null) {
1448 return;
1449 }
1450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001451 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001452 Location lastLocation = mLastKnownLocation.get(provider);
1453 if (lastLocation == null) {
1454 mLastKnownLocation.put(provider, new Location(location));
1455 } else {
1456 lastLocation.set(location);
1457 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 // Fetch latest status update time
1460 long newStatusUpdateTime = p.getStatusUpdateTime();
1461
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001462 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 Bundle extras = new Bundle();
1464 int status = p.getStatus(extras);
1465
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001466 ArrayList<Receiver> deadReceivers = null;
1467
1468 // Broadcast location or status to all listeners
1469 final int N = records.size();
1470 for (int i=0; i<N; i++) {
1471 UpdateRecord r = records.get(i);
1472 Receiver receiver = r.mReceiver;
1473
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001474 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001475 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1476 if (lastLoc == null) {
1477 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001478 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001479 } else {
1480 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001482 if (!receiver.callLocationChangedLocked(location)) {
1483 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1484 if (deadReceivers == null) {
1485 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001487 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 }
1489 }
1490
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001491 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001492 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1493 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1494
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001495 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1497 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1498 if (deadReceivers == null) {
1499 deadReceivers = new ArrayList<Receiver>();
1500 }
1501 if (!deadReceivers.contains(receiver)) {
1502 deadReceivers.add(receiver);
1503 }
1504 }
1505 }
1506 }
1507
1508 if (deadReceivers != null) {
1509 for (int i=deadReceivers.size()-1; i>=0; i--) {
1510 removeUpdatesLocked(deadReceivers.get(i));
1511 }
1512 }
1513 }
1514
1515 private class LocationWorkerHandler extends Handler {
1516
1517 @Override
1518 public void handleMessage(Message msg) {
1519 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001520 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1521 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001523 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001524 Location location = (Location) msg.obj;
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001525 String provider = location.getProvider();
Mike Lockwood98cb6672009-04-17 18:03:44 -04001526
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001527 // notify other providers of the new location
1528 for (int i = mProviders.size() - 1; i >= 0; i--) {
1529 LocationProviderProxy proxy = mProviders.get(i);
1530 if (!provider.equals(proxy.getName())) {
1531 proxy.updateLocation(location);
Mike Lockwood98cb6672009-04-17 18:03:44 -04001532 }
1533 }
1534
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001535 if (isAllowedBySettingsLocked(provider)) {
1536 handleLocationChangedLocked(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001539 }
1540 } catch (Exception e) {
1541 // Log, don't crash!
1542 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1543 }
1544 }
1545 }
1546
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001547 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1548 @Override
1549 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 String action = intent.getAction();
1551
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001552 if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001554 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1556 if (uid >= 0) {
1557 ArrayList<Receiver> removedRecs = null;
1558 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1559 for (int j=i.size()-1; j>=0; j--) {
1560 UpdateRecord ur = i.get(j);
1561 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1562 if (removedRecs == null) {
1563 removedRecs = new ArrayList<Receiver>();
1564 }
1565 if (!removedRecs.contains(ur.mReceiver)) {
1566 removedRecs.add(ur.mReceiver);
1567 }
1568 }
1569 }
1570 }
1571 ArrayList<ProximityAlert> removedAlerts = null;
1572 for (ProximityAlert i : mProximityAlerts.values()) {
1573 if (i.mUid == uid) {
1574 if (removedAlerts == null) {
1575 removedAlerts = new ArrayList<ProximityAlert>();
1576 }
1577 if (!removedAlerts.contains(i)) {
1578 removedAlerts.add(i);
1579 }
1580 }
1581 }
1582 if (removedRecs != null) {
1583 for (int i=removedRecs.size()-1; i>=0; i--) {
1584 removeUpdatesLocked(removedRecs.get(i));
1585 }
1586 }
1587 if (removedAlerts != null) {
1588 for (int i=removedAlerts.size()-1; i>=0; i--) {
1589 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1590 }
1591 }
1592 }
1593 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001594 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001595 boolean noConnectivity =
1596 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1597 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001598 mNetworkState = LocationProvider.AVAILABLE;
1599 } else {
1600 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 }
Mike Lockwood03d24672009-10-08 15:45:03 -04001602 NetworkInfo info =
1603 (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604
1605 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001606 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001607 for (int i = mProviders.size() - 1; i >= 0; i--) {
1608 LocationProviderProxy provider = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001609 if (provider.requiresNetwork()) {
Mike Lockwood03d24672009-10-08 15:45:03 -04001610 provider.updateNetworkState(mNetworkState, info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 }
1612 }
1613 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001615 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001616 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617
1618 // Wake locks
1619
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001620 private void incrementPendingBroadcasts() {
1621 synchronized (mWakeLock) {
1622 if (mPendingBroadcasts++ == 0) {
1623 try {
1624 mWakeLock.acquire();
1625 log("Acquired wakelock");
1626 } catch (Exception e) {
1627 // This is to catch a runtime exception thrown when we try to release an
1628 // already released lock.
1629 Log.e(TAG, "exception in acquireWakeLock()", e);
1630 }
1631 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001632 }
1633 }
1634
1635 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001636 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001637 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001638 try {
1639 // Release wake lock
1640 if (mWakeLock.isHeld()) {
1641 mWakeLock.release();
1642 log("Released wakelock");
1643 } else {
1644 log("Can't release wakelock again!");
1645 }
1646 } catch (Exception e) {
1647 // This is to catch a runtime exception thrown when we try to release an
1648 // already released lock.
1649 Log.e(TAG, "exception in releaseWakeLock()", e);
1650 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001651 }
1652 }
1653 }
1654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 // Geocoder
1656
1657 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001658 String language, String country, String variant, String appName, List<Address> addrs) {
1659 if (mGeocodeProvider != null) {
1660 try {
1661 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1662 variant, appName, addrs);
1663 } catch (RemoteException e) {
1664 Log.e(TAG, "getFromLocation failed", e);
Mike Lockwood3681f262009-05-12 10:52:03 -04001665 mGeocodeProvider = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
1667 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001668 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 }
1670
Mike Lockwooda55c3212009-04-15 11:10:11 -04001671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001672 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001673 double lowerLeftLatitude, double lowerLeftLongitude,
1674 double upperRightLatitude, double upperRightLongitude, int maxResults,
1675 String language, String country, String variant, String appName, List<Address> addrs) {
1676
1677 if (mGeocodeProvider != null) {
1678 try {
1679 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1680 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1681 maxResults, language, country, variant, appName, addrs);
1682 } catch (RemoteException e) {
1683 Log.e(TAG, "getFromLocationName failed", e);
Mike Lockwood3681f262009-05-12 10:52:03 -04001684 mGeocodeProvider = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 }
1686 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001687 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 }
1689
1690 // Mock Providers
1691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692 private void checkMockPermissionsSafe() {
1693 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1694 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1695 if (!allowMocks) {
1696 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1697 }
1698
1699 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1700 PackageManager.PERMISSION_GRANTED) {
1701 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1702 }
1703 }
1704
1705 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1706 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1707 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1708 checkMockPermissionsSafe();
1709
Mike Lockwood86328a92009-10-23 08:38:25 -04001710 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001711 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001712 MockProvider provider = new MockProvider(name, this,
1713 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 requiresCell, hasMonetaryCost, supportsAltitude,
1715 supportsSpeed, supportsBearing, powerRequirement, accuracy);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001716 // remove the real provider if we are replacing GPS or network provider
1717 if (LocationManager.GPS_PROVIDER.equals(name)
1718 || LocationManager.NETWORK_PROVIDER.equals(name)) {
1719 LocationProviderProxy proxy = mProvidersByName.get(name);
1720 if (proxy != null) {
1721 proxy.enableLocationTracking(false);
1722 removeProvider(proxy);
1723 }
1724 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001725 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1727 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001728 addProvider(new LocationProviderProxy(name, provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001729 mMockProviders.put(name, provider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001730 mLastKnownLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 updateProvidersLocked();
1732 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001733 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001734 }
1735
1736 public void removeTestProvider(String provider) {
1737 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001738 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001739 MockProvider mockProvider = mMockProviders.get(provider);
1740 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001741 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1742 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001743 long identity = Binder.clearCallingIdentity();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001744 removeProvider(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001745 mMockProviders.remove(mockProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001746 // reinstall real provider if we were mocking GPS or network provider
1747 if (LocationManager.GPS_PROVIDER.equals(provider) &&
1748 mGpsLocationProvider != null) {
1749 addProvider(mGpsLocationProvider);
1750 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
1751 mNetworkLocationProvider != null) {
1752 addProvider(mNetworkLocationProvider);
1753 }
1754 mLastKnownLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001756 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 }
1758 }
1759
1760 public void setTestProviderLocation(String provider, Location loc) {
1761 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001762 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001763 MockProvider mockProvider = mMockProviders.get(provider);
1764 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1766 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001767 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1768 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001769 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001770 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 }
1772 }
1773
1774 public void clearTestProviderLocation(String provider) {
1775 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001776 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001777 MockProvider mockProvider = mMockProviders.get(provider);
1778 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001779 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1780 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001781 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001782 }
1783 }
1784
1785 public void setTestProviderEnabled(String provider, boolean enabled) {
1786 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001787 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001788 MockProvider mockProvider = mMockProviders.get(provider);
1789 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1791 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001792 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001794 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 mEnabledProviders.add(provider);
1796 mDisabledProviders.remove(provider);
1797 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001798 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 mEnabledProviders.remove(provider);
1800 mDisabledProviders.add(provider);
1801 }
1802 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001803 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 }
1805 }
1806
1807 public void clearTestProviderEnabled(String provider) {
1808 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001809 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001810 MockProvider mockProvider = mMockProviders.get(provider);
1811 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1813 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001814 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 mEnabledProviders.remove(provider);
1816 mDisabledProviders.remove(provider);
1817 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001818 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001819 }
1820 }
1821
1822 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
1823 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001824 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001825 MockProvider mockProvider = mMockProviders.get(provider);
1826 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1828 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001829 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831 }
1832
1833 public void clearTestProviderStatus(String provider) {
1834 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001835 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001836 MockProvider mockProvider = mMockProviders.get(provider);
1837 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1839 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001840 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 }
1842 }
1843
1844 private void log(String log) {
1845 if (Log.isLoggable(TAG, Log.VERBOSE)) {
1846 Log.d(TAG, log);
1847 }
1848 }
1849
1850 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1851 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1852 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001853 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001854 + Binder.getCallingPid()
1855 + ", uid=" + Binder.getCallingUid());
1856 return;
1857 }
1858
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001859 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001860 pw.println("Current Location Manager state:");
1861 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001862 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001863 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001864 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001865 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001866 }
1867 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001868 for (Receiver i : mReceivers.values()) {
1869 pw.println(" " + i + ":");
1870 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 pw.println(" " + j.getKey() + ":");
1872 j.getValue().dump(pw, " ");
1873 }
1874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 pw.println(" Records by Provider:");
1876 for (Map.Entry<String, ArrayList<UpdateRecord>> i
1877 : mRecordsByProvider.entrySet()) {
1878 pw.println(" " + i.getKey() + ":");
1879 for (UpdateRecord j : i.getValue()) {
1880 pw.println(" " + j + ":");
1881 j.dump(pw, " ");
1882 }
1883 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001884 pw.println(" Last Known Locations:");
1885 for (Map.Entry<String, Location> i
1886 : mLastKnownLocation.entrySet()) {
1887 pw.println(" " + i.getKey() + ":");
1888 i.getValue().dump(new PrintWriterPrinter(pw), " ");
1889 }
1890 if (mProximityAlerts.size() > 0) {
1891 pw.println(" Proximity Alerts:");
1892 for (Map.Entry<PendingIntent, ProximityAlert> i
1893 : mProximityAlerts.entrySet()) {
1894 pw.println(" " + i.getKey() + ":");
1895 i.getValue().dump(pw, " ");
1896 }
1897 }
1898 if (mProximitiesEntered.size() > 0) {
1899 pw.println(" Proximities Entered:");
1900 for (ProximityAlert i : mProximitiesEntered) {
1901 pw.println(" " + i + ":");
1902 i.dump(pw, " ");
1903 }
1904 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001905 pw.println(" mProximityReceiver=" + mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 pw.println(" mProximityListener=" + mProximityListener);
1907 if (mEnabledProviders.size() > 0) {
1908 pw.println(" Enabled Providers:");
1909 for (String i : mEnabledProviders) {
1910 pw.println(" " + i);
1911 }
1912
1913 }
1914 if (mDisabledProviders.size() > 0) {
1915 pw.println(" Disabled Providers:");
1916 for (String i : mDisabledProviders) {
1917 pw.println(" " + i);
1918 }
1919
1920 }
1921 if (mMockProviders.size() > 0) {
1922 pw.println(" Mock Providers:");
1923 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001924 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 }
1926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001927 }
1928 }
1929}