blob: 0e1e0d953d4910ff75f448adeab3dd66df816883 [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
19import java.io.BufferedReader;
20import java.io.File;
21import java.io.FileDescriptor;
22import java.io.FileReader;
23import java.io.FileWriter;
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.List;
30import java.util.Map;
Mike Lockwood9637d472009-04-02 21:41:57 -070031import java.util.Observable;
32import java.util.Observer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import java.util.Set;
34import java.util.regex.Pattern;
35
36import android.app.AlarmManager;
37import android.app.PendingIntent;
38import android.content.BroadcastReceiver;
Mike Lockwood9637d472009-04-02 21:41:57 -070039import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.ContentResolver;
41import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
44import android.content.pm.PackageManager;
Mike Lockwood9637d472009-04-02 21:41:57 -070045import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.location.Address;
Mike Lockwooda55c3212009-04-15 11:10:11 -040047import android.location.IGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.location.IGpsStatusListener;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070049import android.location.ILocationCollector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.location.ILocationListener;
51import android.location.ILocationManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070052import android.location.ILocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.location.Location;
54import android.location.LocationManager;
55import android.location.LocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.net.ConnectivityManager;
57import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.os.Binder;
59import android.os.Bundle;
60import android.os.Handler;
61import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070062import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.os.Message;
64import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070065import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.os.RemoteException;
67import android.os.SystemClock;
68import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.util.Config;
70import android.util.Log;
71import android.util.PrintWriterPrinter;
72import android.util.SparseIntArray;
73
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import com.android.internal.location.GpsLocationProvider;
Mike Lockwood79762a32009-04-28 11:31:44 -040075import com.android.internal.location.LocationProviderImpl;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070076import com.android.internal.location.LocationProviderProxy;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070077import com.android.internal.location.MockProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import com.android.server.am.BatteryStatsService;
79
80/**
81 * The service class that manages LocationProviders and issues location
82 * updates and alerts.
83 *
84 * {@hide}
85 */
Mike Lockwood3d12b512009-04-21 23:25:35 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
The Android Open Source Project10592532009-03-18 17:39:46 -070088 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 // Minimum time interval between last known location writes, in milliseconds.
91 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L;
92
93 // Max time to hold wake lock for, in milliseconds.
94 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 // The last time a location was written, by provider name.
97 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
98
99 private static final Pattern PATTERN_COMMA = Pattern.compile(",");
100
101 private static final String ACCESS_FINE_LOCATION =
102 android.Manifest.permission.ACCESS_FINE_LOCATION;
103 private static final String ACCESS_COARSE_LOCATION =
104 android.Manifest.permission.ACCESS_COARSE_LOCATION;
105 private static final String ACCESS_MOCK_LOCATION =
106 android.Manifest.permission.ACCESS_MOCK_LOCATION;
107 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
108 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
109
110 // Set of providers that are explicitly enabled
111 private final Set<String> mEnabledProviders = new HashSet<String>();
112
113 // Set of providers that are explicitly disabled
114 private final Set<String> mDisabledProviders = new HashSet<String>();
115
116 // Locations, status values, and extras for mock providers
Mike Lockwood7ec434e2009-03-27 07:46:48 -0700117 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
119 private static boolean sProvidersLoaded = false;
120
121 private final Context mContext;
122 private GpsLocationProvider mGpsLocationProvider;
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700123 private LocationProviderProxy mNetworkLocationProvider;
Mike Lockwooda55c3212009-04-15 11:10:11 -0400124 private IGeocodeProvider mGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private LocationWorkerHandler mLocationHandler;
126
127 // Handler messages
Mike Lockwood4e50b782009-04-03 08:24:43 -0700128 private static final int MESSAGE_LOCATION_CHANGED = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 // Alarm manager and wakelock variables
131 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
132 private final static String WAKELOCK_KEY = "LocationManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 private AlarmManager mAlarmManager;
134 private long mAlarmInterval = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private PowerManager.WakeLock mWakeLock = null;
Mike Lockwood48f17512009-04-23 09:12:08 -0700136 private int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137 private long mWakeLockAcquireTime = 0;
138 private boolean mWakeLockGpsReceived = true;
139 private boolean mWakeLockNetworkReceived = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400142 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400144 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145
146 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400147 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800148 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400149 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150
151 /**
152 * Mapping from provider name to all its UpdateRecords
153 */
154 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
155 new HashMap<String,ArrayList<UpdateRecord>>();
156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 // Proximity listeners
Mike Lockwood48f17512009-04-23 09:12:08 -0700158 private Receiver mProximityReceiver = null;
159 private ILocationListener mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
161 new HashMap<PendingIntent,ProximityAlert>();
162 private HashSet<ProximityAlert> mProximitiesEntered =
163 new HashSet<ProximityAlert>();
164
165 // Last known location for each provider
166 private HashMap<String,Location> mLastKnownLocation =
167 new HashMap<String,Location>();
168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800169 // Location collector
170 private ILocationCollector mCollector;
171
The Android Open Source Project4df24232009-03-05 14:34:35 -0800172 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800173
Mike Lockwood9637d472009-04-02 21:41:57 -0700174 // for Settings change notification
175 private ContentQueryMap mSettings;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 /**
178 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
179 * location updates.
180 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700181 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800182 final ILocationListener mListener;
183 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184 final Object mKey;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400185 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Mike Lockwood48f17512009-04-23 09:12:08 -0700186 int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400188 Receiver(ILocationListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 mListener = listener;
190 mPendingIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 mKey = listener.asBinder();
192 }
193
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400194 Receiver(PendingIntent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 mPendingIntent = intent;
196 mListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 mKey = intent;
198 }
199
200 @Override
201 public boolean equals(Object otherObj) {
202 if (otherObj instanceof Receiver) {
203 return mKey.equals(
204 ((Receiver)otherObj).mKey);
205 }
206 return false;
207 }
208
209 @Override
210 public int hashCode() {
211 return mKey.hashCode();
212 }
213
214
215 @Override
216 public String toString() {
217 if (mListener != null) {
218 return "Receiver{"
219 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400220 + " Listener " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 } else {
222 return "Receiver{"
223 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400224 + " Intent " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 }
226 }
227
228 public boolean isListener() {
229 return mListener != null;
230 }
231
232 public boolean isPendingIntent() {
233 return mPendingIntent != null;
234 }
235
236 public ILocationListener getListener() {
237 if (mListener != null) {
238 return mListener;
239 }
240 throw new IllegalStateException("Request for non-existent listener");
241 }
242
243 public PendingIntent getPendingIntent() {
244 if (mPendingIntent != null) {
245 return mPendingIntent;
246 }
247 throw new IllegalStateException("Request for non-existent intent");
248 }
249
250 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
251 if (mListener != null) {
252 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700253 synchronized (this) {
254 // synchronize to ensure incrementPendingBroadcastsLocked()
255 // is called before decrementPendingBroadcasts()
256 mListener.onStatusChanged(provider, status, extras);
257 if (mListener != mProximityListener) {
258 // call this after broadcasting so we do not increment
259 // if we throw an exeption.
260 incrementPendingBroadcastsLocked();
261 }
262 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 } catch (RemoteException e) {
264 return false;
265 }
266 } else {
267 Intent statusChanged = new Intent();
268 statusChanged.putExtras(extras);
269 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
270 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700271 synchronized (this) {
272 // synchronize to ensure incrementPendingBroadcastsLocked()
273 // is called before decrementPendingBroadcasts()
274 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
275 // call this after broadcasting so we do not increment
276 // if we throw an exeption.
277 incrementPendingBroadcastsLocked();
278 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 } catch (PendingIntent.CanceledException e) {
280 return false;
281 }
282 }
283 return true;
284 }
285
286 public boolean callLocationChangedLocked(Location location) {
287 if (mListener != null) {
288 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700289 synchronized (this) {
290 // synchronize to ensure incrementPendingBroadcastsLocked()
291 // is called before decrementPendingBroadcasts()
292 mListener.onLocationChanged(location);
293 if (mListener != mProximityListener) {
294 // call this after broadcasting so we do not increment
295 // if we throw an exeption.
296 incrementPendingBroadcastsLocked();
297 }
298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 } catch (RemoteException e) {
300 return false;
301 }
302 } else {
303 Intent locationChanged = new Intent();
304 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
305 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700306 synchronized (this) {
307 // synchronize to ensure incrementPendingBroadcastsLocked()
308 // is called before decrementPendingBroadcasts()
309 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
310 // call this after broadcasting so we do not increment
311 // if we throw an exeption.
312 incrementPendingBroadcastsLocked();
313 }
314 } catch (PendingIntent.CanceledException e) {
315 return false;
316 }
317 }
318 return true;
319 }
320
321 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
322 if (mListener != null) {
323 try {
324 synchronized (this) {
325 // synchronize to ensure incrementPendingBroadcastsLocked()
326 // is called before decrementPendingBroadcasts()
327 if (enabled) {
328 mListener.onProviderEnabled(provider);
329 } else {
330 mListener.onProviderDisabled(provider);
331 }
332 if (mListener != mProximityListener) {
333 // call this after broadcasting so we do not increment
334 // if we throw an exeption.
335 incrementPendingBroadcastsLocked();
336 }
337 }
338 } catch (RemoteException e) {
339 return false;
340 }
341 } else {
342 Intent providerIntent = new Intent();
343 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
344 try {
345 synchronized (this) {
346 // synchronize to ensure incrementPendingBroadcastsLocked()
347 // is called before decrementPendingBroadcasts()
348 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
349 // call this after broadcasting so we do not increment
350 // if we throw an exeption.
351 incrementPendingBroadcastsLocked();
352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353 } catch (PendingIntent.CanceledException e) {
354 return false;
355 }
356 }
357 return true;
358 }
359
360 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700361 if (LOCAL_LOGV) {
362 Log.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400364 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 removeUpdatesLocked(this);
366 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700367 synchronized (this) {
368 if (mPendingBroadcasts > 0) {
369 LocationManagerService.this.decrementPendingBroadcasts();
370 mPendingBroadcasts = 0;
371 }
372 }
373 }
374
375 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
376 int resultCode, String resultData, Bundle resultExtras) {
377 decrementPendingBroadcasts();
378 }
379
380 // this must be called while synchronized by callerin a synchronized block
381 // containing the sending of the broadcaset
382 private void incrementPendingBroadcastsLocked() {
383 if (mPendingBroadcasts++ == 0) {
384 synchronized (mLock) {
385 LocationManagerService.this.incrementPendingBroadcastsLocked();
386 }
387 }
388 }
389
390 private void decrementPendingBroadcasts() {
391 synchronized (this) {
392 if (--mPendingBroadcasts == 0) {
393 LocationManagerService.this.decrementPendingBroadcasts();
394 }
395 }
396 }
397 }
398
399 public void locationCallbackFinished(ILocationListener listener) {
400 Receiver receiver = getReceiver(listener);
401 if (receiver != null) {
402 receiver.decrementPendingBroadcasts();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404 }
405
Mike Lockwood9637d472009-04-02 21:41:57 -0700406 private final class SettingsObserver implements Observer {
407 public void update(Observable o, Object arg) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400408 synchronized (mLock) {
Mike Lockwood9637d472009-04-02 21:41:57 -0700409 updateProvidersLocked();
410 }
411 }
412 }
413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 private Location readLastKnownLocationLocked(String provider) {
415 Location location = null;
416 String s = null;
417 try {
418 File f = new File(LocationManager.SYSTEM_DIR + "/location."
419 + provider);
420 if (!f.exists()) {
421 return null;
422 }
423 BufferedReader reader = new BufferedReader(new FileReader(f), 256);
424 s = reader.readLine();
425 } catch (IOException e) {
426 Log.w(TAG, "Unable to read last known location", e);
427 }
428
429 if (s == null) {
430 return null;
431 }
432 try {
433 String[] tokens = PATTERN_COMMA.split(s);
434 int idx = 0;
435 long time = Long.parseLong(tokens[idx++]);
436 double latitude = Double.parseDouble(tokens[idx++]);
437 double longitude = Double.parseDouble(tokens[idx++]);
438 double altitude = Double.parseDouble(tokens[idx++]);
439 float bearing = Float.parseFloat(tokens[idx++]);
440 float speed = Float.parseFloat(tokens[idx++]);
441
442 location = new Location(provider);
443 location.setTime(time);
444 location.setLatitude(latitude);
445 location.setLongitude(longitude);
446 location.setAltitude(altitude);
447 location.setBearing(bearing);
448 location.setSpeed(speed);
449 } catch (NumberFormatException nfe) {
450 Log.e(TAG, "NumberFormatException reading last known location", nfe);
451 return null;
452 }
453
454 return location;
455 }
456
457 private void writeLastKnownLocationLocked(String provider,
458 Location location) {
459 long now = SystemClock.elapsedRealtime();
460 Long last = mLastWriteTime.get(provider);
461 if ((last != null)
462 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
463 return;
464 }
465 mLastWriteTime.put(provider, now);
466
467 StringBuilder sb = new StringBuilder(100);
468 sb.append(location.getTime());
469 sb.append(',');
470 sb.append(location.getLatitude());
471 sb.append(',');
472 sb.append(location.getLongitude());
473 sb.append(',');
474 sb.append(location.getAltitude());
475 sb.append(',');
476 sb.append(location.getBearing());
477 sb.append(',');
478 sb.append(location.getSpeed());
479
480 FileWriter writer = null;
481 try {
482 File d = new File(LocationManager.SYSTEM_DIR);
483 if (!d.exists()) {
484 if (!d.mkdirs()) {
485 Log.w(TAG, "Unable to create directory to write location");
486 return;
487 }
488 }
489 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
490 writer = new FileWriter(f);
491 writer.write(sb.toString());
492 } catch (IOException e) {
493 Log.w(TAG, "Unable to write location", e);
494 } finally {
495 if (writer != null) {
496 try {
497 writer.close();
498 } catch (IOException e) {
499 Log.w(TAG, "Exception closing file", e);
500 }
501 }
502 }
503 }
504
505 /**
506 * Load providers from /data/location/<provider_name>/
507 * class
508 * kml
509 * nmea
510 * track
511 * location
512 * properties
513 */
514 private void loadProviders() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400515 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 if (sProvidersLoaded) {
517 return;
518 }
519
520 // Load providers
521 loadProvidersLocked();
522 sProvidersLoaded = true;
523 }
524 }
525
526 private void loadProvidersLocked() {
527 try {
528 _loadProvidersLocked();
529 } catch (Exception e) {
530 Log.e(TAG, "Exception loading providers:", e);
531 }
532 }
533
534 private void _loadProvidersLocked() {
535 // Attempt to load "real" providers first
536 if (GpsLocationProvider.isSupported()) {
537 // Create a gps location provider
Mike Lockwood4e50b782009-04-03 08:24:43 -0700538 mGpsLocationProvider = new GpsLocationProvider(mContext, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 LocationProviderImpl.addProvider(mGpsLocationProvider);
540 }
541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 updateProvidersLocked();
543 }
544
545 /**
546 * @param context the context that the LocationManagerService runs in
547 */
548 public LocationManagerService(Context context) {
549 super();
550 mContext = context;
Mike Lockwood3d12b512009-04-21 23:25:35 -0700551
552 Thread thread = new Thread(null, this, "LocationManagerService");
553 thread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800554
The Android Open Source Project10592532009-03-18 17:39:46 -0700555 if (LOCAL_LOGV) {
556 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
Mike Lockwood3d12b512009-04-21 23:25:35 -0700558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559
Mike Lockwood3d12b512009-04-21 23:25:35 -0700560 private void initialize() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 // Alarm manager, needs to be done before calling loadProviders() below
Mike Lockwood3d12b512009-04-21 23:25:35 -0700562 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563
564 // Create a wake lock, needs to be done before calling loadProviders() below
565 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
566 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 // Load providers
569 loadProviders();
570
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 // Register for Network (Wifi or Mobile) updates
572 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
573 IntentFilter networkIntentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
575 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700576 mContext.registerReceiver(networkReceiver, networkIntentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577
578 // Register for power updates
579 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
580 IntentFilter intentFilter = new IntentFilter();
581 intentFilter.addAction(ALARM_INTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
583 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700584 mContext.registerReceiver(powerStateReceiver, intentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585
Mike Lockwood9637d472009-04-02 21:41:57 -0700586 // listen for settings changes
587 ContentResolver resolver = mContext.getContentResolver();
588 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
589 "(" + Settings.System.NAME + "=?)",
590 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
591 null);
592 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
593 SettingsObserver settingsObserver = new SettingsObserver();
594 mSettings.addObserver(settingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 }
596
Mike Lockwood3d12b512009-04-21 23:25:35 -0700597 public void run()
598 {
599 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
600 Looper.prepare();
601 mLocationHandler = new LocationWorkerHandler();
602 initialize();
603 Looper.loop();
604 }
605
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700606 public void setNetworkLocationProvider(ILocationProvider provider) {
607 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
608 throw new SecurityException(
609 "Installing location providers outside of the system is not supported");
610 }
611
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400612 synchronized (mLock) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700613 mNetworkLocationProvider =
614 new LocationProviderProxy(LocationManager.NETWORK_PROVIDER, this, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 LocationProviderImpl.addProvider(mNetworkLocationProvider);
616 updateProvidersLocked();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800617
618 // notify NetworkLocationProvider of any events it might have missed
Mike Lockwoodf113fbe2009-04-06 05:17:28 -0700619 mNetworkLocationProvider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 }
621 }
622
623 public void setLocationCollector(ILocationCollector collector) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700624 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
625 throw new SecurityException(
626 "Installing location collectors outside of the system is not supported");
627 }
628
Mike Lockwood98cb6672009-04-17 18:03:44 -0400629 mCollector = collector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 }
631
Mike Lockwooda55c3212009-04-15 11:10:11 -0400632 public void setGeocodeProvider(IGeocodeProvider provider) {
633 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
634 throw new SecurityException(
635 "Installing location providers outside of the system is not supported");
636 }
637
638 mGeocodeProvider = provider;
639 }
640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 private boolean isAllowedBySettingsLocked(String provider) {
642 if (mEnabledProviders.contains(provider)) {
643 return true;
644 }
645 if (mDisabledProviders.contains(provider)) {
646 return false;
647 }
648 // Use system settings
649 ContentResolver resolver = mContext.getContentResolver();
650 String allowedProviders = Settings.Secure.getString(resolver,
651 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
652
653 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
654 }
655
656 private void checkPermissionsSafe(String provider) {
657 if (LocationManager.GPS_PROVIDER.equals(provider)
658 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
659 != PackageManager.PERMISSION_GRANTED)) {
660 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
661 }
662 if (LocationManager.NETWORK_PROVIDER.equals(provider)
663 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
664 != PackageManager.PERMISSION_GRANTED)
665 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
666 != PackageManager.PERMISSION_GRANTED)) {
667 throw new SecurityException(
668 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
669 }
670 }
671
672 private boolean isAllowedProviderSafe(String provider) {
673 if (LocationManager.GPS_PROVIDER.equals(provider)
674 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
675 != PackageManager.PERMISSION_GRANTED)) {
676 return false;
677 }
678 if (LocationManager.NETWORK_PROVIDER.equals(provider)
679 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
680 != PackageManager.PERMISSION_GRANTED)
681 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
682 != PackageManager.PERMISSION_GRANTED)) {
683 return false;
684 }
685
686 return true;
687 }
688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800689 public List<String> getAllProviders() {
690 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400691 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 return _getAllProvidersLocked();
693 }
694 } catch (SecurityException se) {
695 throw se;
696 } catch (Exception e) {
697 Log.e(TAG, "getAllProviders got exception:", e);
698 return null;
699 }
700 }
701
702 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700703 if (LOCAL_LOGV) {
704 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 }
Mike Lockwood662ea092009-04-28 16:56:30 -0400706 ArrayList<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 ArrayList<String> out = new ArrayList<String>(providers.size());
Mike Lockwood662ea092009-04-28 16:56:30 -0400708 for (int i = providers.size() - 1; i >= 0; i--) {
709 LocationProviderImpl p = providers.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800710 out.add(p.getName());
711 }
712 return out;
713 }
714
715 public List<String> getProviders(boolean enabledOnly) {
716 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400717 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 return _getProvidersLocked(enabledOnly);
719 }
720 } catch (SecurityException se) {
721 throw se;
722 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700723 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 return null;
725 }
726 }
727
728 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700729 if (LOCAL_LOGV) {
730 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800731 }
Mike Lockwood662ea092009-04-28 16:56:30 -0400732 ArrayList<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
733 ArrayList<String> out = new ArrayList<String>(providers.size());
734 for (int i = providers.size() - 1; i >= 0; i--) {
735 LocationProviderImpl p = providers.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 String name = p.getName();
737 if (isAllowedProviderSafe(name)) {
738 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
739 continue;
740 }
741 out.add(name);
742 }
743 }
744 return out;
745 }
746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 private void updateProvidersLocked() {
Mike Lockwood662ea092009-04-28 16:56:30 -0400748 ArrayList<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
749 for (int i = providers.size() - 1; i >= 0; i--) {
750 LocationProviderImpl p = providers.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 boolean isEnabled = p.isEnabled();
752 String name = p.getName();
753 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
754
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 if (isEnabled && !shouldBeEnabled) {
756 updateProviderListenersLocked(name, false);
757 } else if (!isEnabled && shouldBeEnabled) {
758 updateProviderListenersLocked(name, true);
759 }
760
761 }
762 }
763
764 private void updateProviderListenersLocked(String provider, boolean enabled) {
765 int listeners = 0;
766
767 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
768 if (p == null) {
769 return;
770 }
771
772 ArrayList<Receiver> deadReceivers = null;
773
774 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
775 if (records != null) {
776 final int N = records.size();
777 for (int i=0; i<N; i++) {
778 UpdateRecord record = records.get(i);
779 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700780 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
781 if (deadReceivers == null) {
782 deadReceivers = new ArrayList<Receiver>();
783 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786 listeners++;
787 }
788 }
789
790 if (deadReceivers != null) {
791 for (int i=deadReceivers.size()-1; i>=0; i--) {
792 removeUpdatesLocked(deadReceivers.get(i));
793 }
794 }
795
796 if (enabled) {
797 p.enable();
798 if (listeners > 0) {
799 p.setMinTime(getMinTimeLocked(provider));
800 p.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -0700801 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800802 }
803 } else {
804 p.enableLocationTracking(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 p.disable();
Mike Lockwood61fc2862009-04-21 20:02:52 -0700806 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
809
810 private long getMinTimeLocked(String provider) {
811 long minTime = Long.MAX_VALUE;
812 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
813 if (records != null) {
814 for (int i=records.size()-1; i>=0; i--) {
815 minTime = Math.min(minTime, records.get(i).mMinTime);
816 }
817 }
818 return minTime;
819 }
820
821 private class UpdateRecord {
822 final String mProvider;
823 final Receiver mReceiver;
824 final long mMinTime;
825 final float mMinDistance;
826 final int mUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400827 Location mLastFixBroadcast;
828 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829
830 /**
831 * Note: must be constructed with lock held.
832 */
833 UpdateRecord(String provider, long minTime, float minDistance,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400834 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 mProvider = provider;
836 mReceiver = receiver;
837 mMinTime = minTime;
838 mMinDistance = minDistance;
839 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800840
841 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
842 if (records == null) {
843 records = new ArrayList<UpdateRecord>();
844 mRecordsByProvider.put(provider, records);
845 }
846 if (!records.contains(this)) {
847 records.add(this);
848 }
849 }
850
851 /**
852 * Method to be called when a record will no longer be used. Calling this multiple times
853 * must have the same effect as calling it once.
854 */
855 void disposeLocked() {
856 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
857 records.remove(this);
858 }
859
860 @Override
861 public String toString() {
862 return "UpdateRecord{"
863 + Integer.toHexString(System.identityHashCode(this))
864 + " " + mProvider + " " + mReceiver + "}";
865 }
866
867 void dump(PrintWriter pw, String prefix) {
868 pw.println(prefix + this);
869 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
870 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400871 pw.println(prefix + "mUid=" + mUid);
872 pw.println(prefix + "mLastFixBroadcast:");
873 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
874 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800875 }
876
877 /**
878 * Calls dispose().
879 */
880 @Override protected void finalize() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400881 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882 disposeLocked();
883 }
884 }
885 }
886
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400887 private Receiver getReceiver(ILocationListener listener) {
888 IBinder binder = listener.asBinder();
889 Receiver receiver = mReceivers.get(binder);
890 if (receiver == null) {
891 receiver = new Receiver(listener);
892 mReceivers.put(binder, receiver);
893
894 try {
895 if (receiver.isListener()) {
896 receiver.getListener().asBinder().linkToDeath(receiver, 0);
897 }
898 } catch (RemoteException e) {
899 Log.e(TAG, "linkToDeath failed:", e);
900 return null;
901 }
902 }
903 return receiver;
904 }
905
906 private Receiver getReceiver(PendingIntent intent) {
907 Receiver receiver = mReceivers.get(intent);
908 if (receiver == null) {
909 receiver = new Receiver(intent);
910 mReceivers.put(intent, receiver);
911 }
912 return receiver;
913 }
914
915 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
916 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
917 if (records != null) {
918 for (int i = records.size() - 1; i >= 0; i--) {
919 UpdateRecord record = records.get(i);
920 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
921 return true;
922 }
923 }
924 }
925 if (LocationManager.GPS_PROVIDER.equals(provider) ||
926 LocationManager.NETWORK_PROVIDER.equals(provider)) {
927 for (ProximityAlert alert : mProximityAlerts.values()) {
928 if (alert.mUid == uid) {
929 return true;
930 }
931 }
932 }
933 return false;
934 }
935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 public void requestLocationUpdates(String provider,
937 long minTime, float minDistance, ILocationListener listener) {
938
939 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400940 synchronized (mLock) {
941 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 }
943 } catch (SecurityException se) {
944 throw se;
945 } catch (Exception e) {
946 Log.e(TAG, "requestUpdates got exception:", e);
947 }
948 }
949
950 public void requestLocationUpdatesPI(String provider,
951 long minTime, float minDistance, PendingIntent intent) {
952 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400953 synchronized (mLock) {
954 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800955 }
956 } catch (SecurityException se) {
957 throw se;
958 } catch (Exception e) {
959 Log.e(TAG, "requestUpdates got exception:", e);
960 }
961 }
962
963 private void requestLocationUpdatesLocked(String provider,
964 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700965 if (LOCAL_LOGV) {
966 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800967 }
968
969 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
970 if (impl == null) {
971 throw new IllegalArgumentException("provider=" + provider);
972 }
973
974 checkPermissionsSafe(provider);
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 // so wakelock calls will succeed
977 final int callingUid = Binder.getCallingUid();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400978 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800979 long identity = Binder.clearCallingIdentity();
980 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400981 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
982 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (oldRecord != null) {
984 oldRecord.disposeLocked();
985 }
986
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400987 if (newUid) {
988 impl.addListener(callingUid);
989 }
990
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
992 if (isProviderEnabled) {
993 long minTimeForProvider = getMinTimeLocked(provider);
994 impl.setMinTime(minTimeForProvider);
995 impl.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -0700996 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 } else {
Mike Lockwood48f17512009-04-23 09:12:08 -0700998 // Notify the listener that updates are currently disabled
999 receiver.callProviderEnabledLocked(provider, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001000 }
1001 } finally {
1002 Binder.restoreCallingIdentity(identity);
1003 }
1004 }
1005
1006 public void removeUpdates(ILocationListener listener) {
1007 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001008 synchronized (mLock) {
1009 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 }
1011 } catch (SecurityException se) {
1012 throw se;
1013 } catch (Exception e) {
1014 Log.e(TAG, "removeUpdates got exception:", e);
1015 }
1016 }
1017
1018 public void removeUpdatesPI(PendingIntent intent) {
1019 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001020 synchronized (mLock) {
1021 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 }
1023 } catch (SecurityException se) {
1024 throw se;
1025 } catch (Exception e) {
1026 Log.e(TAG, "removeUpdates got exception:", e);
1027 }
1028 }
1029
1030 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001031 if (LOCAL_LOGV) {
1032 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 }
1034
1035 // so wakelock calls will succeed
1036 final int callingUid = Binder.getCallingUid();
1037 long identity = Binder.clearCallingIdentity();
1038 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001039 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1040 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 }
1042
1043 // Record which providers were associated with this listener
1044 HashSet<String> providers = new HashSet<String>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001045 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 if (oldRecords != null) {
1047 // Call dispose() on the obsolete update records.
1048 for (UpdateRecord record : oldRecords.values()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001049 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1050 LocationProviderImpl impl =
1051 LocationProviderImpl.getProvider(record.mProvider);
1052 if (impl != null) {
1053 impl.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
1055 }
1056 record.disposeLocked();
1057 }
1058 // Accumulate providers
1059 providers.addAll(oldRecords.keySet());
1060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061
1062 // See if the providers associated with this listener have any
1063 // other listeners; if one does, inform it of the new smallest minTime
1064 // value; if one does not, disable location tracking for it
1065 for (String provider : providers) {
1066 // If provider is already disabled, don't need to do anything
1067 if (!isAllowedBySettingsLocked(provider)) {
1068 continue;
1069 }
1070
1071 boolean hasOtherListener = false;
1072 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1073 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1074 hasOtherListener = true;
1075 }
1076
1077 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1078 if (p != null) {
1079 if (hasOtherListener) {
1080 p.setMinTime(getMinTimeLocked(provider));
1081 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 p.enableLocationTracking(false);
1083 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 }
1085 }
1086
Mike Lockwood61fc2862009-04-21 20:02:52 -07001087 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088 } finally {
1089 Binder.restoreCallingIdentity(identity);
1090 }
1091 }
1092
1093 public boolean addGpsStatusListener(IGpsStatusListener listener) {
1094 if (mGpsLocationProvider == null) {
1095 return false;
1096 }
1097 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
1098 PackageManager.PERMISSION_GRANTED) {
1099 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1100 }
1101
1102 try {
1103 mGpsLocationProvider.addGpsStatusListener(listener);
1104 } catch (RemoteException e) {
1105 Log.w(TAG, "RemoteException in addGpsStatusListener");
1106 return false;
1107 }
1108 return true;
1109 }
1110
1111 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001112 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001113 mGpsLocationProvider.removeGpsStatusListener(listener);
1114 }
1115 }
1116
1117 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1118 // first check for permission to the provider
1119 checkPermissionsSafe(provider);
1120 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1121 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1122 != PackageManager.PERMISSION_GRANTED)) {
1123 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1124 }
1125
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001126 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1128 if (provider == null) {
1129 return false;
1130 }
1131
1132 return impl.sendExtraCommand(command, extras);
1133 }
1134 }
1135
1136 class ProximityAlert {
1137 final int mUid;
1138 final double mLatitude;
1139 final double mLongitude;
1140 final float mRadius;
1141 final long mExpiration;
1142 final PendingIntent mIntent;
1143 final Location mLocation;
1144
1145 public ProximityAlert(int uid, double latitude, double longitude,
1146 float radius, long expiration, PendingIntent intent) {
1147 mUid = uid;
1148 mLatitude = latitude;
1149 mLongitude = longitude;
1150 mRadius = radius;
1151 mExpiration = expiration;
1152 mIntent = intent;
1153
1154 mLocation = new Location("");
1155 mLocation.setLatitude(latitude);
1156 mLocation.setLongitude(longitude);
1157 }
1158
1159 long getExpiration() {
1160 return mExpiration;
1161 }
1162
1163 PendingIntent getIntent() {
1164 return mIntent;
1165 }
1166
1167 boolean isInProximity(double latitude, double longitude) {
1168 Location loc = new Location("");
1169 loc.setLatitude(latitude);
1170 loc.setLongitude(longitude);
1171
1172 double radius = loc.distanceTo(mLocation);
1173 return radius <= mRadius;
1174 }
1175
1176 @Override
1177 public String toString() {
1178 return "ProximityAlert{"
1179 + Integer.toHexString(System.identityHashCode(this))
1180 + " uid " + mUid + mIntent + "}";
1181 }
1182
1183 void dump(PrintWriter pw, String prefix) {
1184 pw.println(prefix + this);
1185 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1186 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1187 pw.println(prefix + "mIntent=" + mIntent);
1188 pw.println(prefix + "mLocation:");
1189 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1190 }
1191 }
1192
1193 // Listener for receiving locations to trigger proximity alerts
Mike Lockwood48f17512009-04-23 09:12:08 -07001194 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195
1196 boolean isGpsAvailable = false;
1197
1198 // Note: this is called with the lock held.
1199 public void onLocationChanged(Location loc) {
1200
1201 // If Gps is available, then ignore updates from NetworkLocationProvider
1202 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1203 isGpsAvailable = true;
1204 }
1205 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1206 return;
1207 }
1208
1209 // Process proximity alerts
1210 long now = System.currentTimeMillis();
1211 double latitude = loc.getLatitude();
1212 double longitude = loc.getLongitude();
1213 ArrayList<PendingIntent> intentsToRemove = null;
1214
1215 for (ProximityAlert alert : mProximityAlerts.values()) {
1216 PendingIntent intent = alert.getIntent();
1217 long expiration = alert.getExpiration();
1218
1219 if ((expiration == -1) || (now <= expiration)) {
1220 boolean entered = mProximitiesEntered.contains(alert);
1221 boolean inProximity =
1222 alert.isInProximity(latitude, longitude);
1223 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001224 if (LOCAL_LOGV) {
1225 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001226 }
1227 mProximitiesEntered.add(alert);
1228 Intent enteredIntent = new Intent();
1229 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1230 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001231 synchronized (mLock) {
1232 // synchronize to ensure incrementPendingBroadcastsLocked()
1233 // is called before decrementPendingBroadcasts()
1234 intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
1235 // call this after broadcasting so we do not increment
1236 // if we throw an exeption.
1237 incrementPendingBroadcastsLocked();
1238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001240 if (LOCAL_LOGV) {
1241 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
1243 if (intentsToRemove == null) {
1244 intentsToRemove = new ArrayList<PendingIntent>();
1245 }
1246 intentsToRemove.add(intent);
1247 }
1248 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001249 if (LOCAL_LOGV) {
1250 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001251 }
1252 mProximitiesEntered.remove(alert);
1253 Intent exitedIntent = new Intent();
1254 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1255 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001256 synchronized (mLock) {
1257 // synchronize to ensure incrementPendingBroadcastsLocked()
1258 // is called before decrementPendingBroadcasts()
1259 intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
1260 // call this after broadcasting so we do not increment
1261 // if we throw an exeption.
1262 incrementPendingBroadcastsLocked();
1263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001265 if (LOCAL_LOGV) {
1266 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001267 }
1268 if (intentsToRemove == null) {
1269 intentsToRemove = new ArrayList<PendingIntent>();
1270 }
1271 intentsToRemove.add(intent);
1272 }
1273 }
1274 } else {
1275 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001276 if (LOCAL_LOGV) {
1277 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 }
1279 if (intentsToRemove == null) {
1280 intentsToRemove = new ArrayList<PendingIntent>();
1281 }
1282 intentsToRemove.add(alert.getIntent());
1283 }
1284 }
1285
1286 // Remove expired alerts
1287 if (intentsToRemove != null) {
1288 for (PendingIntent i : intentsToRemove) {
1289 mProximityAlerts.remove(i);
1290 ProximityAlert alert = mProximityAlerts.get(i);
1291 mProximitiesEntered.remove(alert);
1292 }
1293 }
1294
1295 }
1296
1297 // Note: this is called with the lock held.
1298 public void onProviderDisabled(String provider) {
1299 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1300 isGpsAvailable = false;
1301 }
1302 }
1303
1304 // Note: this is called with the lock held.
1305 public void onProviderEnabled(String provider) {
1306 // ignore
1307 }
1308
1309 // Note: this is called with the lock held.
1310 public void onStatusChanged(String provider, int status, Bundle extras) {
1311 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1312 (status != LocationProvider.AVAILABLE)) {
1313 isGpsAvailable = false;
1314 }
1315 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001316
1317 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1318 int resultCode, String resultData, Bundle resultExtras) {
1319 decrementPendingBroadcasts();
1320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 }
1322
1323 public void addProximityAlert(double latitude, double longitude,
1324 float radius, long expiration, PendingIntent intent) {
1325 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001326 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001327 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1328 }
1329 } catch (SecurityException se) {
1330 throw se;
1331 } catch (Exception e) {
1332 Log.e(TAG, "addProximityAlert got exception:", e);
1333 }
1334 }
1335
1336 private void addProximityAlertLocked(double latitude, double longitude,
1337 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001338 if (LOCAL_LOGV) {
1339 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001340 ", longitude = " + longitude +
1341 ", expiration = " + expiration +
1342 ", intent = " + intent);
1343 }
1344
1345 // Require ability to access all providers for now
1346 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1347 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1348 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1349 }
1350
1351 if (expiration != -1) {
1352 expiration += System.currentTimeMillis();
1353 }
1354 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1355 latitude, longitude, radius, expiration, intent);
1356 mProximityAlerts.put(intent, alert);
1357
Mike Lockwood48f17512009-04-23 09:12:08 -07001358 if (mProximityReceiver == null) {
1359 mProximityListener = new ProximityListener();
1360 mProximityReceiver = new Receiver(mProximityListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361
1362 LocationProvider provider = LocationProviderImpl.getProvider(
1363 LocationManager.GPS_PROVIDER);
1364 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001365 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 }
1367
1368 provider =
1369 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
1370 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001371 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001373 }
1374 }
1375
1376 public void removeProximityAlert(PendingIntent intent) {
1377 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001378 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001379 removeProximityAlertLocked(intent);
1380 }
1381 } catch (SecurityException se) {
1382 throw se;
1383 } catch (Exception e) {
1384 Log.e(TAG, "removeProximityAlert got exception:", e);
1385 }
1386 }
1387
1388 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001389 if (LOCAL_LOGV) {
1390 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 }
1392
1393 mProximityAlerts.remove(intent);
1394 if (mProximityAlerts.size() == 0) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001395 removeUpdatesLocked(mProximityReceiver);
1396 mProximityReceiver = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001397 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
1399 }
1400
1401 /**
1402 * @return null if the provider does not exits
1403 * @throw SecurityException if the provider is not allowed to be
1404 * accessed by the caller
1405 */
1406 public Bundle getProviderInfo(String provider) {
1407 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001408 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 return _getProviderInfoLocked(provider);
1410 }
1411 } catch (SecurityException se) {
1412 throw se;
1413 } catch (Exception e) {
1414 Log.e(TAG, "_getProviderInfo got exception:", e);
1415 return null;
1416 }
1417 }
1418
1419 private Bundle _getProviderInfoLocked(String provider) {
1420 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1421 if (p == null) {
1422 return null;
1423 }
1424
1425 checkPermissionsSafe(provider);
1426
1427 Bundle b = new Bundle();
1428 b.putBoolean("network", p.requiresNetwork());
1429 b.putBoolean("satellite", p.requiresSatellite());
1430 b.putBoolean("cell", p.requiresCell());
1431 b.putBoolean("cost", p.hasMonetaryCost());
1432 b.putBoolean("altitude", p.supportsAltitude());
1433 b.putBoolean("speed", p.supportsSpeed());
1434 b.putBoolean("bearing", p.supportsBearing());
1435 b.putInt("power", p.getPowerRequirement());
1436 b.putInt("accuracy", p.getAccuracy());
1437
1438 return b;
1439 }
1440
1441 public boolean isProviderEnabled(String provider) {
1442 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001443 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 return _isProviderEnabledLocked(provider);
1445 }
1446 } catch (SecurityException se) {
1447 throw se;
1448 } catch (Exception e) {
1449 Log.e(TAG, "isProviderEnabled got exception:", e);
1450 return false;
1451 }
1452 }
1453
Mike Lockwood4e50b782009-04-03 08:24:43 -07001454 public void setLocation(Location location) {
1455 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1456 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1457 mLocationHandler.sendMessageAtFrontOfQueue(m);
1458 }
1459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 private boolean _isProviderEnabledLocked(String provider) {
1461 checkPermissionsSafe(provider);
1462
1463 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1464 if (p == null) {
1465 throw new IllegalArgumentException("provider=" + provider);
1466 }
1467 return isAllowedBySettingsLocked(provider);
1468 }
1469
1470 public Location getLastKnownLocation(String provider) {
1471 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001472 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001473 return _getLastKnownLocationLocked(provider);
1474 }
1475 } catch (SecurityException se) {
1476 throw se;
1477 } catch (Exception e) {
1478 Log.e(TAG, "getLastKnownLocation got exception:", e);
1479 return null;
1480 }
1481 }
1482
1483 private Location _getLastKnownLocationLocked(String provider) {
1484 checkPermissionsSafe(provider);
1485
1486 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1487 if (p == null) {
1488 throw new IllegalArgumentException("provider=" + provider);
1489 }
1490
1491 if (!isAllowedBySettingsLocked(provider)) {
1492 return null;
1493 }
1494
1495 Location location = mLastKnownLocation.get(provider);
1496 if (location == null) {
1497 // Get the persistent last known location for the provider
1498 location = readLastKnownLocationLocked(provider);
1499 if (location != null) {
1500 mLastKnownLocation.put(provider, location);
1501 }
1502 }
1503
1504 return location;
1505 }
1506
1507 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1508 // Always broadcast the first update
1509 if (lastLoc == null) {
1510 return true;
1511 }
1512
1513 // Don't broadcast same location again regardless of condition
1514 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1515 if (loc.getTime() == lastLoc.getTime()) {
1516 return false;
1517 }
1518
1519 // Check whether sufficient distance has been traveled
1520 double minDistance = record.mMinDistance;
1521 if (minDistance > 0.0) {
1522 if (loc.distanceTo(lastLoc) <= minDistance) {
1523 return false;
1524 }
1525 }
1526
1527 return true;
1528 }
1529
Mike Lockwood4e50b782009-04-03 08:24:43 -07001530 private void handleLocationChangedLocked(Location location) {
1531 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001532 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1533 if (records == null || records.size() == 0) {
1534 return;
1535 }
1536
1537 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1538 if (p == null) {
1539 return;
1540 }
1541
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001543 Location lastLocation = mLastKnownLocation.get(provider);
1544 if (lastLocation == null) {
1545 mLastKnownLocation.put(provider, new Location(location));
1546 } else {
1547 lastLocation.set(location);
1548 }
1549 writeLastKnownLocationLocked(provider, location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001551 if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001552 mWakeLockNetworkReceived = true;
1553 } else if (p instanceof GpsLocationProvider) {
1554 // Gps location received signal is in NetworkStateBroadcastReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 }
1556
1557 // Fetch latest status update time
1558 long newStatusUpdateTime = p.getStatusUpdateTime();
1559
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001560 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 Bundle extras = new Bundle();
1562 int status = p.getStatus(extras);
1563
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 ArrayList<Receiver> deadReceivers = null;
1565
1566 // Broadcast location or status to all listeners
1567 final int N = records.size();
1568 for (int i=0; i<N; i++) {
1569 UpdateRecord r = records.get(i);
1570 Receiver receiver = r.mReceiver;
1571
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001572 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001573 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1574 if (lastLoc == null) {
1575 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001576 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001577 } else {
1578 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001580 if (!receiver.callLocationChangedLocked(location)) {
1581 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1582 if (deadReceivers == null) {
1583 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001585 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 }
1587 }
1588
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001589 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001590 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1591 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1592
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001593 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1595 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1596 if (deadReceivers == null) {
1597 deadReceivers = new ArrayList<Receiver>();
1598 }
1599 if (!deadReceivers.contains(receiver)) {
1600 deadReceivers.add(receiver);
1601 }
1602 }
1603 }
1604 }
1605
1606 if (deadReceivers != null) {
1607 for (int i=deadReceivers.size()-1; i>=0; i--) {
1608 removeUpdatesLocked(deadReceivers.get(i));
1609 }
1610 }
1611 }
1612
1613 private class LocationWorkerHandler extends Handler {
1614
1615 @Override
1616 public void handleMessage(Message msg) {
1617 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001618 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1619 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001621 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001622 Location location = (Location) msg.obj;
Mike Lockwood98cb6672009-04-17 18:03:44 -04001623
1624 if (mCollector != null &&
1625 LocationManager.GPS_PROVIDER.equals(location.getProvider())) {
1626 try {
1627 mCollector.updateLocation(location);
1628 } catch (RemoteException e) {
1629 Log.w(TAG, "mCollector.updateLocation failed");
1630 }
1631 }
1632
Mike Lockwood4e50b782009-04-03 08:24:43 -07001633 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 if (!isAllowedBySettingsLocked(provider)) {
1635 return;
1636 }
1637
Mike Lockwooda0e3cd32009-04-21 21:27:33 -07001638 handleLocationChangedLocked(location);
Mike Lockwood61fc2862009-04-21 20:02:52 -07001639 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 }
1642 } catch (Exception e) {
1643 // Log, don't crash!
1644 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1645 }
1646 }
1647 }
1648
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1650 @Override public void onReceive(Context context, Intent intent) {
1651 String action = intent.getAction();
1652
1653 if (action.equals(ALARM_INTENT)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001654 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 log("PowerStateBroadcastReceiver: Alarm received");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 // Have to do this immediately, rather than posting a
1657 // message, so we execute our code while the system
1658 // is holding a wake lock until the alarm broadcast
1659 // is finished.
1660 acquireWakeLockLocked();
1661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1663 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001664 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001665 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1666 if (uid >= 0) {
1667 ArrayList<Receiver> removedRecs = null;
1668 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1669 for (int j=i.size()-1; j>=0; j--) {
1670 UpdateRecord ur = i.get(j);
1671 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1672 if (removedRecs == null) {
1673 removedRecs = new ArrayList<Receiver>();
1674 }
1675 if (!removedRecs.contains(ur.mReceiver)) {
1676 removedRecs.add(ur.mReceiver);
1677 }
1678 }
1679 }
1680 }
1681 ArrayList<ProximityAlert> removedAlerts = null;
1682 for (ProximityAlert i : mProximityAlerts.values()) {
1683 if (i.mUid == uid) {
1684 if (removedAlerts == null) {
1685 removedAlerts = new ArrayList<ProximityAlert>();
1686 }
1687 if (!removedAlerts.contains(i)) {
1688 removedAlerts.add(i);
1689 }
1690 }
1691 }
1692 if (removedRecs != null) {
1693 for (int i=removedRecs.size()-1; i>=0; i--) {
1694 removeUpdatesLocked(removedRecs.get(i));
1695 }
1696 }
1697 if (removedAlerts != null) {
1698 for (int i=removedAlerts.size()-1; i>=0; i--) {
1699 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1700 }
1701 }
1702 }
1703 }
1704 }
1705 }
1706 }
1707
1708 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1709 @Override public void onReceive(Context context, Intent intent) {
1710 String action = intent.getAction();
1711
Mike Lockwoodf113fbe2009-04-06 05:17:28 -07001712 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 boolean noConnectivity =
1714 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1715 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001716 mNetworkState = LocationProvider.AVAILABLE;
1717 } else {
1718 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 }
1720
1721 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001722 synchronized (mLock) {
Mike Lockwood662ea092009-04-28 16:56:30 -04001723 ArrayList<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1724 for (int i = providers.size() - 1; i >= 0; i--) {
1725 LocationProviderImpl provider = providers.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726 if (provider.requiresNetwork()) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001727 provider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001728 }
1729 }
1730 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001731 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
1732
1733 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
1734 false);
1735
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001736 synchronized (mLock) {
Mike Lockwood98cb6672009-04-17 18:03:44 -04001737 if (!enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001738 // When GPS is disabled, we are OK to release wake-lock
1739 mWakeLockGpsReceived = true;
1740 }
1741 }
1742 }
1743
1744 }
1745 }
1746
1747 // Wake locks
1748
Mike Lockwood61fc2862009-04-21 20:02:52 -07001749 private void updateWakelockStatusLocked() {
1750 log("updateWakelockStatus()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001751
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001752 long callerId = Binder.clearCallingIdentity();
1753
Mike Lockwood48f17512009-04-23 09:12:08 -07001754 boolean needsLock = (mPendingBroadcasts > 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 long minTime = Integer.MAX_VALUE;
1756
1757 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
1758 needsLock = true;
1759 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
1760 }
1761
1762 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
1763 needsLock = true;
1764 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001765 }
1766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767 PendingIntent sender =
1768 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
1769
1770 // Cancel existing alarm
1771 log("Cancelling existing alarm");
1772 mAlarmManager.cancel(sender);
1773
Mike Lockwood61fc2862009-04-21 20:02:52 -07001774 if (needsLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001775 long now = SystemClock.elapsedRealtime();
1776 mAlarmManager.set(
1777 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
1778 mAlarmInterval = minTime;
1779 log("Creating a new wakelock alarm with minTime = " + minTime);
1780 } else {
1781 log("No need for alarm");
1782 mAlarmInterval = -1;
1783
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 releaseWakeLockLocked();
1785 }
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001786 Binder.restoreCallingIdentity(callerId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 }
1788
1789 private void acquireWakeLockLocked() {
1790 try {
1791 acquireWakeLockXLocked();
1792 } catch (Exception e) {
1793 // This is to catch a runtime exception thrown when we try to release an
1794 // already released lock.
1795 Log.e(TAG, "exception in acquireWakeLock()", e);
1796 }
1797 }
1798
1799 private void acquireWakeLockXLocked() {
1800 if (mWakeLock.isHeld()) {
1801 log("Must release wakelock before acquiring");
1802 mWakeLockAcquireTime = 0;
1803 mWakeLock.release();
1804 }
1805
1806 boolean networkActive = (mNetworkLocationProvider != null)
1807 && mNetworkLocationProvider.isLocationTracking();
1808 boolean gpsActive = (mGpsLocationProvider != null)
1809 && mGpsLocationProvider.isLocationTracking();
1810
1811 boolean needsLock = networkActive || gpsActive;
1812 if (!needsLock) {
1813 log("No need for Lock!");
1814 return;
1815 }
1816
1817 mWakeLockGpsReceived = !gpsActive;
1818 mWakeLockNetworkReceived = !networkActive;
1819
1820 // Acquire wake lock
1821 mWakeLock.acquire();
1822 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
1823 log("Acquired wakelock");
1824
Mike Lockwood6de31542009-04-21 12:13:35 -07001825 if (mNetworkLocationProvider != null) {
1826 mNetworkLocationProvider.wakeLockAcquired();
1827 }
1828 if (mGpsLocationProvider != null) {
1829 mGpsLocationProvider.wakeLockAcquired();
1830 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001831 }
1832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 private void releaseWakeLockLocked() {
1834 try {
1835 releaseWakeLockXLocked();
1836 } catch (Exception e) {
1837 // This is to catch a runtime exception thrown when we try to release an
1838 // already released lock.
1839 Log.e(TAG, "exception in releaseWakeLock()", e);
1840 }
1841 }
1842
1843 private void releaseWakeLockXLocked() {
Mike Lockwood6de31542009-04-21 12:13:35 -07001844 if (mNetworkLocationProvider != null) {
1845 mNetworkLocationProvider.wakeLockReleased();
1846 }
1847 if (mGpsLocationProvider != null) {
1848 mGpsLocationProvider.wakeLockReleased();
1849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850
1851 // Release wake lock
1852 mWakeLockAcquireTime = 0;
1853 if (mWakeLock.isHeld()) {
1854 log("Released wakelock");
1855 mWakeLock.release();
1856 } else {
1857 log("Can't release wakelock again!");
1858 }
1859 }
1860
Mike Lockwood48f17512009-04-23 09:12:08 -07001861 private void incrementPendingBroadcastsLocked() {
1862 if (mPendingBroadcasts++ == 0) {
1863 updateWakelockStatusLocked();
1864 }
1865 }
1866
1867 private void decrementPendingBroadcasts() {
1868 synchronized (mLock) {
1869 if (--mPendingBroadcasts == 0) {
1870 updateWakelockStatusLocked();
1871 }
1872 }
1873 }
1874
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001875 // Geocoder
1876
1877 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001878 String language, String country, String variant, String appName, List<Address> addrs) {
1879 if (mGeocodeProvider != null) {
1880 try {
1881 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1882 variant, appName, addrs);
1883 } catch (RemoteException e) {
1884 Log.e(TAG, "getFromLocation failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 }
1886 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001887 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
Mike Lockwooda55c3212009-04-15 11:10:11 -04001890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001892 double lowerLeftLatitude, double lowerLeftLongitude,
1893 double upperRightLatitude, double upperRightLongitude, int maxResults,
1894 String language, String country, String variant, String appName, List<Address> addrs) {
1895
1896 if (mGeocodeProvider != null) {
1897 try {
1898 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1899 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1900 maxResults, language, country, variant, appName, addrs);
1901 } catch (RemoteException e) {
1902 Log.e(TAG, "getFromLocationName failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001903 }
1904 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001905 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
1907
1908 // Mock Providers
1909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 private void checkMockPermissionsSafe() {
1911 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1912 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1913 if (!allowMocks) {
1914 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1915 }
1916
1917 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1918 PackageManager.PERMISSION_GRANTED) {
1919 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1920 }
1921 }
1922
1923 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1924 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1925 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1926 checkMockPermissionsSafe();
1927
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001928 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001929 MockProvider provider = new MockProvider(name, this,
1930 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 requiresCell, hasMonetaryCost, supportsAltitude,
1932 supportsSpeed, supportsBearing, powerRequirement, accuracy);
1933 if (LocationProviderImpl.getProvider(name) != null) {
1934 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1935 }
1936 LocationProviderImpl.addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001937 mMockProviders.put(name, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001938 updateProvidersLocked();
1939 }
1940 }
1941
1942 public void removeTestProvider(String provider) {
1943 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001944 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001945 MockProvider mockProvider = mMockProviders.get(provider);
1946 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1948 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001949 LocationProviderImpl.removeProvider(mockProvider);
1950 mMockProviders.remove(mockProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 updateProvidersLocked();
1952 }
1953 }
1954
1955 public void setTestProviderLocation(String provider, Location loc) {
1956 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001957 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001958 MockProvider mockProvider = mMockProviders.get(provider);
1959 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001960 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1961 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001962 mockProvider.setLocation(loc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001963 }
1964 }
1965
1966 public void clearTestProviderLocation(String provider) {
1967 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001968 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001969 MockProvider mockProvider = mMockProviders.get(provider);
1970 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001971 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1972 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001973 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001974 }
1975 }
1976
1977 public void setTestProviderEnabled(String provider, boolean enabled) {
1978 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001979 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001980 MockProvider mockProvider = mMockProviders.get(provider);
1981 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1983 }
1984 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001985 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 mEnabledProviders.add(provider);
1987 mDisabledProviders.remove(provider);
1988 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001989 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 mEnabledProviders.remove(provider);
1991 mDisabledProviders.add(provider);
1992 }
1993 updateProvidersLocked();
1994 }
1995 }
1996
1997 public void clearTestProviderEnabled(String provider) {
1998 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001999 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002000 MockProvider mockProvider = mMockProviders.get(provider);
2001 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2003 }
2004 mEnabledProviders.remove(provider);
2005 mDisabledProviders.remove(provider);
2006 updateProvidersLocked();
2007 }
2008 }
2009
2010 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2011 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002012 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002013 MockProvider mockProvider = mMockProviders.get(provider);
2014 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2016 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002017 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 }
2019 }
2020
2021 public void clearTestProviderStatus(String provider) {
2022 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002023 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002024 MockProvider mockProvider = mMockProviders.get(provider);
2025 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002026 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2027 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002028 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002029 }
2030 }
2031
2032 private void log(String log) {
2033 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2034 Log.d(TAG, log);
2035 }
2036 }
2037
2038 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2039 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2040 != PackageManager.PERMISSION_GRANTED) {
2041 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2042 + Binder.getCallingPid()
2043 + ", uid=" + Binder.getCallingUid());
2044 return;
2045 }
2046
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002047 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 pw.println("Current Location Manager state:");
2049 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2050 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 pw.println(" mCollector=" + mCollector);
2053 pw.println(" mAlarmInterval=" + mAlarmInterval
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2055 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2056 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002058 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002060 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 }
2062 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002063 for (Receiver i : mReceivers.values()) {
2064 pw.println(" " + i + ":");
2065 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 pw.println(" " + j.getKey() + ":");
2067 j.getValue().dump(pw, " ");
2068 }
2069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 pw.println(" Records by Provider:");
2071 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2072 : mRecordsByProvider.entrySet()) {
2073 pw.println(" " + i.getKey() + ":");
2074 for (UpdateRecord j : i.getValue()) {
2075 pw.println(" " + j + ":");
2076 j.dump(pw, " ");
2077 }
2078 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 pw.println(" Last Known Locations:");
2080 for (Map.Entry<String, Location> i
2081 : mLastKnownLocation.entrySet()) {
2082 pw.println(" " + i.getKey() + ":");
2083 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2084 }
2085 if (mProximityAlerts.size() > 0) {
2086 pw.println(" Proximity Alerts:");
2087 for (Map.Entry<PendingIntent, ProximityAlert> i
2088 : mProximityAlerts.entrySet()) {
2089 pw.println(" " + i.getKey() + ":");
2090 i.getValue().dump(pw, " ");
2091 }
2092 }
2093 if (mProximitiesEntered.size() > 0) {
2094 pw.println(" Proximities Entered:");
2095 for (ProximityAlert i : mProximitiesEntered) {
2096 pw.println(" " + i + ":");
2097 i.dump(pw, " ");
2098 }
2099 }
Mike Lockwood48f17512009-04-23 09:12:08 -07002100 pw.println(" mProximityReceiver=" + mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 pw.println(" mProximityListener=" + mProximityListener);
2102 if (mEnabledProviders.size() > 0) {
2103 pw.println(" Enabled Providers:");
2104 for (String i : mEnabledProviders) {
2105 pw.println(" " + i);
2106 }
2107
2108 }
2109 if (mDisabledProviders.size() > 0) {
2110 pw.println(" Disabled Providers:");
2111 for (String i : mDisabledProviders) {
2112 pw.println(" " + i);
2113 }
2114
2115 }
2116 if (mMockProviders.size() > 0) {
2117 pw.println(" Mock Providers:");
2118 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002119 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 }
2121 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002122 }
2123 }
2124}