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