blob: 2def877560db0d55117c09c1bf965f521a02104f [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;
56import android.location.LocationProviderImpl;
57import android.net.ConnectivityManager;
58import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.os.Binder;
60import android.os.Bundle;
61import android.os.Handler;
62import android.os.IBinder;
63import 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 Lockwoode932f7f2009-04-06 10:51:26 -070075import com.android.internal.location.LocationProviderProxy;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070076import com.android.internal.location.MockProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import com.android.internal.location.TrackProvider;
78import 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 Lockwoode932f7f2009-04-06 10:51:26 -070086public class LocationManagerService extends ILocationManager.Stub {
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
542 // Load fake providers if real providers are not available
543 File f = new File(LocationManager.PROVIDER_DIR);
544 if (f.isDirectory()) {
545 File[] subdirs = f.listFiles();
546 for (int i = 0; i < subdirs.length; i++) {
547 if (!subdirs[i].isDirectory()) {
548 continue;
549 }
550
551 String name = subdirs[i].getName();
552
The Android Open Source Project10592532009-03-18 17:39:46 -0700553 if (LOCAL_LOGV) {
554 Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath());
555 Log.v(TAG, "name = " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 }
557
558 // Don't create a fake provider if a real provider exists
559 if (LocationProviderImpl.getProvider(name) == null) {
560 LocationProviderImpl provider = null;
561 try {
562 File classFile = new File(subdirs[i], "class");
563 // Look for a 'class' file
564 provider = LocationProviderImpl.loadFromClass(classFile);
565
566 // Look for an 'kml', 'nmea', or 'track' file
567 if (provider == null) {
568 // Load properties from 'properties' file, if present
569 File propertiesFile = new File(subdirs[i], "properties");
570
571 if (propertiesFile.exists()) {
Mike Lockwood4e50b782009-04-03 08:24:43 -0700572 provider = new TrackProvider(name, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 ((TrackProvider)provider).readProperties(propertiesFile);
574
575 File kmlFile = new File(subdirs[i], "kml");
576 if (kmlFile.exists()) {
577 ((TrackProvider) provider).readKml(kmlFile);
578 } else {
579 File nmeaFile = new File(subdirs[i], "nmea");
580 if (nmeaFile.exists()) {
581 ((TrackProvider) provider).readNmea(name, nmeaFile);
582 } else {
583 File trackFile = new File(subdirs[i], "track");
584 if (trackFile.exists()) {
585 ((TrackProvider) provider).readTrack(trackFile);
586 }
587 }
588 }
589 }
590 }
591 if (provider != null) {
592 LocationProviderImpl.addProvider(provider);
593 }
594 // Grab the initial location of a TrackProvider and
595 // store it as the last known location for that provider
596 if (provider instanceof TrackProvider) {
597 TrackProvider tp = (TrackProvider) provider;
598 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation());
599 }
600 } catch (Exception e) {
601 Log.e(TAG, "Exception loading provder " + name, e);
602 }
603 }
604 }
605 }
606
607 updateProvidersLocked();
608 }
609
610 /**
611 * @param context the context that the LocationManagerService runs in
612 */
613 public LocationManagerService(Context context) {
614 super();
615 mContext = context;
616 mLocationHandler = new LocationWorkerHandler();
617
The Android Open Source Project10592532009-03-18 17:39:46 -0700618 if (LOCAL_LOGV) {
619 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 }
621
622 // Alarm manager, needs to be done before calling loadProviders() below
623 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
624
625 // Create a wake lock, needs to be done before calling loadProviders() below
626 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
627 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 // Load providers
630 loadProviders();
631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 // Register for Network (Wifi or Mobile) updates
633 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
634 IntentFilter networkIntentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
636 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
637 context.registerReceiver(networkReceiver, networkIntentFilter);
638
639 // Register for power updates
640 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
641 IntentFilter intentFilter = new IntentFilter();
642 intentFilter.addAction(ALARM_INTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
644 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
645 context.registerReceiver(powerStateReceiver, intentFilter);
646
Mike Lockwood9637d472009-04-02 21:41:57 -0700647 // listen for settings changes
648 ContentResolver resolver = mContext.getContentResolver();
649 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
650 "(" + Settings.System.NAME + "=?)",
651 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
652 null);
653 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
654 SettingsObserver settingsObserver = new SettingsObserver();
655 mSettings.addObserver(settingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
657
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700658 public void setNetworkLocationProvider(ILocationProvider provider) {
659 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
660 throw new SecurityException(
661 "Installing location providers outside of the system is not supported");
662 }
663
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400664 synchronized (mLock) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700665 mNetworkLocationProvider =
666 new LocationProviderProxy(LocationManager.NETWORK_PROVIDER, this, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667 LocationProviderImpl.addProvider(mNetworkLocationProvider);
668 updateProvidersLocked();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800669
670 // notify NetworkLocationProvider of any events it might have missed
Mike Lockwoodf113fbe2009-04-06 05:17:28 -0700671 mNetworkLocationProvider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 }
673 }
674
675 public void setLocationCollector(ILocationCollector collector) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700676 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
677 throw new SecurityException(
678 "Installing location collectors outside of the system is not supported");
679 }
680
Mike Lockwood98cb6672009-04-17 18:03:44 -0400681 mCollector = collector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800682 }
683
Mike Lockwooda55c3212009-04-15 11:10:11 -0400684 public void setGeocodeProvider(IGeocodeProvider provider) {
685 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
686 throw new SecurityException(
687 "Installing location providers outside of the system is not supported");
688 }
689
690 mGeocodeProvider = provider;
691 }
692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 private boolean isAllowedBySettingsLocked(String provider) {
694 if (mEnabledProviders.contains(provider)) {
695 return true;
696 }
697 if (mDisabledProviders.contains(provider)) {
698 return false;
699 }
700 // Use system settings
701 ContentResolver resolver = mContext.getContentResolver();
702 String allowedProviders = Settings.Secure.getString(resolver,
703 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
704
705 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
706 }
707
708 private void checkPermissionsSafe(String provider) {
709 if (LocationManager.GPS_PROVIDER.equals(provider)
710 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
711 != PackageManager.PERMISSION_GRANTED)) {
712 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
713 }
714 if (LocationManager.NETWORK_PROVIDER.equals(provider)
715 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
716 != PackageManager.PERMISSION_GRANTED)
717 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
718 != PackageManager.PERMISSION_GRANTED)) {
719 throw new SecurityException(
720 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
721 }
722 }
723
724 private boolean isAllowedProviderSafe(String provider) {
725 if (LocationManager.GPS_PROVIDER.equals(provider)
726 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
727 != PackageManager.PERMISSION_GRANTED)) {
728 return false;
729 }
730 if (LocationManager.NETWORK_PROVIDER.equals(provider)
731 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
732 != PackageManager.PERMISSION_GRANTED)
733 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
734 != PackageManager.PERMISSION_GRANTED)) {
735 return false;
736 }
737
738 return true;
739 }
740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 public List<String> getAllProviders() {
742 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400743 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 return _getAllProvidersLocked();
745 }
746 } catch (SecurityException se) {
747 throw se;
748 } catch (Exception e) {
749 Log.e(TAG, "getAllProviders got exception:", e);
750 return null;
751 }
752 }
753
754 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700755 if (LOCAL_LOGV) {
756 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 }
758 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
759 ArrayList<String> out = new ArrayList<String>(providers.size());
760
761 for (LocationProviderImpl p : providers) {
762 out.add(p.getName());
763 }
764 return out;
765 }
766
767 public List<String> getProviders(boolean enabledOnly) {
768 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400769 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 return _getProvidersLocked(enabledOnly);
771 }
772 } catch (SecurityException se) {
773 throw se;
774 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700775 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 return null;
777 }
778 }
779
780 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700781 if (LOCAL_LOGV) {
782 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800783 }
784 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
785 ArrayList<String> out = new ArrayList<String>();
786
787 for (LocationProviderImpl p : providers) {
788 String name = p.getName();
789 if (isAllowedProviderSafe(name)) {
790 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
791 continue;
792 }
793 out.add(name);
794 }
795 }
796 return out;
797 }
798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 private void updateProvidersLocked() {
800 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
801 boolean isEnabled = p.isEnabled();
802 String name = p.getName();
803 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 if (isEnabled && !shouldBeEnabled) {
806 updateProviderListenersLocked(name, false);
807 } else if (!isEnabled && shouldBeEnabled) {
808 updateProviderListenersLocked(name, true);
809 }
810
811 }
812 }
813
814 private void updateProviderListenersLocked(String provider, boolean enabled) {
815 int listeners = 0;
816
817 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
818 if (p == null) {
819 return;
820 }
821
822 ArrayList<Receiver> deadReceivers = null;
823
824 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
825 if (records != null) {
826 final int N = records.size();
827 for (int i=0; i<N; i++) {
828 UpdateRecord record = records.get(i);
829 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700830 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
831 if (deadReceivers == null) {
832 deadReceivers = new ArrayList<Receiver>();
833 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 }
836 listeners++;
837 }
838 }
839
840 if (deadReceivers != null) {
841 for (int i=deadReceivers.size()-1; i>=0; i--) {
842 removeUpdatesLocked(deadReceivers.get(i));
843 }
844 }
845
846 if (enabled) {
847 p.enable();
848 if (listeners > 0) {
849 p.setMinTime(getMinTimeLocked(provider));
850 p.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -0700851 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 }
853 } else {
854 p.enableLocationTracking(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 p.disable();
Mike Lockwood61fc2862009-04-21 20:02:52 -0700856 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800858 }
859
860 private long getMinTimeLocked(String provider) {
861 long minTime = Long.MAX_VALUE;
862 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
863 if (records != null) {
864 for (int i=records.size()-1; i>=0; i--) {
865 minTime = Math.min(minTime, records.get(i).mMinTime);
866 }
867 }
868 return minTime;
869 }
870
871 private class UpdateRecord {
872 final String mProvider;
873 final Receiver mReceiver;
874 final long mMinTime;
875 final float mMinDistance;
876 final int mUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400877 Location mLastFixBroadcast;
878 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879
880 /**
881 * Note: must be constructed with lock held.
882 */
883 UpdateRecord(String provider, long minTime, float minDistance,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400884 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 mProvider = provider;
886 mReceiver = receiver;
887 mMinTime = minTime;
888 mMinDistance = minDistance;
889 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800890
891 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
892 if (records == null) {
893 records = new ArrayList<UpdateRecord>();
894 mRecordsByProvider.put(provider, records);
895 }
896 if (!records.contains(this)) {
897 records.add(this);
898 }
899 }
900
901 /**
902 * Method to be called when a record will no longer be used. Calling this multiple times
903 * must have the same effect as calling it once.
904 */
905 void disposeLocked() {
906 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
907 records.remove(this);
908 }
909
910 @Override
911 public String toString() {
912 return "UpdateRecord{"
913 + Integer.toHexString(System.identityHashCode(this))
914 + " " + mProvider + " " + mReceiver + "}";
915 }
916
917 void dump(PrintWriter pw, String prefix) {
918 pw.println(prefix + this);
919 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
920 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400921 pw.println(prefix + "mUid=" + mUid);
922 pw.println(prefix + "mLastFixBroadcast:");
923 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
924 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800925 }
926
927 /**
928 * Calls dispose().
929 */
930 @Override protected void finalize() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400931 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932 disposeLocked();
933 }
934 }
935 }
936
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400937 private Receiver getReceiver(ILocationListener listener) {
938 IBinder binder = listener.asBinder();
939 Receiver receiver = mReceivers.get(binder);
940 if (receiver == null) {
941 receiver = new Receiver(listener);
942 mReceivers.put(binder, receiver);
943
944 try {
945 if (receiver.isListener()) {
946 receiver.getListener().asBinder().linkToDeath(receiver, 0);
947 }
948 } catch (RemoteException e) {
949 Log.e(TAG, "linkToDeath failed:", e);
950 return null;
951 }
952 }
953 return receiver;
954 }
955
956 private Receiver getReceiver(PendingIntent intent) {
957 Receiver receiver = mReceivers.get(intent);
958 if (receiver == null) {
959 receiver = new Receiver(intent);
960 mReceivers.put(intent, receiver);
961 }
962 return receiver;
963 }
964
965 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
966 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
967 if (records != null) {
968 for (int i = records.size() - 1; i >= 0; i--) {
969 UpdateRecord record = records.get(i);
970 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
971 return true;
972 }
973 }
974 }
975 if (LocationManager.GPS_PROVIDER.equals(provider) ||
976 LocationManager.NETWORK_PROVIDER.equals(provider)) {
977 for (ProximityAlert alert : mProximityAlerts.values()) {
978 if (alert.mUid == uid) {
979 return true;
980 }
981 }
982 }
983 return false;
984 }
985
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 public void requestLocationUpdates(String provider,
987 long minTime, float minDistance, ILocationListener listener) {
988
989 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400990 synchronized (mLock) {
991 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993 } catch (SecurityException se) {
994 throw se;
995 } catch (Exception e) {
996 Log.e(TAG, "requestUpdates got exception:", e);
997 }
998 }
999
1000 public void requestLocationUpdatesPI(String provider,
1001 long minTime, float minDistance, PendingIntent intent) {
1002 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001003 synchronized (mLock) {
1004 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 }
1006 } catch (SecurityException se) {
1007 throw se;
1008 } catch (Exception e) {
1009 Log.e(TAG, "requestUpdates got exception:", e);
1010 }
1011 }
1012
1013 private void requestLocationUpdatesLocked(String provider,
1014 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001015 if (LOCAL_LOGV) {
1016 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 }
1018
1019 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1020 if (impl == null) {
1021 throw new IllegalArgumentException("provider=" + provider);
1022 }
1023
1024 checkPermissionsSafe(provider);
1025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 // so wakelock calls will succeed
1027 final int callingUid = Binder.getCallingUid();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001028 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 long identity = Binder.clearCallingIdentity();
1030 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001031 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
1032 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001033 if (oldRecord != null) {
1034 oldRecord.disposeLocked();
1035 }
1036
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001037 if (newUid) {
1038 impl.addListener(callingUid);
1039 }
1040
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1042 if (isProviderEnabled) {
1043 long minTimeForProvider = getMinTimeLocked(provider);
1044 impl.setMinTime(minTimeForProvider);
1045 impl.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -07001046 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001047 } else {
Mike Lockwood48f17512009-04-23 09:12:08 -07001048 // Notify the listener that updates are currently disabled
1049 receiver.callProviderEnabledLocked(provider, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001050 }
1051 } finally {
1052 Binder.restoreCallingIdentity(identity);
1053 }
1054 }
1055
1056 public void removeUpdates(ILocationListener listener) {
1057 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001058 synchronized (mLock) {
1059 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 }
1061 } catch (SecurityException se) {
1062 throw se;
1063 } catch (Exception e) {
1064 Log.e(TAG, "removeUpdates got exception:", e);
1065 }
1066 }
1067
1068 public void removeUpdatesPI(PendingIntent intent) {
1069 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001070 synchronized (mLock) {
1071 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 }
1073 } catch (SecurityException se) {
1074 throw se;
1075 } catch (Exception e) {
1076 Log.e(TAG, "removeUpdates got exception:", e);
1077 }
1078 }
1079
1080 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001081 if (LOCAL_LOGV) {
1082 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 }
1084
1085 // so wakelock calls will succeed
1086 final int callingUid = Binder.getCallingUid();
1087 long identity = Binder.clearCallingIdentity();
1088 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1090 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 }
1092
1093 // Record which providers were associated with this listener
1094 HashSet<String> providers = new HashSet<String>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001095 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 if (oldRecords != null) {
1097 // Call dispose() on the obsolete update records.
1098 for (UpdateRecord record : oldRecords.values()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001099 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1100 LocationProviderImpl impl =
1101 LocationProviderImpl.getProvider(record.mProvider);
1102 if (impl != null) {
1103 impl.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001104 }
1105 }
1106 record.disposeLocked();
1107 }
1108 // Accumulate providers
1109 providers.addAll(oldRecords.keySet());
1110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001111
1112 // See if the providers associated with this listener have any
1113 // other listeners; if one does, inform it of the new smallest minTime
1114 // value; if one does not, disable location tracking for it
1115 for (String provider : providers) {
1116 // If provider is already disabled, don't need to do anything
1117 if (!isAllowedBySettingsLocked(provider)) {
1118 continue;
1119 }
1120
1121 boolean hasOtherListener = false;
1122 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1123 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1124 hasOtherListener = true;
1125 }
1126
1127 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1128 if (p != null) {
1129 if (hasOtherListener) {
1130 p.setMinTime(getMinTimeLocked(provider));
1131 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 p.enableLocationTracking(false);
1133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 }
1135 }
1136
Mike Lockwood61fc2862009-04-21 20:02:52 -07001137 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001138 } finally {
1139 Binder.restoreCallingIdentity(identity);
1140 }
1141 }
1142
1143 public boolean addGpsStatusListener(IGpsStatusListener listener) {
1144 if (mGpsLocationProvider == null) {
1145 return false;
1146 }
1147 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
1148 PackageManager.PERMISSION_GRANTED) {
1149 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1150 }
1151
1152 try {
1153 mGpsLocationProvider.addGpsStatusListener(listener);
1154 } catch (RemoteException e) {
1155 Log.w(TAG, "RemoteException in addGpsStatusListener");
1156 return false;
1157 }
1158 return true;
1159 }
1160
1161 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001162 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001163 mGpsLocationProvider.removeGpsStatusListener(listener);
1164 }
1165 }
1166
1167 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1168 // first check for permission to the provider
1169 checkPermissionsSafe(provider);
1170 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1171 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1172 != PackageManager.PERMISSION_GRANTED)) {
1173 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1174 }
1175
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001176 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1178 if (provider == null) {
1179 return false;
1180 }
1181
1182 return impl.sendExtraCommand(command, extras);
1183 }
1184 }
1185
1186 class ProximityAlert {
1187 final int mUid;
1188 final double mLatitude;
1189 final double mLongitude;
1190 final float mRadius;
1191 final long mExpiration;
1192 final PendingIntent mIntent;
1193 final Location mLocation;
1194
1195 public ProximityAlert(int uid, double latitude, double longitude,
1196 float radius, long expiration, PendingIntent intent) {
1197 mUid = uid;
1198 mLatitude = latitude;
1199 mLongitude = longitude;
1200 mRadius = radius;
1201 mExpiration = expiration;
1202 mIntent = intent;
1203
1204 mLocation = new Location("");
1205 mLocation.setLatitude(latitude);
1206 mLocation.setLongitude(longitude);
1207 }
1208
1209 long getExpiration() {
1210 return mExpiration;
1211 }
1212
1213 PendingIntent getIntent() {
1214 return mIntent;
1215 }
1216
1217 boolean isInProximity(double latitude, double longitude) {
1218 Location loc = new Location("");
1219 loc.setLatitude(latitude);
1220 loc.setLongitude(longitude);
1221
1222 double radius = loc.distanceTo(mLocation);
1223 return radius <= mRadius;
1224 }
1225
1226 @Override
1227 public String toString() {
1228 return "ProximityAlert{"
1229 + Integer.toHexString(System.identityHashCode(this))
1230 + " uid " + mUid + mIntent + "}";
1231 }
1232
1233 void dump(PrintWriter pw, String prefix) {
1234 pw.println(prefix + this);
1235 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1236 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1237 pw.println(prefix + "mIntent=" + mIntent);
1238 pw.println(prefix + "mLocation:");
1239 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1240 }
1241 }
1242
1243 // Listener for receiving locations to trigger proximity alerts
Mike Lockwood48f17512009-04-23 09:12:08 -07001244 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001245
1246 boolean isGpsAvailable = false;
1247
1248 // Note: this is called with the lock held.
1249 public void onLocationChanged(Location loc) {
1250
1251 // If Gps is available, then ignore updates from NetworkLocationProvider
1252 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1253 isGpsAvailable = true;
1254 }
1255 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1256 return;
1257 }
1258
1259 // Process proximity alerts
1260 long now = System.currentTimeMillis();
1261 double latitude = loc.getLatitude();
1262 double longitude = loc.getLongitude();
1263 ArrayList<PendingIntent> intentsToRemove = null;
1264
1265 for (ProximityAlert alert : mProximityAlerts.values()) {
1266 PendingIntent intent = alert.getIntent();
1267 long expiration = alert.getExpiration();
1268
1269 if ((expiration == -1) || (now <= expiration)) {
1270 boolean entered = mProximitiesEntered.contains(alert);
1271 boolean inProximity =
1272 alert.isInProximity(latitude, longitude);
1273 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001274 if (LOCAL_LOGV) {
1275 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001276 }
1277 mProximitiesEntered.add(alert);
1278 Intent enteredIntent = new Intent();
1279 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1280 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001281 synchronized (mLock) {
1282 // synchronize to ensure incrementPendingBroadcastsLocked()
1283 // is called before decrementPendingBroadcasts()
1284 intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
1285 // call this after broadcasting so we do not increment
1286 // if we throw an exeption.
1287 incrementPendingBroadcastsLocked();
1288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001290 if (LOCAL_LOGV) {
1291 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 }
1293 if (intentsToRemove == null) {
1294 intentsToRemove = new ArrayList<PendingIntent>();
1295 }
1296 intentsToRemove.add(intent);
1297 }
1298 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001299 if (LOCAL_LOGV) {
1300 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302 mProximitiesEntered.remove(alert);
1303 Intent exitedIntent = new Intent();
1304 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1305 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001306 synchronized (mLock) {
1307 // synchronize to ensure incrementPendingBroadcastsLocked()
1308 // is called before decrementPendingBroadcasts()
1309 intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
1310 // call this after broadcasting so we do not increment
1311 // if we throw an exeption.
1312 incrementPendingBroadcastsLocked();
1313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001315 if (LOCAL_LOGV) {
1316 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 }
1318 if (intentsToRemove == null) {
1319 intentsToRemove = new ArrayList<PendingIntent>();
1320 }
1321 intentsToRemove.add(intent);
1322 }
1323 }
1324 } else {
1325 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001326 if (LOCAL_LOGV) {
1327 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 }
1329 if (intentsToRemove == null) {
1330 intentsToRemove = new ArrayList<PendingIntent>();
1331 }
1332 intentsToRemove.add(alert.getIntent());
1333 }
1334 }
1335
1336 // Remove expired alerts
1337 if (intentsToRemove != null) {
1338 for (PendingIntent i : intentsToRemove) {
1339 mProximityAlerts.remove(i);
1340 ProximityAlert alert = mProximityAlerts.get(i);
1341 mProximitiesEntered.remove(alert);
1342 }
1343 }
1344
1345 }
1346
1347 // Note: this is called with the lock held.
1348 public void onProviderDisabled(String provider) {
1349 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1350 isGpsAvailable = false;
1351 }
1352 }
1353
1354 // Note: this is called with the lock held.
1355 public void onProviderEnabled(String provider) {
1356 // ignore
1357 }
1358
1359 // Note: this is called with the lock held.
1360 public void onStatusChanged(String provider, int status, Bundle extras) {
1361 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1362 (status != LocationProvider.AVAILABLE)) {
1363 isGpsAvailable = false;
1364 }
1365 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001366
1367 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1368 int resultCode, String resultData, Bundle resultExtras) {
1369 decrementPendingBroadcasts();
1370 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001371 }
1372
1373 public void addProximityAlert(double latitude, double longitude,
1374 float radius, long expiration, PendingIntent intent) {
1375 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001376 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1378 }
1379 } catch (SecurityException se) {
1380 throw se;
1381 } catch (Exception e) {
1382 Log.e(TAG, "addProximityAlert got exception:", e);
1383 }
1384 }
1385
1386 private void addProximityAlertLocked(double latitude, double longitude,
1387 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001388 if (LOCAL_LOGV) {
1389 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 ", longitude = " + longitude +
1391 ", expiration = " + expiration +
1392 ", intent = " + intent);
1393 }
1394
1395 // Require ability to access all providers for now
1396 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1397 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1398 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1399 }
1400
1401 if (expiration != -1) {
1402 expiration += System.currentTimeMillis();
1403 }
1404 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1405 latitude, longitude, radius, expiration, intent);
1406 mProximityAlerts.put(intent, alert);
1407
Mike Lockwood48f17512009-04-23 09:12:08 -07001408 if (mProximityReceiver == null) {
1409 mProximityListener = new ProximityListener();
1410 mProximityReceiver = new Receiver(mProximityListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001411
1412 LocationProvider provider = LocationProviderImpl.getProvider(
1413 LocationManager.GPS_PROVIDER);
1414 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001415 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 }
1417
1418 provider =
1419 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
1420 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001421 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 }
1424 }
1425
1426 public void removeProximityAlert(PendingIntent intent) {
1427 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001428 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001429 removeProximityAlertLocked(intent);
1430 }
1431 } catch (SecurityException se) {
1432 throw se;
1433 } catch (Exception e) {
1434 Log.e(TAG, "removeProximityAlert got exception:", e);
1435 }
1436 }
1437
1438 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001439 if (LOCAL_LOGV) {
1440 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001441 }
1442
1443 mProximityAlerts.remove(intent);
1444 if (mProximityAlerts.size() == 0) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001445 removeUpdatesLocked(mProximityReceiver);
1446 mProximityReceiver = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001447 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 }
1449 }
1450
1451 /**
1452 * @return null if the provider does not exits
1453 * @throw SecurityException if the provider is not allowed to be
1454 * accessed by the caller
1455 */
1456 public Bundle getProviderInfo(String provider) {
1457 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001458 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001459 return _getProviderInfoLocked(provider);
1460 }
1461 } catch (SecurityException se) {
1462 throw se;
1463 } catch (Exception e) {
1464 Log.e(TAG, "_getProviderInfo got exception:", e);
1465 return null;
1466 }
1467 }
1468
1469 private Bundle _getProviderInfoLocked(String provider) {
1470 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1471 if (p == null) {
1472 return null;
1473 }
1474
1475 checkPermissionsSafe(provider);
1476
1477 Bundle b = new Bundle();
1478 b.putBoolean("network", p.requiresNetwork());
1479 b.putBoolean("satellite", p.requiresSatellite());
1480 b.putBoolean("cell", p.requiresCell());
1481 b.putBoolean("cost", p.hasMonetaryCost());
1482 b.putBoolean("altitude", p.supportsAltitude());
1483 b.putBoolean("speed", p.supportsSpeed());
1484 b.putBoolean("bearing", p.supportsBearing());
1485 b.putInt("power", p.getPowerRequirement());
1486 b.putInt("accuracy", p.getAccuracy());
1487
1488 return b;
1489 }
1490
1491 public boolean isProviderEnabled(String provider) {
1492 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001493 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 return _isProviderEnabledLocked(provider);
1495 }
1496 } catch (SecurityException se) {
1497 throw se;
1498 } catch (Exception e) {
1499 Log.e(TAG, "isProviderEnabled got exception:", e);
1500 return false;
1501 }
1502 }
1503
Mike Lockwood4e50b782009-04-03 08:24:43 -07001504 public void setLocation(Location location) {
1505 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1506 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1507 mLocationHandler.sendMessageAtFrontOfQueue(m);
1508 }
1509
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 private boolean _isProviderEnabledLocked(String provider) {
1511 checkPermissionsSafe(provider);
1512
1513 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1514 if (p == null) {
1515 throw new IllegalArgumentException("provider=" + provider);
1516 }
1517 return isAllowedBySettingsLocked(provider);
1518 }
1519
1520 public Location getLastKnownLocation(String provider) {
1521 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001522 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001523 return _getLastKnownLocationLocked(provider);
1524 }
1525 } catch (SecurityException se) {
1526 throw se;
1527 } catch (Exception e) {
1528 Log.e(TAG, "getLastKnownLocation got exception:", e);
1529 return null;
1530 }
1531 }
1532
1533 private Location _getLastKnownLocationLocked(String provider) {
1534 checkPermissionsSafe(provider);
1535
1536 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1537 if (p == null) {
1538 throw new IllegalArgumentException("provider=" + provider);
1539 }
1540
1541 if (!isAllowedBySettingsLocked(provider)) {
1542 return null;
1543 }
1544
1545 Location location = mLastKnownLocation.get(provider);
1546 if (location == null) {
1547 // Get the persistent last known location for the provider
1548 location = readLastKnownLocationLocked(provider);
1549 if (location != null) {
1550 mLastKnownLocation.put(provider, location);
1551 }
1552 }
1553
1554 return location;
1555 }
1556
1557 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1558 // Always broadcast the first update
1559 if (lastLoc == null) {
1560 return true;
1561 }
1562
1563 // Don't broadcast same location again regardless of condition
1564 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1565 if (loc.getTime() == lastLoc.getTime()) {
1566 return false;
1567 }
1568
1569 // Check whether sufficient distance has been traveled
1570 double minDistance = record.mMinDistance;
1571 if (minDistance > 0.0) {
1572 if (loc.distanceTo(lastLoc) <= minDistance) {
1573 return false;
1574 }
1575 }
1576
1577 return true;
1578 }
1579
Mike Lockwood4e50b782009-04-03 08:24:43 -07001580 private void handleLocationChangedLocked(Location location) {
1581 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1583 if (records == null || records.size() == 0) {
1584 return;
1585 }
1586
1587 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1588 if (p == null) {
1589 return;
1590 }
1591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001593 Location lastLocation = mLastKnownLocation.get(provider);
1594 if (lastLocation == null) {
1595 mLastKnownLocation.put(provider, new Location(location));
1596 } else {
1597 lastLocation.set(location);
1598 }
1599 writeLastKnownLocationLocked(provider, location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001600
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001601 if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001602 mWakeLockNetworkReceived = true;
1603 } else if (p instanceof GpsLocationProvider) {
1604 // Gps location received signal is in NetworkStateBroadcastReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606
1607 // Fetch latest status update time
1608 long newStatusUpdateTime = p.getStatusUpdateTime();
1609
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001610 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 Bundle extras = new Bundle();
1612 int status = p.getStatus(extras);
1613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 ArrayList<Receiver> deadReceivers = null;
1615
1616 // Broadcast location or status to all listeners
1617 final int N = records.size();
1618 for (int i=0; i<N; i++) {
1619 UpdateRecord r = records.get(i);
1620 Receiver receiver = r.mReceiver;
1621
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001622 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001623 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1624 if (lastLoc == null) {
1625 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001626 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001627 } else {
1628 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001630 if (!receiver.callLocationChangedLocked(location)) {
1631 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1632 if (deadReceivers == null) {
1633 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001635 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 }
1637 }
1638
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001639 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1641 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1642
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001643 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1645 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1646 if (deadReceivers == null) {
1647 deadReceivers = new ArrayList<Receiver>();
1648 }
1649 if (!deadReceivers.contains(receiver)) {
1650 deadReceivers.add(receiver);
1651 }
1652 }
1653 }
1654 }
1655
1656 if (deadReceivers != null) {
1657 for (int i=deadReceivers.size()-1; i>=0; i--) {
1658 removeUpdatesLocked(deadReceivers.get(i));
1659 }
1660 }
1661 }
1662
1663 private class LocationWorkerHandler extends Handler {
1664
1665 @Override
1666 public void handleMessage(Message msg) {
1667 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001668 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1669 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001671 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001672 Location location = (Location) msg.obj;
Mike Lockwood98cb6672009-04-17 18:03:44 -04001673
1674 if (mCollector != null &&
1675 LocationManager.GPS_PROVIDER.equals(location.getProvider())) {
1676 try {
1677 mCollector.updateLocation(location);
1678 } catch (RemoteException e) {
1679 Log.w(TAG, "mCollector.updateLocation failed");
1680 }
1681 }
1682
Mike Lockwood4e50b782009-04-03 08:24:43 -07001683 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 if (!isAllowedBySettingsLocked(provider)) {
1685 return;
1686 }
1687
Mike Lockwooda0e3cd32009-04-21 21:27:33 -07001688 handleLocationChangedLocked(location);
Mike Lockwood61fc2862009-04-21 20:02:52 -07001689 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001691 }
1692 } catch (Exception e) {
1693 // Log, don't crash!
1694 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1695 }
1696 }
1697 }
1698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1700 @Override public void onReceive(Context context, Intent intent) {
1701 String action = intent.getAction();
1702
1703 if (action.equals(ALARM_INTENT)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001704 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001705 log("PowerStateBroadcastReceiver: Alarm received");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001706 // Have to do this immediately, rather than posting a
1707 // message, so we execute our code while the system
1708 // is holding a wake lock until the alarm broadcast
1709 // is finished.
1710 acquireWakeLockLocked();
1711 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001712 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1713 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001714 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001715 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1716 if (uid >= 0) {
1717 ArrayList<Receiver> removedRecs = null;
1718 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1719 for (int j=i.size()-1; j>=0; j--) {
1720 UpdateRecord ur = i.get(j);
1721 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1722 if (removedRecs == null) {
1723 removedRecs = new ArrayList<Receiver>();
1724 }
1725 if (!removedRecs.contains(ur.mReceiver)) {
1726 removedRecs.add(ur.mReceiver);
1727 }
1728 }
1729 }
1730 }
1731 ArrayList<ProximityAlert> removedAlerts = null;
1732 for (ProximityAlert i : mProximityAlerts.values()) {
1733 if (i.mUid == uid) {
1734 if (removedAlerts == null) {
1735 removedAlerts = new ArrayList<ProximityAlert>();
1736 }
1737 if (!removedAlerts.contains(i)) {
1738 removedAlerts.add(i);
1739 }
1740 }
1741 }
1742 if (removedRecs != null) {
1743 for (int i=removedRecs.size()-1; i>=0; i--) {
1744 removeUpdatesLocked(removedRecs.get(i));
1745 }
1746 }
1747 if (removedAlerts != null) {
1748 for (int i=removedAlerts.size()-1; i>=0; i--) {
1749 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1750 }
1751 }
1752 }
1753 }
1754 }
1755 }
1756 }
1757
1758 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1759 @Override public void onReceive(Context context, Intent intent) {
1760 String action = intent.getAction();
1761
Mike Lockwoodf113fbe2009-04-06 05:17:28 -07001762 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 boolean noConnectivity =
1764 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1765 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001766 mNetworkState = LocationProvider.AVAILABLE;
1767 } else {
1768 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001769 }
1770
1771 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001772 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1774 for (LocationProviderImpl provider : providers) {
1775 if (provider.requiresNetwork()) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001776 provider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001777 }
1778 }
1779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001780 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
1781
1782 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
1783 false);
1784
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001785 synchronized (mLock) {
Mike Lockwood98cb6672009-04-17 18:03:44 -04001786 if (!enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001787 // When GPS is disabled, we are OK to release wake-lock
1788 mWakeLockGpsReceived = true;
1789 }
1790 }
1791 }
1792
1793 }
1794 }
1795
1796 // Wake locks
1797
Mike Lockwood61fc2862009-04-21 20:02:52 -07001798 private void updateWakelockStatusLocked() {
1799 log("updateWakelockStatus()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001801 long callerId = Binder.clearCallingIdentity();
1802
Mike Lockwood48f17512009-04-23 09:12:08 -07001803 boolean needsLock = (mPendingBroadcasts > 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 long minTime = Integer.MAX_VALUE;
1805
1806 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
1807 needsLock = true;
1808 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
1809 }
1810
1811 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
1812 needsLock = true;
1813 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 }
1815
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001816 PendingIntent sender =
1817 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
1818
1819 // Cancel existing alarm
1820 log("Cancelling existing alarm");
1821 mAlarmManager.cancel(sender);
1822
Mike Lockwood61fc2862009-04-21 20:02:52 -07001823 if (needsLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 long now = SystemClock.elapsedRealtime();
1825 mAlarmManager.set(
1826 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
1827 mAlarmInterval = minTime;
1828 log("Creating a new wakelock alarm with minTime = " + minTime);
1829 } else {
1830 log("No need for alarm");
1831 mAlarmInterval = -1;
1832
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 releaseWakeLockLocked();
1834 }
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001835 Binder.restoreCallingIdentity(callerId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001836 }
1837
1838 private void acquireWakeLockLocked() {
1839 try {
1840 acquireWakeLockXLocked();
1841 } catch (Exception e) {
1842 // This is to catch a runtime exception thrown when we try to release an
1843 // already released lock.
1844 Log.e(TAG, "exception in acquireWakeLock()", e);
1845 }
1846 }
1847
1848 private void acquireWakeLockXLocked() {
1849 if (mWakeLock.isHeld()) {
1850 log("Must release wakelock before acquiring");
1851 mWakeLockAcquireTime = 0;
1852 mWakeLock.release();
1853 }
1854
1855 boolean networkActive = (mNetworkLocationProvider != null)
1856 && mNetworkLocationProvider.isLocationTracking();
1857 boolean gpsActive = (mGpsLocationProvider != null)
1858 && mGpsLocationProvider.isLocationTracking();
1859
1860 boolean needsLock = networkActive || gpsActive;
1861 if (!needsLock) {
1862 log("No need for Lock!");
1863 return;
1864 }
1865
1866 mWakeLockGpsReceived = !gpsActive;
1867 mWakeLockNetworkReceived = !networkActive;
1868
1869 // Acquire wake lock
1870 mWakeLock.acquire();
1871 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
1872 log("Acquired wakelock");
1873
Mike Lockwood6de31542009-04-21 12:13:35 -07001874 if (mNetworkLocationProvider != null) {
1875 mNetworkLocationProvider.wakeLockAcquired();
1876 }
1877 if (mGpsLocationProvider != null) {
1878 mGpsLocationProvider.wakeLockAcquired();
1879 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 }
1881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001882 private void releaseWakeLockLocked() {
1883 try {
1884 releaseWakeLockXLocked();
1885 } catch (Exception e) {
1886 // This is to catch a runtime exception thrown when we try to release an
1887 // already released lock.
1888 Log.e(TAG, "exception in releaseWakeLock()", e);
1889 }
1890 }
1891
1892 private void releaseWakeLockXLocked() {
Mike Lockwood6de31542009-04-21 12:13:35 -07001893 if (mNetworkLocationProvider != null) {
1894 mNetworkLocationProvider.wakeLockReleased();
1895 }
1896 if (mGpsLocationProvider != null) {
1897 mGpsLocationProvider.wakeLockReleased();
1898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001899
1900 // Release wake lock
1901 mWakeLockAcquireTime = 0;
1902 if (mWakeLock.isHeld()) {
1903 log("Released wakelock");
1904 mWakeLock.release();
1905 } else {
1906 log("Can't release wakelock again!");
1907 }
1908 }
1909
Mike Lockwood48f17512009-04-23 09:12:08 -07001910 private void incrementPendingBroadcastsLocked() {
1911 if (mPendingBroadcasts++ == 0) {
1912 updateWakelockStatusLocked();
1913 }
1914 }
1915
1916 private void decrementPendingBroadcasts() {
1917 synchronized (mLock) {
1918 if (--mPendingBroadcasts == 0) {
1919 updateWakelockStatusLocked();
1920 }
1921 }
1922 }
1923
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001924 // Geocoder
1925
1926 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001927 String language, String country, String variant, String appName, List<Address> addrs) {
1928 if (mGeocodeProvider != null) {
1929 try {
1930 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1931 variant, appName, addrs);
1932 } catch (RemoteException e) {
1933 Log.e(TAG, "getFromLocation failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001934 }
1935 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001936 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001937 }
1938
Mike Lockwooda55c3212009-04-15 11:10:11 -04001939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001941 double lowerLeftLatitude, double lowerLeftLongitude,
1942 double upperRightLatitude, double upperRightLongitude, int maxResults,
1943 String language, String country, String variant, String appName, List<Address> addrs) {
1944
1945 if (mGeocodeProvider != null) {
1946 try {
1947 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1948 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1949 maxResults, language, country, variant, appName, addrs);
1950 } catch (RemoteException e) {
1951 Log.e(TAG, "getFromLocationName failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001952 }
1953 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001954 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 }
1956
1957 // Mock Providers
1958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 private void checkMockPermissionsSafe() {
1960 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1961 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1962 if (!allowMocks) {
1963 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1964 }
1965
1966 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1967 PackageManager.PERMISSION_GRANTED) {
1968 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1969 }
1970 }
1971
1972 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1973 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1974 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1975 checkMockPermissionsSafe();
1976
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001977 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001978 MockProvider provider = new MockProvider(name, this,
1979 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 requiresCell, hasMonetaryCost, supportsAltitude,
1981 supportsSpeed, supportsBearing, powerRequirement, accuracy);
1982 if (LocationProviderImpl.getProvider(name) != null) {
1983 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1984 }
1985 LocationProviderImpl.addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001986 mMockProviders.put(name, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 updateProvidersLocked();
1988 }
1989 }
1990
1991 public void removeTestProvider(String provider) {
1992 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001993 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001994 MockProvider mockProvider = mMockProviders.get(provider);
1995 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1997 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001998 LocationProviderImpl.removeProvider(mockProvider);
1999 mMockProviders.remove(mockProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002000 updateProvidersLocked();
2001 }
2002 }
2003
2004 public void setTestProviderLocation(String provider, Location loc) {
2005 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002006 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002007 MockProvider mockProvider = mMockProviders.get(provider);
2008 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2010 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002011 mockProvider.setLocation(loc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002012 }
2013 }
2014
2015 public void clearTestProviderLocation(String provider) {
2016 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002017 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002018 MockProvider mockProvider = mMockProviders.get(provider);
2019 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002020 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2021 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002022 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 }
2024 }
2025
2026 public void setTestProviderEnabled(String provider, boolean enabled) {
2027 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002028 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002029 MockProvider mockProvider = mMockProviders.get(provider);
2030 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2032 }
2033 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002034 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002035 mEnabledProviders.add(provider);
2036 mDisabledProviders.remove(provider);
2037 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002038 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 mEnabledProviders.remove(provider);
2040 mDisabledProviders.add(provider);
2041 }
2042 updateProvidersLocked();
2043 }
2044 }
2045
2046 public void clearTestProviderEnabled(String provider) {
2047 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002048 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002049 MockProvider mockProvider = mMockProviders.get(provider);
2050 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002051 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2052 }
2053 mEnabledProviders.remove(provider);
2054 mDisabledProviders.remove(provider);
2055 updateProvidersLocked();
2056 }
2057 }
2058
2059 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2060 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002061 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002062 MockProvider mockProvider = mMockProviders.get(provider);
2063 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2065 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002066 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 }
2068 }
2069
2070 public void clearTestProviderStatus(String provider) {
2071 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002072 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002073 MockProvider mockProvider = mMockProviders.get(provider);
2074 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2076 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002077 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 }
2079 }
2080
2081 private void log(String log) {
2082 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2083 Log.d(TAG, log);
2084 }
2085 }
2086
2087 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2088 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2089 != PackageManager.PERMISSION_GRANTED) {
2090 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2091 + Binder.getCallingPid()
2092 + ", uid=" + Binder.getCallingUid());
2093 return;
2094 }
2095
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002096 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 pw.println("Current Location Manager state:");
2098 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2099 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002100 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002101 pw.println(" mCollector=" + mCollector);
2102 pw.println(" mAlarmInterval=" + mAlarmInterval
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002103 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2104 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2105 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002106 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002107 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002109 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002112 for (Receiver i : mReceivers.values()) {
2113 pw.println(" " + i + ":");
2114 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002115 pw.println(" " + j.getKey() + ":");
2116 j.getValue().dump(pw, " ");
2117 }
2118 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 pw.println(" Records by Provider:");
2120 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2121 : mRecordsByProvider.entrySet()) {
2122 pw.println(" " + i.getKey() + ":");
2123 for (UpdateRecord j : i.getValue()) {
2124 pw.println(" " + j + ":");
2125 j.dump(pw, " ");
2126 }
2127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002128 pw.println(" Last Known Locations:");
2129 for (Map.Entry<String, Location> i
2130 : mLastKnownLocation.entrySet()) {
2131 pw.println(" " + i.getKey() + ":");
2132 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2133 }
2134 if (mProximityAlerts.size() > 0) {
2135 pw.println(" Proximity Alerts:");
2136 for (Map.Entry<PendingIntent, ProximityAlert> i
2137 : mProximityAlerts.entrySet()) {
2138 pw.println(" " + i.getKey() + ":");
2139 i.getValue().dump(pw, " ");
2140 }
2141 }
2142 if (mProximitiesEntered.size() > 0) {
2143 pw.println(" Proximities Entered:");
2144 for (ProximityAlert i : mProximitiesEntered) {
2145 pw.println(" " + i + ":");
2146 i.dump(pw, " ");
2147 }
2148 }
Mike Lockwood48f17512009-04-23 09:12:08 -07002149 pw.println(" mProximityReceiver=" + mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002150 pw.println(" mProximityListener=" + mProximityListener);
2151 if (mEnabledProviders.size() > 0) {
2152 pw.println(" Enabled Providers:");
2153 for (String i : mEnabledProviders) {
2154 pw.println(" " + i);
2155 }
2156
2157 }
2158 if (mDisabledProviders.size() > 0) {
2159 pw.println(" Disabled Providers:");
2160 for (String i : mDisabledProviders) {
2161 pw.println(" " + i);
2162 }
2163
2164 }
2165 if (mMockProviders.size() > 0) {
2166 pw.println(" Mock Providers:");
2167 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002168 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169 }
2170 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002171 }
2172 }
2173}