blob: f3187d77b26706a6666c1fa0d76e62dfa8d6c5f8 [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;
47import android.location.IGpsStatusListener;
48import android.location.ILocationListener;
49import android.location.ILocationManager;
50import android.location.Location;
51import android.location.LocationManager;
52import android.location.LocationProvider;
53import android.location.LocationProviderImpl;
54import android.net.ConnectivityManager;
55import android.net.Uri;
56import android.net.wifi.ScanResult;
57import android.net.wifi.WifiManager;
58import android.os.Binder;
59import android.os.Bundle;
60import android.os.Handler;
61import android.os.IBinder;
62import android.os.Message;
63import android.os.PowerManager;
64import android.os.RemoteException;
65import android.os.SystemClock;
66import android.provider.Settings;
67import android.telephony.CellLocation;
68import android.telephony.PhoneStateListener;
69import android.telephony.TelephonyManager;
70import android.util.Config;
71import android.util.Log;
72import android.util.PrintWriterPrinter;
73import android.util.SparseIntArray;
74
75import com.android.internal.app.IBatteryStats;
76import com.android.internal.location.CellState;
77import com.android.internal.location.GpsLocationProvider;
78import com.android.internal.location.ILocationCollector;
79import com.android.internal.location.INetworkLocationManager;
80import com.android.internal.location.INetworkLocationProvider;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070081import com.android.internal.location.MockProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import com.android.internal.location.TrackProvider;
83import com.android.server.am.BatteryStatsService;
84
85/**
86 * The service class that manages LocationProviders and issues location
87 * updates and alerts.
88 *
89 * {@hide}
90 */
91public class LocationManagerService extends ILocationManager.Stub
92 implements INetworkLocationManager {
93 private static final String TAG = "LocationManagerService";
The Android Open Source Project10592532009-03-18 17:39:46 -070094 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095
96 // Minimum time interval between last known location writes, in milliseconds.
97 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L;
98
99 // Max time to hold wake lock for, in milliseconds.
100 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
101
102 // Time to wait after releasing a wake lock for clients to process location update,
103 // in milliseconds.
104 private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L;
105
106 // The last time a location was written, by provider name.
107 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
108
109 private static final Pattern PATTERN_COMMA = Pattern.compile(",");
110
111 private static final String ACCESS_FINE_LOCATION =
112 android.Manifest.permission.ACCESS_FINE_LOCATION;
113 private static final String ACCESS_COARSE_LOCATION =
114 android.Manifest.permission.ACCESS_COARSE_LOCATION;
115 private static final String ACCESS_MOCK_LOCATION =
116 android.Manifest.permission.ACCESS_MOCK_LOCATION;
117 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
118 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
119
120 // Set of providers that are explicitly enabled
121 private final Set<String> mEnabledProviders = new HashSet<String>();
122
123 // Set of providers that are explicitly disabled
124 private final Set<String> mDisabledProviders = new HashSet<String>();
125
126 // Locations, status values, and extras for mock providers
Mike Lockwood7ec434e2009-03-27 07:46:48 -0700127 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
129 private static boolean sProvidersLoaded = false;
130
131 private final Context mContext;
132 private GpsLocationProvider mGpsLocationProvider;
133 private boolean mGpsNavigating;
134 private LocationProviderImpl mNetworkLocationProvider;
135 private INetworkLocationProvider mNetworkLocationInterface;
136 private LocationWorkerHandler mLocationHandler;
137
138 // Handler messages
139 private static final int MESSAGE_HEARTBEAT = 1;
140 private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
141 private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
142 private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4;
143
144 // Alarm manager and wakelock variables
145 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
146 private final static String WAKELOCK_KEY = "LocationManagerService";
147 private final static String WIFILOCK_KEY = "LocationManagerService";
148 private AlarmManager mAlarmManager;
149 private long mAlarmInterval = 0;
150 private boolean mScreenOn = true;
151 private PowerManager.WakeLock mWakeLock = null;
152 private WifiManager.WifiLock mWifiLock = null;
153 private long mWakeLockAcquireTime = 0;
154 private boolean mWakeLockGpsReceived = true;
155 private boolean mWakeLockNetworkReceived = true;
156 private boolean mWifiWakeLockAcquired = false;
157 private boolean mCellWakeLockAcquired = false;
158
159 private final IBatteryStats mBatteryStats;
160
161 /**
162 * Mapping from listener IBinder/PendingIntent to local Listener wrappers.
163 */
164 private final ArrayList<Receiver> mListeners = new ArrayList<Receiver>();
165
166 /**
167 * Used for reporting which UIDs are causing the GPS to run.
168 */
169 private final SparseIntArray mReportedGpsUids = new SparseIntArray();
170 private int mReportedGpsSeq = 0;
171
172 /**
173 * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord.
174 * This also serves as the lock for our state.
175 */
176 private final HashMap<Receiver,HashMap<String,UpdateRecord>> mLocationListeners =
177 new HashMap<Receiver,HashMap<String,UpdateRecord>>();
178
179 /**
180 * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast
181 * location.
182 */
183 private final HashMap<Receiver,HashMap<String,Location>> mLastFixBroadcast =
184 new HashMap<Receiver,HashMap<String,Location>>();
185 private final HashMap<Receiver,HashMap<String,Long>> mLastStatusBroadcast =
186 new HashMap<Receiver,HashMap<String,Long>>();
187
188 /**
189 * Mapping from provider name to all its UpdateRecords
190 */
191 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
192 new HashMap<String,ArrayList<UpdateRecord>>();
193
194 /**
195 * Mappings from provider name to object to use for current location. Locations
196 * contained in this list may not always be valid.
197 */
198 private final HashMap<String,Location> mLocationsByProvider =
199 new HashMap<String,Location>();
200
201 // Proximity listeners
202 private Receiver mProximityListener = null;
203 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
204 new HashMap<PendingIntent,ProximityAlert>();
205 private HashSet<ProximityAlert> mProximitiesEntered =
206 new HashSet<ProximityAlert>();
207
208 // Last known location for each provider
209 private HashMap<String,Location> mLastKnownLocation =
210 new HashMap<String,Location>();
211
212 // Battery status extras (from com.android.server.BatteryService)
213 private static final String BATTERY_EXTRA_SCALE = "scale";
214 private static final String BATTERY_EXTRA_LEVEL = "level";
215 private static final String BATTERY_EXTRA_PLUGGED = "plugged";
216
217 // Last known cell service state
218 private TelephonyManager mTelephonyManager;
219
220 // Location collector
221 private ILocationCollector mCollector;
222
223 // Wifi Manager
224 private WifiManager mWifiManager;
225
The Android Open Source Project4df24232009-03-05 14:34:35 -0800226 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
227 private boolean mWifiEnabled = false;
228
Mike Lockwood9637d472009-04-02 21:41:57 -0700229 // for Settings change notification
230 private ContentQueryMap mSettings;
231
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232 /**
233 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
234 * location updates.
235 */
236 private final class Receiver implements IBinder.DeathRecipient {
237 final ILocationListener mListener;
238 final PendingIntent mPendingIntent;
239 final int mUid;
240 final Object mKey;
241
242 Receiver(ILocationListener listener, int uid) {
243 mListener = listener;
244 mPendingIntent = null;
245 mUid = uid;
246 mKey = listener.asBinder();
247 }
248
249 Receiver(PendingIntent intent, int uid) {
250 mPendingIntent = intent;
251 mListener = null;
252 mUid = uid;
253 mKey = intent;
254 }
255
256 @Override
257 public boolean equals(Object otherObj) {
258 if (otherObj instanceof Receiver) {
259 return mKey.equals(
260 ((Receiver)otherObj).mKey);
261 }
262 return false;
263 }
264
265 @Override
266 public int hashCode() {
267 return mKey.hashCode();
268 }
269
270
271 @Override
272 public String toString() {
273 if (mListener != null) {
274 return "Receiver{"
275 + Integer.toHexString(System.identityHashCode(this))
276 + " uid " + mUid + " Listener " + mKey + "}";
277 } else {
278 return "Receiver{"
279 + Integer.toHexString(System.identityHashCode(this))
280 + " uid " + mUid + " Intent " + mKey + "}";
281 }
282 }
283
284 public boolean isListener() {
285 return mListener != null;
286 }
287
288 public boolean isPendingIntent() {
289 return mPendingIntent != null;
290 }
291
292 public ILocationListener getListener() {
293 if (mListener != null) {
294 return mListener;
295 }
296 throw new IllegalStateException("Request for non-existent listener");
297 }
298
299 public PendingIntent getPendingIntent() {
300 if (mPendingIntent != null) {
301 return mPendingIntent;
302 }
303 throw new IllegalStateException("Request for non-existent intent");
304 }
305
306 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
307 if (mListener != null) {
308 try {
309 mListener.onStatusChanged(provider, status, extras);
310 } catch (RemoteException e) {
311 return false;
312 }
313 } else {
314 Intent statusChanged = new Intent();
315 statusChanged.putExtras(extras);
316 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
317 try {
318 mPendingIntent.send(mContext, 0, statusChanged, null, null);
319 } catch (PendingIntent.CanceledException e) {
320 return false;
321 }
322 }
323 return true;
324 }
325
326 public boolean callLocationChangedLocked(Location location) {
327 if (mListener != null) {
328 try {
329 mListener.onLocationChanged(location);
330 } catch (RemoteException e) {
331 return false;
332 }
333 } else {
334 Intent locationChanged = new Intent();
335 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
336 try {
337 mPendingIntent.send(mContext, 0, locationChanged, null, null);
338 } catch (PendingIntent.CanceledException e) {
339 return false;
340 }
341 }
342 return true;
343 }
344
345 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700346 if (LOCAL_LOGV) {
347 Log.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800348 }
349 synchronized (mLocationListeners) {
350 removeUpdatesLocked(this);
351 }
352 }
353 }
354
Mike Lockwood9637d472009-04-02 21:41:57 -0700355 private final class SettingsObserver implements Observer {
356 public void update(Observable o, Object arg) {
357 synchronized (mLocationListeners) {
358 updateProvidersLocked();
359 }
360 }
361 }
362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 private Location readLastKnownLocationLocked(String provider) {
364 Location location = null;
365 String s = null;
366 try {
367 File f = new File(LocationManager.SYSTEM_DIR + "/location."
368 + provider);
369 if (!f.exists()) {
370 return null;
371 }
372 BufferedReader reader = new BufferedReader(new FileReader(f), 256);
373 s = reader.readLine();
374 } catch (IOException e) {
375 Log.w(TAG, "Unable to read last known location", e);
376 }
377
378 if (s == null) {
379 return null;
380 }
381 try {
382 String[] tokens = PATTERN_COMMA.split(s);
383 int idx = 0;
384 long time = Long.parseLong(tokens[idx++]);
385 double latitude = Double.parseDouble(tokens[idx++]);
386 double longitude = Double.parseDouble(tokens[idx++]);
387 double altitude = Double.parseDouble(tokens[idx++]);
388 float bearing = Float.parseFloat(tokens[idx++]);
389 float speed = Float.parseFloat(tokens[idx++]);
390
391 location = new Location(provider);
392 location.setTime(time);
393 location.setLatitude(latitude);
394 location.setLongitude(longitude);
395 location.setAltitude(altitude);
396 location.setBearing(bearing);
397 location.setSpeed(speed);
398 } catch (NumberFormatException nfe) {
399 Log.e(TAG, "NumberFormatException reading last known location", nfe);
400 return null;
401 }
402
403 return location;
404 }
405
406 private void writeLastKnownLocationLocked(String provider,
407 Location location) {
408 long now = SystemClock.elapsedRealtime();
409 Long last = mLastWriteTime.get(provider);
410 if ((last != null)
411 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
412 return;
413 }
414 mLastWriteTime.put(provider, now);
415
416 StringBuilder sb = new StringBuilder(100);
417 sb.append(location.getTime());
418 sb.append(',');
419 sb.append(location.getLatitude());
420 sb.append(',');
421 sb.append(location.getLongitude());
422 sb.append(',');
423 sb.append(location.getAltitude());
424 sb.append(',');
425 sb.append(location.getBearing());
426 sb.append(',');
427 sb.append(location.getSpeed());
428
429 FileWriter writer = null;
430 try {
431 File d = new File(LocationManager.SYSTEM_DIR);
432 if (!d.exists()) {
433 if (!d.mkdirs()) {
434 Log.w(TAG, "Unable to create directory to write location");
435 return;
436 }
437 }
438 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
439 writer = new FileWriter(f);
440 writer.write(sb.toString());
441 } catch (IOException e) {
442 Log.w(TAG, "Unable to write location", e);
443 } finally {
444 if (writer != null) {
445 try {
446 writer.close();
447 } catch (IOException e) {
448 Log.w(TAG, "Exception closing file", e);
449 }
450 }
451 }
452 }
453
454 /**
455 * Load providers from /data/location/<provider_name>/
456 * class
457 * kml
458 * nmea
459 * track
460 * location
461 * properties
462 */
463 private void loadProviders() {
464 synchronized (mLocationListeners) {
465 if (sProvidersLoaded) {
466 return;
467 }
468
469 // Load providers
470 loadProvidersLocked();
471 sProvidersLoaded = true;
472 }
473 }
474
475 private void loadProvidersLocked() {
476 try {
477 _loadProvidersLocked();
478 } catch (Exception e) {
479 Log.e(TAG, "Exception loading providers:", e);
480 }
481 }
482
483 private void _loadProvidersLocked() {
484 // Attempt to load "real" providers first
485 if (GpsLocationProvider.isSupported()) {
486 // Create a gps location provider
487 mGpsLocationProvider = new GpsLocationProvider(mContext);
488 LocationProviderImpl.addProvider(mGpsLocationProvider);
489 }
490
491 // Load fake providers if real providers are not available
492 File f = new File(LocationManager.PROVIDER_DIR);
493 if (f.isDirectory()) {
494 File[] subdirs = f.listFiles();
495 for (int i = 0; i < subdirs.length; i++) {
496 if (!subdirs[i].isDirectory()) {
497 continue;
498 }
499
500 String name = subdirs[i].getName();
501
The Android Open Source Project10592532009-03-18 17:39:46 -0700502 if (LOCAL_LOGV) {
503 Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath());
504 Log.v(TAG, "name = " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 }
506
507 // Don't create a fake provider if a real provider exists
508 if (LocationProviderImpl.getProvider(name) == null) {
509 LocationProviderImpl provider = null;
510 try {
511 File classFile = new File(subdirs[i], "class");
512 // Look for a 'class' file
513 provider = LocationProviderImpl.loadFromClass(classFile);
514
515 // Look for an 'kml', 'nmea', or 'track' file
516 if (provider == null) {
517 // Load properties from 'properties' file, if present
518 File propertiesFile = new File(subdirs[i], "properties");
519
520 if (propertiesFile.exists()) {
521 provider = new TrackProvider(name);
522 ((TrackProvider)provider).readProperties(propertiesFile);
523
524 File kmlFile = new File(subdirs[i], "kml");
525 if (kmlFile.exists()) {
526 ((TrackProvider) provider).readKml(kmlFile);
527 } else {
528 File nmeaFile = new File(subdirs[i], "nmea");
529 if (nmeaFile.exists()) {
530 ((TrackProvider) provider).readNmea(name, nmeaFile);
531 } else {
532 File trackFile = new File(subdirs[i], "track");
533 if (trackFile.exists()) {
534 ((TrackProvider) provider).readTrack(trackFile);
535 }
536 }
537 }
538 }
539 }
540 if (provider != null) {
541 LocationProviderImpl.addProvider(provider);
542 }
543 // Grab the initial location of a TrackProvider and
544 // store it as the last known location for that provider
545 if (provider instanceof TrackProvider) {
546 TrackProvider tp = (TrackProvider) provider;
547 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation());
548 }
549 } catch (Exception e) {
550 Log.e(TAG, "Exception loading provder " + name, e);
551 }
552 }
553 }
554 }
555
556 updateProvidersLocked();
557 }
558
559 /**
560 * @param context the context that the LocationManagerService runs in
561 */
562 public LocationManagerService(Context context) {
563 super();
564 mContext = context;
565 mLocationHandler = new LocationWorkerHandler();
566
The Android Open Source Project10592532009-03-18 17:39:46 -0700567 if (LOCAL_LOGV) {
568 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 }
570
571 // Alarm manager, needs to be done before calling loadProviders() below
572 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
573
574 // Create a wake lock, needs to be done before calling loadProviders() below
575 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
576 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
577
578 // Battery statistics service to be notified when GPS turns on or off
579 mBatteryStats = BatteryStatsService.getService();
580
581 // Load providers
582 loadProviders();
583
584 // Listen for Radio changes
585 mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
586 mTelephonyManager.listen(mPhoneStateListener,
587 PhoneStateListener.LISTEN_CELL_LOCATION |
588 PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
589 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
590
591 // Register for Network (Wifi or Mobile) updates
592 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
593 IntentFilter networkIntentFilter = new IntentFilter();
594 networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
595 networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
596 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
597 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
598 context.registerReceiver(networkReceiver, networkIntentFilter);
599
600 // Register for power updates
601 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
602 IntentFilter intentFilter = new IntentFilter();
603 intentFilter.addAction(ALARM_INTENT);
604 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
605 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
606 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
607 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
608 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
609 context.registerReceiver(powerStateReceiver, intentFilter);
610
Mike Lockwood9637d472009-04-02 21:41:57 -0700611 // listen for settings changes
612 ContentResolver resolver = mContext.getContentResolver();
613 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
614 "(" + Settings.System.NAME + "=?)",
615 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
616 null);
617 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
618 SettingsObserver settingsObserver = new SettingsObserver();
619 mSettings.addObserver(settingsObserver);
620
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 // Get the wifi manager
622 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
623
624 // Create a wifi lock for future use
625 mWifiLock = getWifiWakelockLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800626 }
627
628 public void setInstallCallback(InstallCallback callback) {
629 synchronized (mLocationListeners) {
630 mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
631 Message m = Message.obtain(mLocationHandler,
632 MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
633 mLocationHandler.sendMessageAtFrontOfQueue(m);
634 }
635 }
636
637 public void setNetworkLocationProvider(INetworkLocationProvider provider) {
638 synchronized (mLocationListeners) {
639 mNetworkLocationInterface = provider;
640 provider.addListener(getPackageNames());
641 mNetworkLocationProvider = (LocationProviderImpl)provider;
642 LocationProviderImpl.addProvider(mNetworkLocationProvider);
643 updateProvidersLocked();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800644
645 // notify NetworkLocationProvider of any events it might have missed
646 synchronized (mLocationListeners) {
647 mNetworkLocationProvider.updateNetworkState(mNetworkState);
648 mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled);
649 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
650
651 if (mLastCellState != null) {
652 if (mCollector != null) {
653 mCollector.updateCellState(mLastCellState);
654 }
655 mNetworkLocationProvider.updateCellState(mLastCellState);
656 }
657
658 // There might be an existing wifi scan available
659 if (mWifiManager != null) {
660 List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
661 if (wifiScanResults != null && wifiScanResults.size() != 0) {
662 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
663 if (mCollector != null) {
664 mCollector.updateWifiScanResults(wifiScanResults);
665 }
666 }
667 }
668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 }
670 }
671
672 public void setLocationCollector(ILocationCollector collector) {
673 synchronized (mLocationListeners) {
674 mCollector = collector;
675 if (mGpsLocationProvider != null) {
676 mGpsLocationProvider.setLocationCollector(mCollector);
677 }
678 }
679 }
680
681 private WifiManager.WifiLock getWifiWakelockLocked() {
682 if (mWifiLock == null && mWifiManager != null) {
683 mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
684 mWifiLock.setReferenceCounted(false);
685 }
686 return mWifiLock;
687 }
688
689 private boolean isAllowedBySettingsLocked(String provider) {
690 if (mEnabledProviders.contains(provider)) {
691 return true;
692 }
693 if (mDisabledProviders.contains(provider)) {
694 return false;
695 }
696 // Use system settings
697 ContentResolver resolver = mContext.getContentResolver();
698 String allowedProviders = Settings.Secure.getString(resolver,
699 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
700
701 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
702 }
703
704 private void checkPermissionsSafe(String provider) {
705 if (LocationManager.GPS_PROVIDER.equals(provider)
706 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
707 != PackageManager.PERMISSION_GRANTED)) {
708 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
709 }
710 if (LocationManager.NETWORK_PROVIDER.equals(provider)
711 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
712 != PackageManager.PERMISSION_GRANTED)
713 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
714 != PackageManager.PERMISSION_GRANTED)) {
715 throw new SecurityException(
716 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
717 }
718 }
719
720 private boolean isAllowedProviderSafe(String provider) {
721 if (LocationManager.GPS_PROVIDER.equals(provider)
722 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
723 != PackageManager.PERMISSION_GRANTED)) {
724 return false;
725 }
726 if (LocationManager.NETWORK_PROVIDER.equals(provider)
727 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
728 != PackageManager.PERMISSION_GRANTED)
729 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
730 != PackageManager.PERMISSION_GRANTED)) {
731 return false;
732 }
733
734 return true;
735 }
736
737 private String[] getPackageNames() {
738 // Since a single UID may correspond to multiple packages, this can only be used as an
739 // approximation for tracking
740 return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
741 }
742
743 public List<String> getAllProviders() {
744 try {
745 synchronized (mLocationListeners) {
746 return _getAllProvidersLocked();
747 }
748 } catch (SecurityException se) {
749 throw se;
750 } catch (Exception e) {
751 Log.e(TAG, "getAllProviders got exception:", e);
752 return null;
753 }
754 }
755
756 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700757 if (LOCAL_LOGV) {
758 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
760 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
761 ArrayList<String> out = new ArrayList<String>(providers.size());
762
763 for (LocationProviderImpl p : providers) {
764 out.add(p.getName());
765 }
766 return out;
767 }
768
769 public List<String> getProviders(boolean enabledOnly) {
770 try {
771 synchronized (mLocationListeners) {
772 return _getProvidersLocked(enabledOnly);
773 }
774 } catch (SecurityException se) {
775 throw se;
776 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700777 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 return null;
779 }
780 }
781
782 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700783 if (LOCAL_LOGV) {
784 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 }
786 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
787 ArrayList<String> out = new ArrayList<String>();
788
789 for (LocationProviderImpl p : providers) {
790 String name = p.getName();
791 if (isAllowedProviderSafe(name)) {
792 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
793 continue;
794 }
795 out.add(name);
796 }
797 }
798 return out;
799 }
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 private void updateProvidersLocked() {
802 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
803 boolean isEnabled = p.isEnabled();
804 String name = p.getName();
805 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
806
807 // Collection is only allowed when network provider is being used
808 if (mCollector != null &&
809 p.getName().equals(LocationManager.NETWORK_PROVIDER)) {
810 mCollector.updateNetworkProviderStatus(shouldBeEnabled);
811 }
812
813 if (isEnabled && !shouldBeEnabled) {
814 updateProviderListenersLocked(name, false);
815 } else if (!isEnabled && shouldBeEnabled) {
816 updateProviderListenersLocked(name, true);
817 }
818
819 }
820 }
821
822 private void updateProviderListenersLocked(String provider, boolean enabled) {
823 int listeners = 0;
824
825 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
826 if (p == null) {
827 return;
828 }
829
830 ArrayList<Receiver> deadReceivers = null;
831
832 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
833 if (records != null) {
834 final int N = records.size();
835 for (int i=0; i<N; i++) {
836 UpdateRecord record = records.get(i);
837 // Sends a notification message to the receiver
838 try {
839 Receiver receiver = record.mReceiver;
840 if (receiver.isListener()) {
841 if (enabled) {
842 receiver.getListener().onProviderEnabled(provider);
843 } else {
844 receiver.getListener().onProviderDisabled(provider);
845 }
846 } else {
847 Intent providerIntent = new Intent();
848 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
849 try {
850 receiver.getPendingIntent().send(mContext, 0,
851 providerIntent, null, null);
852 } catch (PendingIntent.CanceledException e) {
853 if (deadReceivers == null) {
854 deadReceivers = new ArrayList<Receiver>();
855 deadReceivers.add(receiver);
856 }
857 }
858 }
859 } catch (RemoteException e) {
860 // The death link will clean this up.
861 }
862 listeners++;
863 }
864 }
865
866 if (deadReceivers != null) {
867 for (int i=deadReceivers.size()-1; i>=0; i--) {
868 removeUpdatesLocked(deadReceivers.get(i));
869 }
870 }
871
872 if (enabled) {
873 p.enable();
874 if (listeners > 0) {
875 p.setMinTime(getMinTimeLocked(provider));
876 p.enableLocationTracking(true);
877 updateWakelockStatusLocked(mScreenOn);
878 }
879 } else {
880 p.enableLocationTracking(false);
881 if (p == mGpsLocationProvider) {
882 mGpsNavigating = false;
883 reportStopGpsLocked();
884 }
885 p.disable();
886 updateWakelockStatusLocked(mScreenOn);
887 }
888
889 if (enabled && listeners > 0) {
890 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
891 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
892 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
893 } else {
894 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
895 }
896 }
897
898 private long getMinTimeLocked(String provider) {
899 long minTime = Long.MAX_VALUE;
900 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
901 if (records != null) {
902 for (int i=records.size()-1; i>=0; i--) {
903 minTime = Math.min(minTime, records.get(i).mMinTime);
904 }
905 }
906 return minTime;
907 }
908
909 private class UpdateRecord {
910 final String mProvider;
911 final Receiver mReceiver;
912 final long mMinTime;
913 final float mMinDistance;
914 final int mUid;
915 final String[] mPackages;
916
917 /**
918 * Note: must be constructed with lock held.
919 */
920 UpdateRecord(String provider, long minTime, float minDistance,
921 Receiver receiver, int uid, String[] packages) {
922 mProvider = provider;
923 mReceiver = receiver;
924 mMinTime = minTime;
925 mMinDistance = minDistance;
926 mUid = uid;
927 mPackages = packages;
928
929 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
930 if (records == null) {
931 records = new ArrayList<UpdateRecord>();
932 mRecordsByProvider.put(provider, records);
933 }
934 if (!records.contains(this)) {
935 records.add(this);
936 }
937 }
938
939 /**
940 * Method to be called when a record will no longer be used. Calling this multiple times
941 * must have the same effect as calling it once.
942 */
943 void disposeLocked() {
944 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
945 records.remove(this);
946 }
947
948 @Override
949 public String toString() {
950 return "UpdateRecord{"
951 + Integer.toHexString(System.identityHashCode(this))
952 + " " + mProvider + " " + mReceiver + "}";
953 }
954
955 void dump(PrintWriter pw, String prefix) {
956 pw.println(prefix + this);
957 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
958 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
959 StringBuilder sb = new StringBuilder();
960 if (mPackages != null) {
961 for (int i=0; i<mPackages.length; i++) {
962 if (i > 0) sb.append(", ");
963 sb.append(mPackages[i]);
964 }
965 }
966 pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb);
967 }
968
969 /**
970 * Calls dispose().
971 */
972 @Override protected void finalize() {
973 synchronized (mLocationListeners) {
974 disposeLocked();
975 }
976 }
977 }
978
979 public void requestLocationUpdates(String provider,
980 long minTime, float minDistance, ILocationListener listener) {
981
982 try {
983 synchronized (mLocationListeners) {
984 requestLocationUpdatesLocked(provider, minTime, minDistance,
985 new Receiver(listener, Binder.getCallingUid()));
986 }
987 } catch (SecurityException se) {
988 throw se;
989 } catch (Exception e) {
990 Log.e(TAG, "requestUpdates got exception:", e);
991 }
992 }
993
994 public void requestLocationUpdatesPI(String provider,
995 long minTime, float minDistance, PendingIntent intent) {
996 try {
997 synchronized (mLocationListeners) {
998 requestLocationUpdatesLocked(provider, minTime, minDistance,
999 new Receiver(intent, Binder.getCallingUid()));
1000 }
1001 } catch (SecurityException se) {
1002 throw se;
1003 } catch (Exception e) {
1004 Log.e(TAG, "requestUpdates got exception:", e);
1005 }
1006 }
1007
1008 private void requestLocationUpdatesLocked(String provider,
1009 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001010 if (LOCAL_LOGV) {
1011 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001012 }
1013
1014 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1015 if (impl == null) {
1016 throw new IllegalArgumentException("provider=" + provider);
1017 }
1018
1019 checkPermissionsSafe(provider);
1020
1021 String[] packages = getPackageNames();
1022
1023 // so wakelock calls will succeed
1024 final int callingUid = Binder.getCallingUid();
1025 long identity = Binder.clearCallingIdentity();
1026 try {
1027 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance,
1028 receiver, callingUid, packages);
1029 if (!mListeners.contains(receiver)) {
1030 try {
1031 if (receiver.isListener()) {
1032 receiver.getListener().asBinder().linkToDeath(receiver, 0);
1033 }
1034 mListeners.add(receiver);
1035 } catch (RemoteException e) {
1036 return;
1037 }
1038 }
1039
1040 HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver);
1041 if (records == null) {
1042 records = new HashMap<String,UpdateRecord>();
1043 mLocationListeners.put(receiver, records);
1044 }
1045 UpdateRecord oldRecord = records.put(provider, r);
1046 if (oldRecord != null) {
1047 oldRecord.disposeLocked();
1048 }
1049
1050 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1051 if (isProviderEnabled) {
1052 long minTimeForProvider = getMinTimeLocked(provider);
1053 impl.setMinTime(minTimeForProvider);
1054 impl.enableLocationTracking(true);
1055 updateWakelockStatusLocked(mScreenOn);
1056
1057 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1058 if (mGpsNavigating) {
1059 updateReportedGpsLocked();
1060 }
1061 }
1062
1063 // Clear heartbeats if any before starting a new one
1064 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
1065 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
1066 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
1067 } else {
1068 try {
1069 // Notify the listener that updates are currently disabled
1070 if (receiver.isListener()) {
1071 receiver.getListener().onProviderDisabled(provider);
1072 }
1073 } catch(RemoteException e) {
1074 Log.w(TAG, "RemoteException calling onProviderDisabled on " +
1075 receiver.getListener());
1076 }
1077 }
1078 } finally {
1079 Binder.restoreCallingIdentity(identity);
1080 }
1081 }
1082
1083 public void removeUpdates(ILocationListener listener) {
1084 try {
1085 synchronized (mLocationListeners) {
1086 removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid()));
1087 }
1088 } catch (SecurityException se) {
1089 throw se;
1090 } catch (Exception e) {
1091 Log.e(TAG, "removeUpdates got exception:", e);
1092 }
1093 }
1094
1095 public void removeUpdatesPI(PendingIntent intent) {
1096 try {
1097 synchronized (mLocationListeners) {
1098 removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid()));
1099 }
1100 } catch (SecurityException se) {
1101 throw se;
1102 } catch (Exception e) {
1103 Log.e(TAG, "removeUpdates got exception:", e);
1104 }
1105 }
1106
1107 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001108 if (LOCAL_LOGV) {
1109 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111
1112 // so wakelock calls will succeed
1113 final int callingUid = Binder.getCallingUid();
1114 long identity = Binder.clearCallingIdentity();
1115 try {
1116 int idx = mListeners.indexOf(receiver);
1117 if (idx >= 0) {
1118 Receiver myReceiver = mListeners.remove(idx);
1119 if (myReceiver.isListener()) {
1120 myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0);
1121 }
1122 }
1123
1124 // Record which providers were associated with this listener
1125 HashSet<String> providers = new HashSet<String>();
1126 HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver);
1127 if (oldRecords != null) {
1128 // Call dispose() on the obsolete update records.
1129 for (UpdateRecord record : oldRecords.values()) {
1130 if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) {
1131 if (mNetworkLocationInterface != null) {
1132 mNetworkLocationInterface.removeListener(record.mPackages);
1133 }
1134 }
1135 record.disposeLocked();
1136 }
1137 // Accumulate providers
1138 providers.addAll(oldRecords.keySet());
1139 }
1140
1141 mLocationListeners.remove(receiver);
1142 mLastFixBroadcast.remove(receiver);
1143 mLastStatusBroadcast.remove(receiver);
1144
1145 // See if the providers associated with this listener have any
1146 // other listeners; if one does, inform it of the new smallest minTime
1147 // value; if one does not, disable location tracking for it
1148 for (String provider : providers) {
1149 // If provider is already disabled, don't need to do anything
1150 if (!isAllowedBySettingsLocked(provider)) {
1151 continue;
1152 }
1153
1154 boolean hasOtherListener = false;
1155 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1156 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1157 hasOtherListener = true;
1158 }
1159
1160 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1161 if (p != null) {
1162 if (hasOtherListener) {
1163 p.setMinTime(getMinTimeLocked(provider));
1164 } else {
1165 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
1166 p.enableLocationTracking(false);
1167 }
1168
1169 if (p == mGpsLocationProvider && mGpsNavigating) {
1170 updateReportedGpsLocked();
1171 }
1172 }
1173 }
1174
1175 updateWakelockStatusLocked(mScreenOn);
1176 } finally {
1177 Binder.restoreCallingIdentity(identity);
1178 }
1179 }
1180
1181 public boolean addGpsStatusListener(IGpsStatusListener listener) {
1182 if (mGpsLocationProvider == null) {
1183 return false;
1184 }
1185 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
1186 PackageManager.PERMISSION_GRANTED) {
1187 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1188 }
1189
1190 try {
1191 mGpsLocationProvider.addGpsStatusListener(listener);
1192 } catch (RemoteException e) {
1193 Log.w(TAG, "RemoteException in addGpsStatusListener");
1194 return false;
1195 }
1196 return true;
1197 }
1198
1199 public void removeGpsStatusListener(IGpsStatusListener listener) {
1200 synchronized (mLocationListeners) {
1201 mGpsLocationProvider.removeGpsStatusListener(listener);
1202 }
1203 }
1204
1205 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1206 // first check for permission to the provider
1207 checkPermissionsSafe(provider);
1208 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1209 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1210 != PackageManager.PERMISSION_GRANTED)) {
1211 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1212 }
1213
1214 synchronized (mLocationListeners) {
1215 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1216 if (provider == null) {
1217 return false;
1218 }
1219
1220 return impl.sendExtraCommand(command, extras);
1221 }
1222 }
1223
1224 class ProximityAlert {
1225 final int mUid;
1226 final double mLatitude;
1227 final double mLongitude;
1228 final float mRadius;
1229 final long mExpiration;
1230 final PendingIntent mIntent;
1231 final Location mLocation;
1232
1233 public ProximityAlert(int uid, double latitude, double longitude,
1234 float radius, long expiration, PendingIntent intent) {
1235 mUid = uid;
1236 mLatitude = latitude;
1237 mLongitude = longitude;
1238 mRadius = radius;
1239 mExpiration = expiration;
1240 mIntent = intent;
1241
1242 mLocation = new Location("");
1243 mLocation.setLatitude(latitude);
1244 mLocation.setLongitude(longitude);
1245 }
1246
1247 long getExpiration() {
1248 return mExpiration;
1249 }
1250
1251 PendingIntent getIntent() {
1252 return mIntent;
1253 }
1254
1255 boolean isInProximity(double latitude, double longitude) {
1256 Location loc = new Location("");
1257 loc.setLatitude(latitude);
1258 loc.setLongitude(longitude);
1259
1260 double radius = loc.distanceTo(mLocation);
1261 return radius <= mRadius;
1262 }
1263
1264 @Override
1265 public String toString() {
1266 return "ProximityAlert{"
1267 + Integer.toHexString(System.identityHashCode(this))
1268 + " uid " + mUid + mIntent + "}";
1269 }
1270
1271 void dump(PrintWriter pw, String prefix) {
1272 pw.println(prefix + this);
1273 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1274 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1275 pw.println(prefix + "mIntent=" + mIntent);
1276 pw.println(prefix + "mLocation:");
1277 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1278 }
1279 }
1280
1281 // Listener for receiving locations to trigger proximity alerts
1282 class ProximityListener extends ILocationListener.Stub {
1283
1284 boolean isGpsAvailable = false;
1285
1286 // Note: this is called with the lock held.
1287 public void onLocationChanged(Location loc) {
1288
1289 // If Gps is available, then ignore updates from NetworkLocationProvider
1290 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1291 isGpsAvailable = true;
1292 }
1293 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1294 return;
1295 }
1296
1297 // Process proximity alerts
1298 long now = System.currentTimeMillis();
1299 double latitude = loc.getLatitude();
1300 double longitude = loc.getLongitude();
1301 ArrayList<PendingIntent> intentsToRemove = null;
1302
1303 for (ProximityAlert alert : mProximityAlerts.values()) {
1304 PendingIntent intent = alert.getIntent();
1305 long expiration = alert.getExpiration();
1306
1307 if ((expiration == -1) || (now <= expiration)) {
1308 boolean entered = mProximitiesEntered.contains(alert);
1309 boolean inProximity =
1310 alert.isInProximity(latitude, longitude);
1311 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001312 if (LOCAL_LOGV) {
1313 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 }
1315 mProximitiesEntered.add(alert);
1316 Intent enteredIntent = new Intent();
1317 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1318 try {
1319 intent.send(mContext, 0, enteredIntent, null, null);
1320 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001321 if (LOCAL_LOGV) {
1322 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 }
1324 if (intentsToRemove == null) {
1325 intentsToRemove = new ArrayList<PendingIntent>();
1326 }
1327 intentsToRemove.add(intent);
1328 }
1329 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001330 if (LOCAL_LOGV) {
1331 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001332 }
1333 mProximitiesEntered.remove(alert);
1334 Intent exitedIntent = new Intent();
1335 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1336 try {
1337 intent.send(mContext, 0, exitedIntent, null, null);
1338 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001339 if (LOCAL_LOGV) {
1340 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001341 }
1342 if (intentsToRemove == null) {
1343 intentsToRemove = new ArrayList<PendingIntent>();
1344 }
1345 intentsToRemove.add(intent);
1346 }
1347 }
1348 } else {
1349 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001350 if (LOCAL_LOGV) {
1351 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 }
1353 if (intentsToRemove == null) {
1354 intentsToRemove = new ArrayList<PendingIntent>();
1355 }
1356 intentsToRemove.add(alert.getIntent());
1357 }
1358 }
1359
1360 // Remove expired alerts
1361 if (intentsToRemove != null) {
1362 for (PendingIntent i : intentsToRemove) {
1363 mProximityAlerts.remove(i);
1364 ProximityAlert alert = mProximityAlerts.get(i);
1365 mProximitiesEntered.remove(alert);
1366 }
1367 }
1368
1369 }
1370
1371 // Note: this is called with the lock held.
1372 public void onProviderDisabled(String provider) {
1373 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1374 isGpsAvailable = false;
1375 }
1376 }
1377
1378 // Note: this is called with the lock held.
1379 public void onProviderEnabled(String provider) {
1380 // ignore
1381 }
1382
1383 // Note: this is called with the lock held.
1384 public void onStatusChanged(String provider, int status, Bundle extras) {
1385 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1386 (status != LocationProvider.AVAILABLE)) {
1387 isGpsAvailable = false;
1388 }
1389 }
1390 }
1391
1392 public void addProximityAlert(double latitude, double longitude,
1393 float radius, long expiration, PendingIntent intent) {
1394 try {
1395 synchronized (mLocationListeners) {
1396 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1397 }
1398 } catch (SecurityException se) {
1399 throw se;
1400 } catch (Exception e) {
1401 Log.e(TAG, "addProximityAlert got exception:", e);
1402 }
1403 }
1404
1405 private void addProximityAlertLocked(double latitude, double longitude,
1406 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001407 if (LOCAL_LOGV) {
1408 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 ", longitude = " + longitude +
1410 ", expiration = " + expiration +
1411 ", intent = " + intent);
1412 }
1413
1414 // Require ability to access all providers for now
1415 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1416 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1417 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1418 }
1419
1420 if (expiration != -1) {
1421 expiration += System.currentTimeMillis();
1422 }
1423 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1424 latitude, longitude, radius, expiration, intent);
1425 mProximityAlerts.put(intent, alert);
1426
1427 if (mProximityListener == null) {
1428 mProximityListener = new Receiver(new ProximityListener(), -1);
1429
1430 LocationProvider provider = LocationProviderImpl.getProvider(
1431 LocationManager.GPS_PROVIDER);
1432 if (provider != null) {
1433 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
1434 }
1435
1436 provider =
1437 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
1438 if (provider != null) {
1439 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
1440 }
1441 } else if (mGpsNavigating) {
1442 updateReportedGpsLocked();
1443 }
1444 }
1445
1446 public void removeProximityAlert(PendingIntent intent) {
1447 try {
1448 synchronized (mLocationListeners) {
1449 removeProximityAlertLocked(intent);
1450 }
1451 } catch (SecurityException se) {
1452 throw se;
1453 } catch (Exception e) {
1454 Log.e(TAG, "removeProximityAlert got exception:", e);
1455 }
1456 }
1457
1458 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001459 if (LOCAL_LOGV) {
1460 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001461 }
1462
1463 mProximityAlerts.remove(intent);
1464 if (mProximityAlerts.size() == 0) {
1465 removeUpdatesLocked(mProximityListener);
1466 mProximityListener = null;
1467 } else if (mGpsNavigating) {
1468 updateReportedGpsLocked();
1469 }
1470 }
1471
1472 /**
1473 * @return null if the provider does not exits
1474 * @throw SecurityException if the provider is not allowed to be
1475 * accessed by the caller
1476 */
1477 public Bundle getProviderInfo(String provider) {
1478 try {
1479 synchronized (mLocationListeners) {
1480 return _getProviderInfoLocked(provider);
1481 }
1482 } catch (SecurityException se) {
1483 throw se;
1484 } catch (Exception e) {
1485 Log.e(TAG, "_getProviderInfo got exception:", e);
1486 return null;
1487 }
1488 }
1489
1490 private Bundle _getProviderInfoLocked(String provider) {
1491 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1492 if (p == null) {
1493 return null;
1494 }
1495
1496 checkPermissionsSafe(provider);
1497
1498 Bundle b = new Bundle();
1499 b.putBoolean("network", p.requiresNetwork());
1500 b.putBoolean("satellite", p.requiresSatellite());
1501 b.putBoolean("cell", p.requiresCell());
1502 b.putBoolean("cost", p.hasMonetaryCost());
1503 b.putBoolean("altitude", p.supportsAltitude());
1504 b.putBoolean("speed", p.supportsSpeed());
1505 b.putBoolean("bearing", p.supportsBearing());
1506 b.putInt("power", p.getPowerRequirement());
1507 b.putInt("accuracy", p.getAccuracy());
1508
1509 return b;
1510 }
1511
1512 public boolean isProviderEnabled(String provider) {
1513 try {
1514 synchronized (mLocationListeners) {
1515 return _isProviderEnabledLocked(provider);
1516 }
1517 } catch (SecurityException se) {
1518 throw se;
1519 } catch (Exception e) {
1520 Log.e(TAG, "isProviderEnabled got exception:", e);
1521 return false;
1522 }
1523 }
1524
1525 private boolean _isProviderEnabledLocked(String provider) {
1526 checkPermissionsSafe(provider);
1527
1528 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1529 if (p == null) {
1530 throw new IllegalArgumentException("provider=" + provider);
1531 }
1532 return isAllowedBySettingsLocked(provider);
1533 }
1534
1535 public Location getLastKnownLocation(String provider) {
1536 try {
1537 synchronized (mLocationListeners) {
1538 return _getLastKnownLocationLocked(provider);
1539 }
1540 } catch (SecurityException se) {
1541 throw se;
1542 } catch (Exception e) {
1543 Log.e(TAG, "getLastKnownLocation got exception:", e);
1544 return null;
1545 }
1546 }
1547
1548 private Location _getLastKnownLocationLocked(String provider) {
1549 checkPermissionsSafe(provider);
1550
1551 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1552 if (p == null) {
1553 throw new IllegalArgumentException("provider=" + provider);
1554 }
1555
1556 if (!isAllowedBySettingsLocked(provider)) {
1557 return null;
1558 }
1559
1560 Location location = mLastKnownLocation.get(provider);
1561 if (location == null) {
1562 // Get the persistent last known location for the provider
1563 location = readLastKnownLocationLocked(provider);
1564 if (location != null) {
1565 mLastKnownLocation.put(provider, location);
1566 }
1567 }
1568
1569 return location;
1570 }
1571
1572 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1573 // Always broadcast the first update
1574 if (lastLoc == null) {
1575 return true;
1576 }
1577
1578 // Don't broadcast same location again regardless of condition
1579 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1580 if (loc.getTime() == lastLoc.getTime()) {
1581 return false;
1582 }
1583
1584 // Check whether sufficient distance has been traveled
1585 double minDistance = record.mMinDistance;
1586 if (minDistance > 0.0) {
1587 if (loc.distanceTo(lastLoc) <= minDistance) {
1588 return false;
1589 }
1590 }
1591
1592 return true;
1593 }
1594
1595 private void handleLocationChangedLocked(String provider) {
1596 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1597 if (records == null || records.size() == 0) {
1598 return;
1599 }
1600
1601 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1602 if (p == null) {
1603 return;
1604 }
1605
1606 // Get location object
1607 Location loc = mLocationsByProvider.get(provider);
1608 if (loc == null) {
1609 loc = new Location(provider);
1610 mLocationsByProvider.put(provider, loc);
1611 } else {
1612 loc.reset();
1613 }
1614
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001615 boolean locationValid;
1616
1617 // Use the mock location if available
1618 MockProvider mockProvider = mMockProviders.get(provider);
1619 if (mockProvider != null && mockProvider.getLocation(loc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 locationValid = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001621 } else {
1622 locationValid = p.getLocation(loc);
1623 }
1624
1625 // Update last known location for provider
1626 if (locationValid) {
1627 Location location = mLastKnownLocation.get(provider);
1628 if (location == null) {
1629 mLastKnownLocation.put(provider, new Location(loc));
1630 } else {
1631 location.set(loc);
1632 }
1633 writeLastKnownLocationLocked(provider, loc);
1634
1635 if (p instanceof INetworkLocationProvider) {
1636 mWakeLockNetworkReceived = true;
1637 } else if (p instanceof GpsLocationProvider) {
1638 // Gps location received signal is in NetworkStateBroadcastReceiver
1639 }
1640 }
1641
1642 // Fetch latest status update time
1643 long newStatusUpdateTime = p.getStatusUpdateTime();
1644
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001645 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001646 Bundle extras = new Bundle();
1647 int status = p.getStatus(extras);
1648
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001649 // Override with mock values if mock provider is present
1650 if (mockProvider != null) {
1651 status = mockProvider.overrideStatus(status);
1652 newStatusUpdateTime = mockProvider.overrideStatusUpdateTime(newStatusUpdateTime);
1653 mockProvider.overrideExtras(extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 }
1655
1656 ArrayList<Receiver> deadReceivers = null;
1657
1658 // Broadcast location or status to all listeners
1659 final int N = records.size();
1660 for (int i=0; i<N; i++) {
1661 UpdateRecord r = records.get(i);
1662 Receiver receiver = r.mReceiver;
1663
1664 // Broadcast location only if it is valid
1665 if (locationValid) {
1666 HashMap<String,Location> map = mLastFixBroadcast.get(receiver);
1667 if (map == null) {
1668 map = new HashMap<String,Location>();
1669 mLastFixBroadcast.put(receiver, map);
1670 }
1671 Location lastLoc = map.get(provider);
1672 if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) {
1673 if (lastLoc == null) {
1674 lastLoc = new Location(loc);
1675 map.put(provider, lastLoc);
1676 } else {
1677 lastLoc.set(loc);
1678 }
1679 if (!receiver.callLocationChangedLocked(loc)) {
1680 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1681 if (deadReceivers == null) {
1682 deadReceivers = new ArrayList<Receiver>();
1683 }
1684 deadReceivers.add(receiver);
1685 }
1686 }
1687 }
1688
1689 // Broadcast status message
1690 HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver);
1691 if (statusMap == null) {
1692 statusMap = new HashMap<String,Long>();
1693 mLastStatusBroadcast.put(receiver, statusMap);
1694 }
1695 long prevStatusUpdateTime =
1696 (statusMap.get(provider) != null) ? statusMap.get(provider) : 0;
1697
1698 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1699 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1700
1701 statusMap.put(provider, newStatusUpdateTime);
1702 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1703 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1704 if (deadReceivers == null) {
1705 deadReceivers = new ArrayList<Receiver>();
1706 }
1707 if (!deadReceivers.contains(receiver)) {
1708 deadReceivers.add(receiver);
1709 }
1710 }
1711 }
1712 }
1713
1714 if (deadReceivers != null) {
1715 for (int i=deadReceivers.size()-1; i>=0; i--) {
1716 removeUpdatesLocked(deadReceivers.get(i));
1717 }
1718 }
1719 }
1720
1721 private class LocationWorkerHandler extends Handler {
1722
1723 @Override
1724 public void handleMessage(Message msg) {
1725 try {
1726 if (msg.what == MESSAGE_HEARTBEAT) {
1727 // log("LocationWorkerHandler: Heartbeat!");
1728
1729 synchronized (mLocationListeners) {
1730 String provider = (String) msg.obj;
1731 if (!isAllowedBySettingsLocked(provider)) {
1732 return;
1733 }
1734
1735 // Process the location fix if the screen is on or we're holding a wakelock
1736 if (mScreenOn || (mWakeLockAcquireTime != 0)) {
1737 handleLocationChangedLocked(provider);
1738 }
1739
1740 // If it continues to have listeners
1741 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1742 if (records != null && records.size() > 0) {
1743 Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider);
1744 sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
1745 }
1746
1747 if ((mWakeLockAcquireTime != 0) &&
1748 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
1749 > MAX_TIME_FOR_WAKE_LOCK)) {
1750
1751 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1752 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1753
1754 log("LocationWorkerHandler: Exceeded max time for wake lock");
1755 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1756 sendMessageAtFrontOfQueue(m);
1757
1758 } else if (mWakeLockAcquireTime != 0 &&
1759 mWakeLockGpsReceived && mWakeLockNetworkReceived) {
1760
1761 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1762 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1763
1764 log("LocationWorkerHandler: Locations received.");
1765 mWakeLockAcquireTime = 0;
1766 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1767 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
1768 }
1769 }
1770
1771 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) {
1772 log("LocationWorkerHandler: Acquire");
1773 synchronized (mLocationListeners) {
1774 acquireWakeLockLocked();
1775 }
1776 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
1777 log("LocationWorkerHandler: Release");
1778
1779 // Update wakelock status so the next alarm is set before releasing wakelock
1780 synchronized (mLocationListeners) {
1781 updateWakelockStatusLocked(mScreenOn);
1782 releaseWakeLockLocked();
1783 }
1784 } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) {
1785 synchronized (mLocationListeners) {
1786 Log.d(TAG, "installing network location provider");
1787 INetworkLocationManager.InstallCallback callback =
1788 (INetworkLocationManager.InstallCallback)msg.obj;
1789 callback.installNetworkLocationProvider(LocationManagerService.this);
1790 }
1791 }
1792 } catch (Exception e) {
1793 // Log, don't crash!
1794 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1795 }
1796 }
1797 }
1798
1799 class CellLocationUpdater extends Thread {
1800 CellLocation mNextLocation;
1801
1802 CellLocationUpdater() {
1803 super("CellLocationUpdater");
1804 }
1805
1806 @Override
1807 public void run() {
1808 int curAsu = -1;
1809 CellLocation curLocation = null;
1810
1811 while (true) {
1812 // See if there is more work to do...
1813 synchronized (mLocationListeners) {
1814 if (curLocation == mNextLocation) {
1815 mCellLocationUpdater = null;
1816 break;
1817 }
1818
1819 curLocation = mNextLocation;
1820 if (curLocation == null) {
1821 mCellLocationUpdater = null;
1822 break;
1823 }
1824
1825 curAsu = mLastSignalStrength;
1826
1827 mNextLocation = null;
1828 }
1829
1830 try {
1831 // Gets cell state. This can block so must be done without
1832 // locks held.
1833 CellState cs = new CellState(mTelephonyManager, curLocation, curAsu);
1834
1835 synchronized (mLocationListeners) {
1836 mLastCellState = cs;
1837
1838 cs.updateSignalStrength(mLastSignalStrength);
1839 cs.updateRadioType(mLastRadioType);
1840
1841 // Notify collector
1842 if (mCollector != null) {
1843 mCollector.updateCellState(cs);
1844 }
1845
1846 // Updates providers
1847 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1848 for (LocationProviderImpl provider : providers) {
1849 if (provider.requiresCell()) {
1850 provider.updateCellState(cs);
1851 }
1852 }
1853 }
1854 } catch (RuntimeException e) {
1855 Log.e(TAG, "Exception in PhoneStateListener.onCellLocationChanged:", e);
1856 }
1857 }
1858 }
1859 }
1860
1861 CellLocationUpdater mCellLocationUpdater = null;
1862 CellState mLastCellState = null;
1863 int mLastSignalStrength = -1;
1864 int mLastRadioType = -1;
1865
1866 PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1867
1868 @Override
1869 public void onCellLocationChanged(CellLocation cellLocation) {
1870 synchronized (mLocationListeners) {
1871 if (mCellLocationUpdater == null) {
1872 mCellLocationUpdater = new CellLocationUpdater();
1873 mCellLocationUpdater.start();
1874 }
1875 mCellLocationUpdater.mNextLocation = cellLocation;
1876 }
1877 }
1878
1879 @Override
1880 public void onSignalStrengthChanged(int asu) {
1881 synchronized (mLocationListeners) {
1882 mLastSignalStrength = asu;
1883
1884 if (mLastCellState != null) {
1885 mLastCellState.updateSignalStrength(asu);
1886 }
1887 }
1888 }
1889
1890 @Override
1891 public void onDataConnectionStateChanged(int state) {
1892 synchronized (mLocationListeners) {
1893 // Get radio type
1894 int radioType = mTelephonyManager.getNetworkType();
1895 if (radioType == TelephonyManager.NETWORK_TYPE_GPRS ||
1896 radioType == TelephonyManager.NETWORK_TYPE_EDGE) {
1897 radioType = CellState.RADIO_TYPE_GPRS;
1898 } else if (radioType == TelephonyManager.NETWORK_TYPE_UMTS) {
1899 radioType = CellState.RADIO_TYPE_WCDMA;
1900 }
1901 mLastRadioType = radioType;
1902
1903 if (mLastCellState != null) {
1904 mLastCellState.updateRadioType(radioType);
1905 }
1906 }
1907 }
1908 };
1909
1910 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1911 @Override public void onReceive(Context context, Intent intent) {
1912 String action = intent.getAction();
1913
1914 if (action.equals(ALARM_INTENT)) {
1915 synchronized (mLocationListeners) {
1916 log("PowerStateBroadcastReceiver: Alarm received");
1917 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1918 // Have to do this immediately, rather than posting a
1919 // message, so we execute our code while the system
1920 // is holding a wake lock until the alarm broadcast
1921 // is finished.
1922 acquireWakeLockLocked();
1923 }
1924
1925 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1926 log("PowerStateBroadcastReceiver: Screen off");
1927 synchronized (mLocationListeners) {
1928 updateWakelockStatusLocked(false);
1929 }
1930
1931 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1932 log("PowerStateBroadcastReceiver: Screen on");
1933 synchronized (mLocationListeners) {
1934 updateWakelockStatusLocked(true);
1935 }
1936
1937 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1938 log("PowerStateBroadcastReceiver: Battery changed");
1939 synchronized (mLocationListeners) {
1940 int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100);
1941 int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0);
1942 boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0;
1943
1944 // Notify collector battery state
1945 if (mCollector != null) {
1946 mCollector.updateBatteryState(scale, level, plugged);
1947 }
1948 }
1949 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1950 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
1951 synchronized (mLocationListeners) {
1952 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1953 if (uid >= 0) {
1954 ArrayList<Receiver> removedRecs = null;
1955 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1956 for (int j=i.size()-1; j>=0; j--) {
1957 UpdateRecord ur = i.get(j);
1958 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1959 if (removedRecs == null) {
1960 removedRecs = new ArrayList<Receiver>();
1961 }
1962 if (!removedRecs.contains(ur.mReceiver)) {
1963 removedRecs.add(ur.mReceiver);
1964 }
1965 }
1966 }
1967 }
1968 ArrayList<ProximityAlert> removedAlerts = null;
1969 for (ProximityAlert i : mProximityAlerts.values()) {
1970 if (i.mUid == uid) {
1971 if (removedAlerts == null) {
1972 removedAlerts = new ArrayList<ProximityAlert>();
1973 }
1974 if (!removedAlerts.contains(i)) {
1975 removedAlerts.add(i);
1976 }
1977 }
1978 }
1979 if (removedRecs != null) {
1980 for (int i=removedRecs.size()-1; i>=0; i--) {
1981 removeUpdatesLocked(removedRecs.get(i));
1982 }
1983 }
1984 if (removedAlerts != null) {
1985 for (int i=removedAlerts.size()-1; i>=0; i--) {
1986 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1987 }
1988 }
1989 }
1990 }
1991 }
1992 }
1993 }
1994
1995 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1996 @Override public void onReceive(Context context, Intent intent) {
1997 String action = intent.getAction();
1998
1999 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
2000
2001 List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
2002
2003 if (wifiScanResults == null) {
2004 return;
2005 }
2006
2007 // Notify provider and collector of Wifi scan results
2008 synchronized (mLocationListeners) {
2009 if (mCollector != null) {
2010 mCollector.updateWifiScanResults(wifiScanResults);
2011 }
2012 if (mNetworkLocationInterface != null) {
2013 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
2014 }
2015 }
2016
2017 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 boolean noConnectivity =
2019 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
2020 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002021 mNetworkState = LocationProvider.AVAILABLE;
2022 } else {
2023 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 }
2025
2026 // Notify location providers of current network state
2027 synchronized (mLocationListeners) {
2028 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
2029 for (LocationProviderImpl provider : providers) {
2030 if (provider.requiresNetwork()) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002031 provider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002032 }
2033 }
2034 }
2035
2036 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
2037 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
2038 WifiManager.WIFI_STATE_UNKNOWN);
2039
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002040 if (state == WifiManager.WIFI_STATE_ENABLED) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002041 mWifiEnabled = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 } else if (state == WifiManager.WIFI_STATE_DISABLED) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002043 mWifiEnabled = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002044 } else {
2045 return;
2046 }
2047
2048 // Notify network provider of current wifi enabled state
2049 synchronized (mLocationListeners) {
2050 if (mNetworkLocationInterface != null) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08002051 mNetworkLocationInterface.updateWifiEnabledState(mWifiEnabled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 }
2053 }
2054
2055 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
2056
2057 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
2058 false);
2059
2060 synchronized (mLocationListeners) {
2061 if (enabled) {
2062 updateReportedGpsLocked();
2063 mGpsNavigating = true;
2064 } else {
2065 reportStopGpsLocked();
2066 mGpsNavigating = false;
2067 // When GPS is disabled, we are OK to release wake-lock
2068 mWakeLockGpsReceived = true;
2069 }
2070 }
2071 }
2072
2073 }
2074 }
2075
2076 // Wake locks
2077
2078 private void updateWakelockStatusLocked(boolean screenOn) {
2079 log("updateWakelockStatus(): " + screenOn);
2080
Amith Yamasanie1ccba22009-04-02 11:40:25 -07002081 long callerId = Binder.clearCallingIdentity();
2082
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 boolean needsLock = false;
2084 long minTime = Integer.MAX_VALUE;
2085
2086 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
2087 needsLock = true;
2088 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
2089 }
2090
2091 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
2092 needsLock = true;
2093 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
2094 if (screenOn) {
2095 startGpsLocked();
2096 } else if (mScreenOn && !screenOn) {
2097 // We just turned the screen off so stop navigating
2098 stopGpsLocked();
2099 }
2100 }
2101
2102 mScreenOn = screenOn;
2103
2104 PendingIntent sender =
2105 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
2106
2107 // Cancel existing alarm
2108 log("Cancelling existing alarm");
2109 mAlarmManager.cancel(sender);
2110
2111 if (needsLock && !mScreenOn) {
2112 long now = SystemClock.elapsedRealtime();
2113 mAlarmManager.set(
2114 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
2115 mAlarmInterval = minTime;
2116 log("Creating a new wakelock alarm with minTime = " + minTime);
2117 } else {
2118 log("No need for alarm");
2119 mAlarmInterval = -1;
2120
2121 // Clear out existing wakelocks
2122 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
2123 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
2124 releaseWakeLockLocked();
2125 }
Amith Yamasanie1ccba22009-04-02 11:40:25 -07002126 Binder.restoreCallingIdentity(callerId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002127 }
2128
2129 private void acquireWakeLockLocked() {
2130 try {
2131 acquireWakeLockXLocked();
2132 } catch (Exception e) {
2133 // This is to catch a runtime exception thrown when we try to release an
2134 // already released lock.
2135 Log.e(TAG, "exception in acquireWakeLock()", e);
2136 }
2137 }
2138
2139 private void acquireWakeLockXLocked() {
2140 if (mWakeLock.isHeld()) {
2141 log("Must release wakelock before acquiring");
2142 mWakeLockAcquireTime = 0;
2143 mWakeLock.release();
2144 }
2145
2146 boolean networkActive = (mNetworkLocationProvider != null)
2147 && mNetworkLocationProvider.isLocationTracking();
2148 boolean gpsActive = (mGpsLocationProvider != null)
2149 && mGpsLocationProvider.isLocationTracking();
2150
2151 boolean needsLock = networkActive || gpsActive;
2152 if (!needsLock) {
2153 log("No need for Lock!");
2154 return;
2155 }
2156
2157 mWakeLockGpsReceived = !gpsActive;
2158 mWakeLockNetworkReceived = !networkActive;
2159
2160 // Acquire wake lock
2161 mWakeLock.acquire();
2162 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
2163 log("Acquired wakelock");
2164
2165 // Start the gps provider
2166 startGpsLocked();
2167
2168 // Acquire cell lock
2169 if (mCellWakeLockAcquired) {
2170 // Lock is already acquired
2171 } else if (!mWakeLockNetworkReceived) {
2172 mTelephonyManager.enableLocationUpdates();
2173 mCellWakeLockAcquired = true;
2174 } else {
2175 mCellWakeLockAcquired = false;
2176 }
2177
2178 // Notify NetworkLocationProvider
2179 if (mNetworkLocationInterface != null) {
2180 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
2181 }
2182
2183 // Acquire wifi lock
2184 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
2185 if (wifiLock != null) {
2186 if (mWifiWakeLockAcquired) {
2187 // Lock is already acquired
2188 } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) {
2189 wifiLock.acquire();
2190 mWifiWakeLockAcquired = true;
2191 } else {
2192 mWifiWakeLockAcquired = false;
2193 Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock");
2194 }
2195 }
2196 }
2197
2198 private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) {
2199 int seq = mReportedGpsUids.get(uid, -1);
2200 if (seq == curSeq) {
2201 // Already reported; propagate to next sequence.
2202 mReportedGpsUids.put(uid, nextSeq);
2203 return true;
2204 } else if (seq != nextSeq) {
2205 try {
2206 // New UID; report it.
2207 mBatteryStats.noteStartGps(uid);
2208 mReportedGpsUids.put(uid, nextSeq);
2209 return true;
2210 } catch (RemoteException e) {
2211 }
2212 }
2213 return false;
2214 }
2215
2216 private void updateReportedGpsLocked() {
2217 if (mGpsLocationProvider == null) {
2218 return;
2219 }
2220
2221 final String name = mGpsLocationProvider.getName();
2222 final int curSeq = mReportedGpsSeq;
2223 final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0;
2224 mReportedGpsSeq = nextSeq;
2225
2226 ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name);
2227 int num = 0;
2228 final int N = urs.size();
2229 for (int i=0; i<N; i++) {
2230 UpdateRecord ur = urs.get(i);
2231 if (ur.mReceiver == mProximityListener) {
2232 // We don't want the system to take the blame for this one.
2233 continue;
2234 }
2235 if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) {
2236 num++;
2237 }
2238 }
2239
2240 for (ProximityAlert pe : mProximityAlerts.values()) {
2241 if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) {
2242 num++;
2243 }
2244 }
2245
2246 if (num != mReportedGpsUids.size()) {
2247 // The number of uids is processed is different than the
2248 // array; report any that are no longer active.
2249 for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
2250 if (mReportedGpsUids.valueAt(i) != nextSeq) {
2251 try {
2252 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
2253 } catch (RemoteException e) {
2254 }
2255 mReportedGpsUids.removeAt(i);
2256 }
2257 }
2258 }
2259 }
2260
2261 private void reportStopGpsLocked() {
2262 int curSeq = mReportedGpsSeq;
2263 for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
2264 if (mReportedGpsUids.valueAt(i) == curSeq) {
2265 try {
2266 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
2267 } catch (RemoteException e) {
2268 }
2269 }
2270 }
2271 curSeq++;
2272 if (curSeq < 0) curSeq = 0;
2273 mReportedGpsSeq = curSeq;
2274 mReportedGpsUids.clear();
2275 }
2276
2277 private void startGpsLocked() {
2278 boolean gpsActive = (mGpsLocationProvider != null)
2279 && mGpsLocationProvider.isLocationTracking();
2280 if (gpsActive) {
2281 mGpsLocationProvider.startNavigating();
2282 }
2283 }
2284
2285 private void stopGpsLocked() {
2286 boolean gpsActive = mGpsLocationProvider != null
2287 && mGpsLocationProvider.isLocationTracking();
2288 if (gpsActive) {
2289 mGpsLocationProvider.stopNavigating();
2290 }
2291 }
2292
2293 private void releaseWakeLockLocked() {
2294 try {
2295 releaseWakeLockXLocked();
2296 } catch (Exception e) {
2297 // This is to catch a runtime exception thrown when we try to release an
2298 // already released lock.
2299 Log.e(TAG, "exception in releaseWakeLock()", e);
2300 }
2301 }
2302
2303 private void releaseWakeLockXLocked() {
2304 // Release wifi lock
2305 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
2306 if (wifiLock != null) {
2307 if (mWifiWakeLockAcquired) {
2308 wifiLock.release();
2309 mWifiWakeLockAcquired = false;
2310 }
2311 }
2312
2313 if (!mScreenOn) {
2314 // Stop the gps
2315 stopGpsLocked();
2316 }
2317
2318 // Release cell lock
2319 if (mCellWakeLockAcquired) {
2320 mTelephonyManager.disableLocationUpdates();
2321 mCellWakeLockAcquired = false;
2322 }
2323
2324 // Notify NetworkLocationProvider
2325 if (mNetworkLocationInterface != null) {
2326 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
2327 }
2328
2329 // Release wake lock
2330 mWakeLockAcquireTime = 0;
2331 if (mWakeLock.isHeld()) {
2332 log("Released wakelock");
2333 mWakeLock.release();
2334 } else {
2335 log("Can't release wakelock again!");
2336 }
2337 }
2338
2339 // Geocoder
2340
2341 public String getFromLocation(double latitude, double longitude, int maxResults,
2342 String language, String country, String variant, String appName, List<Address> addrs) {
2343 synchronized (mLocationListeners) {
2344 if (mNetworkLocationInterface != null) {
2345 return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults,
2346 language, country, variant, appName, addrs);
2347 } else {
2348 return null;
2349 }
2350 }
2351 }
2352
2353 public String getFromLocationName(String locationName,
2354 double lowerLeftLatitude, double lowerLeftLongitude,
2355 double upperRightLatitude, double upperRightLongitude, int maxResults,
2356 String language, String country, String variant, String appName, List<Address> addrs) {
2357 synchronized (mLocationListeners) {
2358 if (mNetworkLocationInterface != null) {
2359 return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude,
2360 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults,
2361 language, country, variant, appName, addrs);
2362 } else {
2363 return null;
2364 }
2365 }
2366 }
2367
2368 // Mock Providers
2369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002370 private void checkMockPermissionsSafe() {
2371 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2372 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2373 if (!allowMocks) {
2374 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2375 }
2376
2377 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2378 PackageManager.PERMISSION_GRANTED) {
2379 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2380 }
2381 }
2382
2383 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
2384 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
2385 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
2386 checkMockPermissionsSafe();
2387
2388 synchronized (mLocationListeners) {
2389 MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
2390 requiresCell, hasMonetaryCost, supportsAltitude,
2391 supportsSpeed, supportsBearing, powerRequirement, accuracy);
2392 if (LocationProviderImpl.getProvider(name) != null) {
2393 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2394 }
2395 LocationProviderImpl.addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002396 mMockProviders.put(name, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002397 updateProvidersLocked();
2398 }
2399 }
2400
2401 public void removeTestProvider(String provider) {
2402 checkMockPermissionsSafe();
2403 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002404 MockProvider mockProvider = mMockProviders.get(provider);
2405 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002406 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2407 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002408 LocationProviderImpl.removeProvider(mockProvider);
2409 mMockProviders.remove(mockProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002410 updateProvidersLocked();
2411 }
2412 }
2413
2414 public void setTestProviderLocation(String provider, Location loc) {
2415 checkMockPermissionsSafe();
2416 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002417 MockProvider mockProvider = mMockProviders.get(provider);
2418 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002419 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2420 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002421 mockProvider.setLocation(loc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002422 }
2423 }
2424
2425 public void clearTestProviderLocation(String provider) {
2426 checkMockPermissionsSafe();
2427 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002428 MockProvider mockProvider = mMockProviders.get(provider);
2429 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002430 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2431 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002432 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002433 }
2434 }
2435
2436 public void setTestProviderEnabled(String provider, boolean enabled) {
2437 checkMockPermissionsSafe();
2438 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002439 MockProvider mockProvider = mMockProviders.get(provider);
2440 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002441 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2442 }
2443 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002444 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002445 mEnabledProviders.add(provider);
2446 mDisabledProviders.remove(provider);
2447 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002448 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002449 mEnabledProviders.remove(provider);
2450 mDisabledProviders.add(provider);
2451 }
2452 updateProvidersLocked();
2453 }
2454 }
2455
2456 public void clearTestProviderEnabled(String provider) {
2457 checkMockPermissionsSafe();
2458 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002459 MockProvider mockProvider = mMockProviders.get(provider);
2460 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002461 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2462 }
2463 mEnabledProviders.remove(provider);
2464 mDisabledProviders.remove(provider);
2465 updateProvidersLocked();
2466 }
2467 }
2468
2469 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2470 checkMockPermissionsSafe();
2471 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002472 MockProvider mockProvider = mMockProviders.get(provider);
2473 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002474 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2475 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002476 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002477 }
2478 }
2479
2480 public void clearTestProviderStatus(String provider) {
2481 checkMockPermissionsSafe();
2482 synchronized (mLocationListeners) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002483 MockProvider mockProvider = mMockProviders.get(provider);
2484 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002485 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2486 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002487 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002488 }
2489 }
2490
2491 private void log(String log) {
2492 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2493 Log.d(TAG, log);
2494 }
2495 }
2496
2497 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2498 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2499 != PackageManager.PERMISSION_GRANTED) {
2500 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2501 + Binder.getCallingPid()
2502 + ", uid=" + Binder.getCallingUid());
2503 return;
2504 }
2505
2506 synchronized (mLocationListeners) {
2507 pw.println("Current Location Manager state:");
2508 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2509 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
2510 pw.println(" mGpsNavigating=" + mGpsNavigating);
2511 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
2512 pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface);
2513 pw.println(" mLastSignalStrength=" + mLastSignalStrength
2514 + " mLastRadioType=" + mLastRadioType);
2515 pw.println(" mCellLocationUpdater=" + mCellLocationUpdater);
2516 pw.println(" mLastCellState=" + mLastCellState);
2517 pw.println(" mCollector=" + mCollector);
2518 pw.println(" mAlarmInterval=" + mAlarmInterval
2519 + " mScreenOn=" + mScreenOn
2520 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2521 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2522 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
2523 pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired
2524 + " mCellWakeLockAcquired=" + mCellWakeLockAcquired);
2525 pw.println(" Listeners:");
2526 int N = mListeners.size();
2527 for (int i=0; i<N; i++) {
2528 pw.println(" " + mListeners.get(i));
2529 }
2530 pw.println(" Location Listeners:");
2531 for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i
2532 : mLocationListeners.entrySet()) {
2533 pw.println(" " + i.getKey() + ":");
2534 for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) {
2535 pw.println(" " + j.getKey() + ":");
2536 j.getValue().dump(pw, " ");
2537 }
2538 }
2539 pw.println(" Last Fix Broadcasts:");
2540 for (Map.Entry<Receiver, HashMap<String,Location>> i
2541 : mLastFixBroadcast.entrySet()) {
2542 pw.println(" " + i.getKey() + ":");
2543 for (Map.Entry<String,Location> j : i.getValue().entrySet()) {
2544 pw.println(" " + j.getKey() + ":");
2545 j.getValue().dump(new PrintWriterPrinter(pw), " ");
2546 }
2547 }
2548 pw.println(" Last Status Broadcasts:");
2549 for (Map.Entry<Receiver, HashMap<String,Long>> i
2550 : mLastStatusBroadcast.entrySet()) {
2551 pw.println(" " + i.getKey() + ":");
2552 for (Map.Entry<String,Long> j : i.getValue().entrySet()) {
2553 pw.println(" " + j.getKey() + " -> 0x"
2554 + Long.toHexString(j.getValue()));
2555 }
2556 }
2557 pw.println(" Records by Provider:");
2558 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2559 : mRecordsByProvider.entrySet()) {
2560 pw.println(" " + i.getKey() + ":");
2561 for (UpdateRecord j : i.getValue()) {
2562 pw.println(" " + j + ":");
2563 j.dump(pw, " ");
2564 }
2565 }
2566 pw.println(" Locations by Provider:");
2567 for (Map.Entry<String, Location> i
2568 : mLocationsByProvider.entrySet()) {
2569 pw.println(" " + i.getKey() + ":");
2570 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2571 }
2572 pw.println(" Last Known Locations:");
2573 for (Map.Entry<String, Location> i
2574 : mLastKnownLocation.entrySet()) {
2575 pw.println(" " + i.getKey() + ":");
2576 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2577 }
2578 if (mProximityAlerts.size() > 0) {
2579 pw.println(" Proximity Alerts:");
2580 for (Map.Entry<PendingIntent, ProximityAlert> i
2581 : mProximityAlerts.entrySet()) {
2582 pw.println(" " + i.getKey() + ":");
2583 i.getValue().dump(pw, " ");
2584 }
2585 }
2586 if (mProximitiesEntered.size() > 0) {
2587 pw.println(" Proximities Entered:");
2588 for (ProximityAlert i : mProximitiesEntered) {
2589 pw.println(" " + i + ":");
2590 i.dump(pw, " ");
2591 }
2592 }
2593 pw.println(" mProximityListener=" + mProximityListener);
2594 if (mEnabledProviders.size() > 0) {
2595 pw.println(" Enabled Providers:");
2596 for (String i : mEnabledProviders) {
2597 pw.println(" " + i);
2598 }
2599
2600 }
2601 if (mDisabledProviders.size() > 0) {
2602 pw.println(" Disabled Providers:");
2603 for (String i : mDisabledProviders) {
2604 pw.println(" " + i);
2605 }
2606
2607 }
2608 if (mMockProviders.size() > 0) {
2609 pw.println(" Mock Providers:");
2610 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002611 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002612 }
2613 }
2614 pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":");
2615 N = mReportedGpsUids.size();
2616 for (int i=0; i<N; i++) {
2617 pw.println(" UID " + mReportedGpsUids.keyAt(i)
2618 + " seq=" + mReportedGpsUids.valueAt(i));
2619 }
2620 }
2621 }
2622}