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